14
14
use Yiisoft \Db \Exception \NotSupportedException ;
15
15
use Yiisoft \Db \Expression \ExpressionInterface ;
16
16
use Yiisoft \Db \Helper \DbArrayHelper ;
17
- use Yiisoft \Db \Query \BatchQueryResultInterface ;
17
+ use Yiisoft \Db \Query \DataReaderInterface ;
18
18
use Yiisoft \Db \Query \Query ;
19
19
use Yiisoft \Db \Query \QueryInterface ;
20
20
use Yiisoft \Db \QueryBuilder \QueryBuilderInterface ;
25
25
use function array_combine ;
26
26
use function array_flip ;
27
27
use function array_intersect_key ;
28
- use function array_key_first ;
29
28
use function array_map ;
30
29
use function array_merge ;
31
30
use function array_values ;
104
103
* @psalm-import-type ARClass from ActiveQueryInterface
105
104
* @psalm-import-type IndexKey from ArArrayHelper
106
105
*
107
- * @psalm-property IndexKey $indexBy
106
+ * @psalm-property IndexKey|null $indexBy
108
107
* @psalm-suppress ClassMustBeFinal
109
108
*/
110
109
class ActiveQuery extends Query implements ActiveQueryInterface
@@ -125,23 +124,13 @@ final public function __construct(
125
124
parent ::__construct ($ this ->getARInstance ()->db ());
126
125
}
127
126
128
- public function all (): array
127
+ public function each (): DataReaderInterface
129
128
{
130
- if ($ this ->shouldEmulateExecution ()) {
131
- return [];
132
- }
133
-
134
- return $ this ->populate ($ this ->createCommand ()->queryAll (), $ this ->indexBy );
135
- }
136
-
137
- public function batch (int $ batchSize = 100 ): BatchQueryResultInterface
138
- {
139
- return parent ::batch ($ batchSize )->setPopulatedMethod ($ this ->populate (...));
140
- }
141
-
142
- public function each (int $ batchSize = 100 ): BatchQueryResultInterface
143
- {
144
- return parent ::each ($ batchSize )->setPopulatedMethod ($ this ->populate (...));
129
+ /** @psalm-suppress InvalidArgument */
130
+ return $ this ->createCommand ()
131
+ ->query ()
132
+ ->indexBy ($ this ->indexBy )
133
+ ->resultCallback ($ this ->populateOne (...));
145
134
}
146
135
147
136
/**
@@ -235,22 +224,25 @@ public function prepare(QueryBuilderInterface $builder): QueryInterface
235
224
* @throws NotSupportedException
236
225
* @throws ReflectionException
237
226
* @throws Throwable
227
+ *
228
+ * @psalm-param list<array> $rows
229
+ * @psalm-return (
230
+ * $rows is non-empty-list<array>
231
+ * ? non-empty-list<ActiveRecordInterface|array>
232
+ * : list<ActiveRecordInterface|array>
233
+ * )
238
234
*/
239
- public function populate (array $ rows, Closure | string | null $ indexBy = null ): array
235
+ public function populate (array $ rows ): array
240
236
{
241
237
if (empty ($ rows )) {
242
238
return [];
243
239
}
244
240
245
- $ models = $ this ->createModels ($ rows );
246
-
247
- if (empty ($ models )) {
248
- return [];
241
+ if (!empty ($ this ->join ) && $ this ->indexBy === null ) {
242
+ $ rows = $ this ->removeDuplicatedRows ($ rows );
249
243
}
250
244
251
- if (!empty ($ this ->join ) && $ this ->getIndexBy () === null ) {
252
- $ models = $ this ->removeDuplicatedModels ($ models );
253
- }
245
+ $ models = $ this ->createModels ($ rows );
254
246
255
247
if (!empty ($ this ->with )) {
256
248
$ this ->findWith ($ this ->with , $ models );
@@ -260,94 +252,68 @@ public function populate(array $rows, Closure|string|null $indexBy = null): arra
260
252
$ this ->addInverseRelations ($ models );
261
253
}
262
254
263
- return ArArrayHelper:: index ( $ models, $ indexBy ) ;
255
+ return $ models ;
264
256
}
265
257
266
258
/**
267
- * Removes duplicated models by checking their primary key values.
259
+ * Removes duplicated rows by checking their primary key values.
268
260
*
269
261
* This method is mainly called when a join query is performed, which may cause duplicated rows being returned.
270
262
*
271
- * @param ActiveRecordInterface[]| array[] $models The models to be checked.
263
+ * @param array[] $rows The rows to be checked.
272
264
*
273
265
* @throws CircularReferenceException
274
266
* @throws Exception
275
267
* @throws InvalidConfigException
276
268
* @throws NotInstantiableException
277
269
*
278
- * @return ActiveRecordInterface[]|array[] The distinctive models.
270
+ * @return array[] The distinctive rows.
271
+ *
272
+ * @psalm-param non-empty-list<array> $rows
273
+ * @psalm-return non-empty-list<array>
279
274
*/
280
- private function removeDuplicatedModels (array $ models ): array
275
+ private function removeDuplicatedRows (array $ rows ): array
281
276
{
282
- $ model = reset ($ models );
277
+ $ instance = $ this ->getARInstance ();
278
+ $ pks = $ instance ->primaryKey ();
283
279
284
- if ($ this -> asArray ) {
285
- $ instance = $ this -> getARInstance ( );
286
- $ pks = $ instance -> primaryKey ();
280
+ if (empty ( $ pks ) ) {
281
+ throw new InvalidConfigException ( ' Primary key of " ' . $ instance::class . ' " can not be empty. ' );
282
+ }
287
283
288
- if (empty ($ pks )) {
289
- throw new InvalidConfigException ('Primary key of " ' . $ instance ::class . '" can not be empty. ' );
290
- }
291
-
292
- foreach ($ pks as $ pk ) {
293
- /** @var array $model */
294
- if (!isset ($ model [$ pk ])) {
295
- return $ models ;
296
- }
284
+ foreach ($ pks as $ pk ) {
285
+ if (!isset ($ rows [0 ][$ pk ])) {
286
+ return $ rows ;
297
287
}
288
+ }
298
289
299
- /** @var array[] $models */
300
- if (count ($ pks ) === 1 ) {
301
- $ hash = array_column ($ models , reset ($ pks ));
302
- } else {
303
- $ flippedPks = array_flip ($ pks );
304
- $ hash = array_map (
305
- static fn (array $ model ): string => serialize (array_intersect_key ($ model , $ flippedPks )),
306
- $ models
307
- );
308
- }
290
+ if (count ($ pks ) === 1 ) {
291
+ $ hash = array_column ($ rows , reset ($ pks ));
309
292
} else {
310
- /** @var ActiveRecordInterface $model */
311
- $ pks = $ model ->getPrimaryKey (true );
312
-
313
- if (empty ($ pks )) {
314
- throw new InvalidConfigException ('Primary key of " ' . $ model ::class . '" can not be empty. ' );
315
- }
316
-
317
- /** @var ActiveRecordInterface[] $models */
318
- foreach ($ pks as $ pk ) {
319
- if ($ pk === null ) {
320
- return $ models ;
321
- }
322
- }
323
-
324
- if (count ($ pks ) === 1 ) {
325
- $ key = array_key_first ($ pks );
326
- $ hash = array_map (
327
- static fn (ActiveRecordInterface $ model ): string => (string ) $ model ->get ($ key ),
328
- $ models
329
- );
330
- } else {
331
- $ hash = array_map (
332
- static fn (ActiveRecordInterface $ model ): string => serialize ($ model ->getPrimaryKey (true )),
333
- $ models
334
- );
335
- }
293
+ $ flippedPks = array_flip ($ pks );
294
+ $ hash = array_map (
295
+ static fn (array $ row ): string => serialize (array_intersect_key ($ row , $ flippedPks )),
296
+ $ rows
297
+ );
336
298
}
337
299
338
- return array_values (array_combine ($ hash , $ models ));
300
+ /** @psalm-var non-empty-list<array> */
301
+ return array_values (array_combine ($ hash , $ rows ));
339
302
}
340
303
341
304
public function one (): array |ActiveRecordInterface |null
342
305
{
343
- /** @var array|null $row */
344
- $ row = parent ::one ();
306
+ if ($ this ->shouldEmulateExecution ()) {
307
+ return null ;
308
+ }
309
+
310
+ $ row = $ this ->createCommand ()->queryOne ();
345
311
346
312
if ($ row === null ) {
347
313
return null ;
348
314
}
349
315
350
- return $ this ->populate ([ $ row])[ 0 ] ;
316
+ return $ this ->populateOne ( $ row) ;
351
317
}
352
318
353
319
/**
@@ -955,6 +921,11 @@ public function getARInstance(): ActiveRecordInterface
955
921
return new $ class ();
956
922
}
957
923
924
+ protected function index (array $ rows ): array
925
+ {
926
+ return ArArrayHelper::index ($ this ->populate ($ rows ), $ this ->indexBy );
927
+ }
928
+
958
929
private function createInstance (): static
959
930
{
960
931
return (new static ($ this ->arClass ))
@@ -974,4 +945,9 @@ private function createInstance(): static
974
945
->params ($ this ->params )
975
946
->withQueries ($ this ->withQueries );
976
947
}
948
+
949
+ private function populateOne (array $ row ): ActiveRecordInterface |array
950
+ {
951
+ return $ this ->populate ([$ row ])[0 ];
952
+ }
977
953
}
0 commit comments