Completed
Push — master ( 1d7e0e...752c00 )
by Dmitry
10:25
created

ActiveQuery::prepare()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 13
ccs 0
cts 8
cp 0
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 6
1
<?php
2
3
/*
4
 * Tools to use API as ActiveRecord for Yii2
5
 *
6
 * @link      https://github.com/hiqdev/yii2-hiart
7
 * @package   yii2-hiart
8
 * @license   BSD-3-Clause
9
 * @copyright Copyright (c) 2015-2016, HiQDev (http://hiqdev.com/)
10
 */
11
12
namespace hiqdev\hiart;
13
14
use yii\base\NotSupportedException;
15
use yii\db\ActiveQueryInterface;
16
use yii\db\ActiveQueryTrait;
17
use yii\db\ActiveRecordInterface;
18
use yii\db\ActiveRelationTrait;
19
use yii\helpers\ArrayHelper;
20
21
class ActiveQuery extends Query implements ActiveQueryInterface
22
{
23
    use ActiveQueryTrait {
24
        createModels as defaultCreateModels;
25
    }
26
27
    use ActiveRelationTrait;
28
29
    /**
30
     * @event Event an event that is triggered when the query is initialized via [[init()]].
31
     */
32
    const EVENT_INIT = 'init';
33
34
    /**
35
     * @var array|null a list of relations that this query should be joined with
36
     */
37
    public $joinWith = [];
38
39
    /**
40
     * @var array options for search
41
     */
42
    public $options = [];
43
44
    /**
45
     * Constructor.
46
     *
47
     * @param string $modelClass the model class associated with this query
48
     * @param array $config configurations to be applied to the newly created query object
49
     */
50
    public function __construct($modelClass, $config = [])
51
    {
52
        $this->modelClass = $modelClass;
53
54
        parent::__construct($config);
55
    }
56
57
    /**
58
     * Initializes the object.
59
     * This method is called at the end of the constructor. The default implementation will trigger
60
     * an [[EVENT_INIT]] event. If you override this method, make sure you call the parent implementation at the end
61
     * to ensure triggering of the event.
62
     */
63
    public function init()
64
    {
65
        parent::init();
66
        $this->trigger(self::EVENT_INIT);
67
    }
68
69
    /**
70
     * Creates a DB command that can be used to execute this query.
71
     *
72
     * @param Connection $db the DB connection used to create the DB command.
73
     *                       If null, the DB connection returned by [[modelClass]] will be used.
74
     *
75
     * @return Command the created DB command instance.
76
     */
77
    public function createCommand($db = null)
78
    {
79
        if ($this->primaryModel !== null) {
80
            // lazy loading
81
            if (is_array($this->via)) {
82
                // via relation
83
                /* @var $viaQuery ActiveQuery */
84
                list($viaName, $viaQuery) = $this->via;
85
                if ($viaQuery->multiple) {
86
                    $viaModels = $viaQuery->all();
87
                    $this->primaryModel->populateRelation($viaName, $viaModels);
88
                } else {
89
                    $model = $viaQuery->one();
90
                    $this->primaryModel->populateRelation($viaName, $model);
91
                    $viaModels = $model === null ? [] : [$model];
92
                }
93
                $this->filterByModels($viaModels);
94
            } else {
95
                $this->filterByModels([$this->primaryModel]);
96
            }
97
        }
98
99
        /* @var $modelClass ActiveRecord */
100
        $modelClass = $this->modelClass;
101
        if ($db === null) {
102
            $db = $modelClass::getDb();
103
        }
104
105
        if ($this->type === null) {
106
            $this->type = $modelClass::type();
107
        }
108
        if ($this->index === null) {
109
            $this->index = $modelClass::index();
110
            $this->type = $modelClass::type();
111
        }
112
113
        $commandConfig = $db->getQueryBuilder()->build($this);
114
115
        return $db->createCommand($commandConfig);
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function prepare()
122
    {
123
        // NOTE: because the same ActiveQuery may be used to build different SQL statements
124
        // (e.g. by ActiveDataProvider, one for count query, the other for row data query,
125
        // it is important to make sure the same ActiveQuery can be used to build SQL statements
126
        // multiple times.
127
        if (!empty($this->joinWith)) {
128
            $this->buildJoinWith();
129
            $this->joinWith = null;
130
        }
131
132
        return $this;
133
    }
134
135
    public function joinWith($with)
136
    {
137
        $this->joinWith[] = (array) $with;
138
139
        return $this;
140
    }
141
142
    private function buildJoinWith()
143
    {
144
        $join = $this->join;
145
        $this->join = [];
146
147
        $model = new $this->modelClass;
148
149
        foreach ($this->joinWith as $with) {
0 ignored issues
show
Bug introduced by
The expression $this->joinWith of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
150
            $this->joinWithRelations($model, $with);
151
152
            foreach ($with as $name => $callback) {
153
                if (is_int($name)) {
154
                    $this->join([$callback]);
155
                } else {
156
                    $this->join([$name => $callback]);
157
                }
158
159
                unset($with[$name]);
160
            }
161
        }
162
163
        if (!empty($join)) {
164
            // append explicit join to joinWith()
165
            // https://github.com/yiisoft/yii2/issues/2880
166
            $this->join = empty($this->join) ? $join : array_merge($this->join, $join);
167
        }
168
169
        if (empty($this->select) || true) {
170
            $this->addSelect(['*' => '*']);
171
            foreach ($this->joinWith as $join) {
0 ignored issues
show
Bug introduced by
The expression $this->joinWith of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
172
                $key = array_shift(array_keys($join));
0 ignored issues
show
Bug introduced by
array_keys($join) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
173
                $closure = array_shift($join);
174
175
                $this->addSelect(is_int($key) ? $closure : $key);
176
            }
177
        }
178
    }
179
180
    /**
181
     * @param ActiveRecord $model
182
     * @param $with
183
     */
184
    protected function joinWithRelations($model, $with)
185
    {
186
        foreach ($with as $name => $callback) {
187
            if (is_int($name)) {
188
                $name = $callback;
189
                $callback = null;
190
            }
191
192
            $primaryModel = $model;
193
            $parent = $this;
194
195
            if (!isset($relations[$name])) {
196
                $relations[$name] = $relation = $primaryModel->getRelation($name);
0 ignored issues
show
Bug introduced by
The variable $relations does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
197
                if ($callback !== null) {
198
                    call_user_func($callback, $relation);
199
                }
200
                if (!empty($relation->joinWith)) {
0 ignored issues
show
Bug introduced by
Accessing joinWith on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
201
                    $relation->buildJoinWith();
202
                }
203
                $this->joinWithRelation($parent, $relation);
0 ignored issues
show
Compatibility introduced by
$relation of type object<yii\db\ActiveQueryInterface> is not a sub-type of object<hiqdev\hiart\ActiveQuery>. It seems like you assume a concrete implementation of the interface yii\db\ActiveQueryInterface to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
204
            }
205
        }
206
    }
207
208
    /**
209
     * Joins a parent query with a child query.
210
     * The current query object will be modified accordingly.
211
     * @param ActiveQuery $parent
212
     * @param ActiveQuery $child
213
     */
214
    private function joinWithRelation($parent, $child)
0 ignored issues
show
Unused Code introduced by
The parameter $parent is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
215
    {
216
        if (!empty($child->join)) {
217
            foreach ($child->join as $join) {
218
                $this->join[] = $join;
219
            }
220
        }
221
    }
222
223
    public function select($columns)
224
    {
225
        $this->select = $columns;
226
227
        return $this;
228
    }
229
230
    /**
231
     * @param array|string $columns
232
     * @return $this
233
     */
234
    public function addSelect($columns)
235
    {
236
        if (!is_array($columns)) {
237
            $columns = (array) $columns;
238
        }
239
240
        if ($this->select === null) {
241
            $this->select = $columns;
242
        } else {
243
            $this->select = array_merge($this->select, $columns);
244
        }
245
246
        return $this;
247
    }
248
249
    /**
250
     * Executes query and returns all results as an array.
251
     *
252
     * @param Connection $db the DB connection used to create the DB command.
253
     *                            If null, the DB connection returned by [[modelClass]] will be used.
254
     *
255
     * @return array the query results. If the query results in nothing, an empty array will be returned.
256
     */
257
    public function all($db = null)
258
    {
259
        if ($this->asArray) {
260
            // TODO implement with
261
            return parent::all($db);
0 ignored issues
show
Bug introduced by
It seems like $db defined by parameter $db on line 257 can also be of type object<hiqdev\hiart\Connection>; however, hiqdev\hiart\Query::all() does only seem to accept object<yii\db\Connection>|null, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
262
        }
263
264
        $rows = $this->createCommand($db)->search($this->options);
265
266
        return $this->populate($rows);
267
    }
268
269
    public function populate($rows)
270
    {
271
        if (empty($rows)) {
272
            return [];
273
        }
274
275
        $models = $this->createModels($rows);
276
        if (!empty($this->with)) {
277
            $this->findWith($this->with, $models);
278
        }
279
280
        foreach ($models as $model) {
281
            $model->afterFind();
282
        }
283
284
        return $models;
285
    }
286
287
    private function createModels($rows)
288
    {
289
        $models = [];
290
        if ($this->asArray) {
291
            if ($this->indexBy === null) {
292
                return $rows;
293
            }
294
            foreach ($rows as $row) {
295 View Code Duplication
                if (is_string($this->indexBy)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
296
                    $key = $row[$this->indexBy];
297
                } else {
298
                    $key = call_user_func($this->indexBy, $row);
299
                }
300
                $models[$key] = $row;
301
            }
302
        } else {
303
            /* @var $class ActiveRecord */
304
            $class = $this->modelClass;
305
            if ($this->indexBy === null) {
306
                foreach ($rows as $row) {
307
                    $model = $class::instantiate($row);
308
                    $modelClass = get_class($model);
309
                    $modelClass::populateRecord($model, $row);
310
                    $this->populateJoinedRelations($model, $row);
311
                    $models[] = $model;
312
                }
313
            } else {
314
                foreach ($rows as $row) {
315
                    $model = $class::instantiate($row);
316
                    $modelClass = get_class($model);
317
                    $modelClass::populateRecord($model, $row);
318
                    $this->populateJoinedRelations($model, $row);
319 View Code Duplication
                    if (is_string($this->indexBy)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
320
                        $key = $model->{$this->indexBy};
321
                    } else {
322
                        $key = call_user_func($this->indexBy, $model);
323
                    }
324
                    $models[$key] = $model;
325
                }
326
            }
327
        }
328
329
        return $models;
330
    }
331
332
    /**
333
     * Populates joined relations from [[join]] array.
334
     *
335
     * @param ActiveRecord $model
336
     * @param array $row
337
     */
338
    public function populateJoinedRelations($model, array $row)
339
    {
340
        foreach ($row as $key => $value) {
341
            if (empty($this->join) || !is_array($value) || $model->hasAttribute($key)) {
342
                continue;
343
            }
344
            foreach ($this->join as $join) {
345
                $name = array_shift(array_keys($join));
0 ignored issues
show
Bug introduced by
array_keys($join) cannot be passed to array_shift() as the parameter $array expects a reference.
Loading history...
346
                $closure = array_shift($join);
347
348
                if (is_int($name)) {
349
                    $name = $closure;
350
                    $closure = null;
351
                }
352
                if ($name !== $key) {
353
                    continue;
354
                }
355
                if ($model->isRelationPopulated($name)) {
356
                    continue 2;
357
                }
358
                $records = [];
359
                $relation = $model->getRelation($name);
360
                $relationClass = $relation->modelClass;
0 ignored issues
show
Bug introduced by
Accessing modelClass on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
361
                if ($closure !== null) {
362
                    call_user_func($closure, $relation);
363
                }
364
                $relation->prepare();
365
366
                if ($relation->multiple) {
0 ignored issues
show
Bug introduced by
Accessing multiple on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
367
                    foreach ($value as $item) {
368
                        $relatedModel = $relationClass::instantiate($item);
369
                        $relatedModelClass = get_class($relatedModel);
370
                        $relatedModelClass::populateRecord($relatedModel, $item);
371
                        $relation->populateJoinedRelations($relatedModel, $item);
372
                        $relation->addInverseRelation($relatedModel, $model);
373
                        if ($relation->indexBy !== null) {
0 ignored issues
show
Bug introduced by
Accessing indexBy on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
374
                            $index = is_string($relation->indexBy)
0 ignored issues
show
Bug introduced by
Accessing indexBy on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
375
                                ? $relatedModel[$relation->indexBy]
0 ignored issues
show
Bug introduced by
Accessing indexBy on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
376
                                : call_user_func($relation->indexBy, $relatedModel);
0 ignored issues
show
Bug introduced by
Accessing indexBy on the interface yii\db\ActiveQueryInterface suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
377
                            $records[$index] = $relatedModel;
378
                        } else {
379
                            $records[] = $relatedModel;
380
                        }
381
                    }
382
                } else {
383
                    $relatedModel = $relationClass::instantiate($value);
384
                    $relatedModelClass = get_class($relatedModel);
385
                    $relatedModelClass::populateRecord($relatedModel, $value);
386
                    $relation->populateJoinedRelations($relatedModel, $value);
387
                    $relation->addInverseRelation($relatedModel, $model);
388
                    $records = $relatedModel;
389
                }
390
391
                $model->populateRelation($name, $records);
392
            }
393
        }
394
    }
395
396
    /**
397
     * @param $relatedModel
398
     */
399
    private function addInverseRelation($relatedModel)
400
    {
401
        if ($this->inverseOf === null) {
402
            return;
403
        }
404
405
        $inverseRelation = $relatedModel->getRelation($this->inverseOf);
406
        $relatedModel->populateRelation($this->inverseOf, $inverseRelation->multiple ? [$this->primaryModel] : $this->primaryModel);
407
    }
408
409
    /**
410
     * Executes query and returns a single row of result.
411
     *
412
     * @param Connection $db the DB connection used to create the DB command.
413
     *                       If null, the DB connection returned by [[modelClass]] will be used.
414
     *
415
     * @return ActiveRecord|array|null a single row of query result. Depending on the setting of [[asArray]],
416
     *                                 the query result may be either an array or an ActiveRecord object. Null will be returned
417
     *                                 if the query results in nothing.
418
     */
419
    public function one($db = null)
420
    {
421
        //        $result = $this->createCommand($db)->get();
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
422
423
        $result = $this->createCommand($db)->search(ArrayHelper::merge(['limit' => 1], $this->options));
424
        if (empty($result)) {
425
            return null;
426
        }
427
        $result = reset($result);
428
429
        if ($this->asArray) {
430
            // TODO implement with()
0 ignored issues
show
Unused Code Comprehensibility introduced by
53% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
431
//            /* @var $modelClass ActiveRecord */
432
//            $modelClass = $this->modelClass;
433
//            $model = $result['_source'];
434
//            $pk = $modelClass::primaryKey()[0];
435
//            if ($pk === '_id') {
436
//                $model['_id'] = $result['_id'];
437
//            }
438
//            $model['_score'] = $result['_score'];
439
//            if (!empty($this->with)) {
440
//                $models = [$model];
441
//                $this->findWith($this->with, $models);
442
//                $model = $models[0];
443
//            }
444
            return $result;
445
        }
446
447
        /* @var $class ActiveRecord */
448
        $class = $this->modelClass;
449
        $model = $class::instantiate($result);
450
        $class::populateRecord($model, $result);
451
        $this->populateJoinedRelations($model, $result);
452
        if (!empty($this->with)) {
453
            $models = [$model];
454
            $this->findWith($this->with, $models);
455
            $model = $models[0];
456
        }
457
        $model->afterFind();
458
459
        return $model;
460
    }
461
462
    /**
463
     * {@inheritdoc}
464
     */
465
    public function search($db = null, $options = [])
466
    {
467
        $result = $this->createCommand($db)->search($options);
468
        // TODO implement with() for asArray
469
        if (!empty($result) && !$this->asArray) {
470
            $models = $this->createModels($result);
471
            if (!empty($this->with)) {
472
                $this->findWith($this->with, $models);
473
            }
474
            foreach ($models as $model) {
475
                $model->afterFind();
476
            }
477
            $result = $models;
478
        }
479
480
        return $result;
481
    }
482
483
    /**
484
     * {@inheritdoc}
485
     */
486
    public function column($field, $db = null)
487
    {
488
        if ($field === '_id') {
489
            $command = $this->createCommand($db);
490
            $command->queryParts['fields'] = [];
491
            $command->queryParts['_source'] = false;
492
            $result = $command->search();
493
            if (empty($result['hits']['hits'])) {
494
                return [];
495
            }
496
            $column = [];
497
            foreach ($result['hits']['hits'] as $row) {
498
                $column[] = $row['_id'];
499
            }
500
501
            return $column;
502
        }
503
504
        return parent::column($field, $db);
505
    }
506
}
507