Closed pyhbka closed 5 years ago
как я решил проблему: необходимо определить наследники классов kak\clickhouse\ActiveRecord и kak\clickhouse\ActiveQuery. в класс ActiveQuery скопировать следующие методы из yii\db\ActiveQuery: one, populate, removeDuplicatedModels, addInverseRelations. ничего менять не надо.
класс ActiveQuery:
use kak\clickhouse\ActiveQuery;
use kak\clickhouse\ActiveRecord;
use yii\base\InvalidConfigException;
use yii\db\ActiveRecordInterface;
/**
* Копипаста из \yii\db\ActiveQuery для нормальной работы с моделями вместо массивов для clickHouse.
*/
class BaseClickHouseActiveQuery extends ActiveQuery
{
/**
* @param null $db
* @return ActiveRecordInterface|null
* @throws InvalidConfigException
*/
public function one($db = null)
{
$row = parent::one($db);
if ($row !== false) {
$models = $this->populate([$row]);
return reset($models) ?: null;
}
return null;
}
/**
* {@inheritdoc}
* @throws InvalidConfigException
*/
public function populate($rows)
{
if (empty($rows)) {
return [];
}
$models = $this->createModels($rows);
if (!empty($this->join) && $this->indexBy === null) {
$models = $this->removeDuplicatedModels($models);
}
if (!empty($this->with)) {
$this->findWith($this->with, $models);
}
if ($this->inverseOf !== null) {
$this->addInverseRelations($models);
}
if (!$this->asArray) {
foreach ($models as $model) {
$model->afterFind();
}
}
return parent::populate($models);
}
/**
* Removes duplicated models by checking their primary key values.
* This method is mainly called when a join query is performed, which may cause duplicated rows being returned.
* @param array $models the models to be checked
* @throws InvalidConfigException if model primary key is empty
* @return array the distinctive models
*/
private function removeDuplicatedModels($models)
{
$hash = [];
/* @var $class ActiveRecord */
$class = $this->modelClass;
$pks = $class::primaryKey();
if (count($pks) > 1) {
// composite primary key
foreach ($models as $i => $model) {
$key = [];
foreach ($pks as $pk) {
if (!isset($model[$pk])) {
// do not continue if the primary key is not part of the result set
break 2;
}
$key[] = $model[$pk];
}
$key = serialize($key);
if (isset($hash[$key])) {
unset($models[$i]);
} else {
$hash[$key] = true;
}
}
} elseif (empty($pks)) {
throw new InvalidConfigException("Primary key of '{$class}' can not be empty.");
} else {
// single column primary key
$pk = reset($pks);
foreach ($models as $i => $model) {
if (!isset($model[$pk])) {
// do not continue if the primary key is not part of the result set
break;
}
$key = $model[$pk];
if (isset($hash[$key])) {
unset($models[$i]);
} elseif ($key !== null) {
$hash[$key] = true;
}
}
}
return array_values($models);
}
/**
* If applicable, populate the query's primary model into the related records' inverse relationship.
* @param array $result the array of related records as generated by [[populate()]]
* @since 2.0.9
*/
private function addInverseRelations(&$result)
{
if ($this->inverseOf === null) {
return;
}
foreach ($result as $i => $relatedModel) {
if ($relatedModel instanceof ActiveRecordInterface) {
if (!isset($inverseRelation)) {
$inverseRelation = $relatedModel->getRelation($this->inverseOf);
}
$relatedModel->populateRelation($this->inverseOf, $inverseRelation->multiple ? [$this->primaryModel] : $this->primaryModel);
} else {
if (!isset($inverseRelation)) {
/* @var $modelClass ActiveRecordInterface */
$modelClass = $this->modelClass;
$inverseRelation = $modelClass::instance()->getRelation($this->inverseOf);
}
$result[$i][$this->inverseOf] = $inverseRelation->multiple ? [$this->primaryModel] : $this->primaryModel;
}
}
}
}
класс ActiveRecord:
use kak\clickhouse\ActiveRecord;
use yii\helpers\Inflector;
use yii\helpers\StringHelper;
class BaseClickHouseActiveRecord extends ActiveRecord
{
public static function tableName()
{
return Inflector::underscore(StringHelper::basename(get_called_class()));
}
public static function find()
{
return new BaseClickHouseActiveQuery(get_called_class());
}
}
Свои модели наследовать от этого класса - все будет работать.
@sanchezzzhak надо добавить реализацию ActiveQuery
При любом раскладе возвращает массив как пример TestModel::find()->one(); вернет массив TestModel::find()->all(); вернет массив массивов моделька ни разу не прогрузилась.
TestModel - https://github.com/sanchezzzhak/kak-clickhouse#activerecord-model как тут, ничего лишнего только rules добавил, связей нет.
пока смог решить добавлением двух методов в класс kak\clickhouse\ActiveQuery из yii\db\ActiveQuery, методы one и populate
Что я не так делаю ? :(