Skip to content

Commit 711f4cc

Browse files
authored
Update according changes in DB (#409)
1 parent 513810c commit 711f4cc

File tree

10 files changed

+135
-131
lines changed

10 files changed

+135
-131
lines changed

src/ActiveQuery.php

Lines changed: 61 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
use Yiisoft\Db\Exception\NotSupportedException;
1515
use Yiisoft\Db\Expression\ExpressionInterface;
1616
use Yiisoft\Db\Helper\DbArrayHelper;
17-
use Yiisoft\Db\Query\BatchQueryResultInterface;
17+
use Yiisoft\Db\Query\DataReaderInterface;
1818
use Yiisoft\Db\Query\Query;
1919
use Yiisoft\Db\Query\QueryInterface;
2020
use Yiisoft\Db\QueryBuilder\QueryBuilderInterface;
@@ -25,7 +25,6 @@
2525
use function array_combine;
2626
use function array_flip;
2727
use function array_intersect_key;
28-
use function array_key_first;
2928
use function array_map;
3029
use function array_merge;
3130
use function array_values;
@@ -104,7 +103,7 @@
104103
* @psalm-import-type ARClass from ActiveQueryInterface
105104
* @psalm-import-type IndexKey from ArArrayHelper
106105
*
107-
* @psalm-property IndexKey $indexBy
106+
* @psalm-property IndexKey|null $indexBy
108107
* @psalm-suppress ClassMustBeFinal
109108
*/
110109
class ActiveQuery extends Query implements ActiveQueryInterface
@@ -125,23 +124,13 @@ final public function __construct(
125124
parent::__construct($this->getARInstance()->db());
126125
}
127126

128-
public function all(): array
127+
public function each(): DataReaderInterface
129128
{
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(...));
145134
}
146135

147136
/**
@@ -235,22 +224,25 @@ public function prepare(QueryBuilderInterface $builder): QueryInterface
235224
* @throws NotSupportedException
236225
* @throws ReflectionException
237226
* @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+
* )
238234
*/
239-
public function populate(array $rows, Closure|string|null $indexBy = null): array
235+
public function populate(array $rows): array
240236
{
241237
if (empty($rows)) {
242238
return [];
243239
}
244240

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);
249243
}
250244

251-
if (!empty($this->join) && $this->getIndexBy() === null) {
252-
$models = $this->removeDuplicatedModels($models);
253-
}
245+
$models = $this->createModels($rows);
254246

255247
if (!empty($this->with)) {
256248
$this->findWith($this->with, $models);
@@ -260,94 +252,68 @@ public function populate(array $rows, Closure|string|null $indexBy = null): arra
260252
$this->addInverseRelations($models);
261253
}
262254

263-
return ArArrayHelper::index($models, $indexBy);
255+
return $models;
264256
}
265257

266258
/**
267-
* Removes duplicated models by checking their primary key values.
259+
* Removes duplicated rows by checking their primary key values.
268260
*
269261
* This method is mainly called when a join query is performed, which may cause duplicated rows being returned.
270262
*
271-
* @param ActiveRecordInterface[]|array[] $models The models to be checked.
263+
* @param array[] $rows The rows to be checked.
272264
*
273265
* @throws CircularReferenceException
274266
* @throws Exception
275267
* @throws InvalidConfigException
276268
* @throws NotInstantiableException
277269
*
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>
279274
*/
280-
private function removeDuplicatedModels(array $models): array
275+
private function removeDuplicatedRows(array $rows): array
281276
{
282-
$model = reset($models);
277+
$instance = $this->getARInstance();
278+
$pks = $instance->primaryKey();
283279

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+
}
287283

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;
297287
}
288+
}
298289

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));
309292
} 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+
);
336298
}
337299

338-
return array_values(array_combine($hash, $models));
300+
/** @psalm-var non-empty-list<array> */
301+
return array_values(array_combine($hash, $rows));
339302
}
340303

341304
public function one(): array|ActiveRecordInterface|null
342305
{
343-
/** @var array|null $row */
344-
$row = parent::one();
306+
if ($this->shouldEmulateExecution()) {
307+
return null;
308+
}
309+
310+
$row = $this->createCommand()->queryOne();
345311

346312
if ($row === null) {
347313
return null;
348314
}
349315

350-
return $this->populate([$row])[0];
316+
return $this->populateOne($row);
351317
}
352318

353319
/**
@@ -955,6 +921,11 @@ public function getARInstance(): ActiveRecordInterface
955921
return new $class();
956922
}
957923

924+
protected function index(array $rows): array
925+
{
926+
return ArArrayHelper::index($this->populate($rows), $this->indexBy);
927+
}
928+
958929
private function createInstance(): static
959930
{
960931
return (new static($this->arClass))
@@ -974,4 +945,9 @@ private function createInstance(): static
974945
->params($this->params)
975946
->withQueries($this->withQueries);
976947
}
948+
949+
private function populateOne(array $row): ActiveRecordInterface|array
950+
{
951+
return $this->populate([$row])[0];
952+
}
977953
}

src/ActiveQueryInterface.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,16 @@ public function sql(string|null $value): static;
351351
*
352352
* @param array[] $rows The raw query result from a database.
353353
*
354-
* @psalm-param IndexKey|null $indexBy
355-
*
356354
* @return ActiveRecordInterface[]|array[] The converted query result.
355+
*
356+
* @psalm-param list<array> $rows
357+
* @psalm-return (
358+
* $rows is non-empty-list<array>
359+
* ? non-empty-list<ActiveRecordInterface|array>
360+
* : list<ActiveRecordInterface|array>
361+
* )
357362
*/
358-
public function populate(array $rows, Closure|string|null $indexBy = null): array;
363+
public function populate(array $rows): array;
359364

360365
/**
361366
* Returns related record(s).
@@ -640,6 +645,9 @@ public function one(): array|ActiveRecordInterface|null;
640645
* @throws InvalidArgumentException|InvalidConfigException|NotSupportedException|Throwable If {@see link()} is
641646
* invalid.
642647
* @return ActiveRecordInterface[]|array[] The related models.
648+
*
649+
* @psalm-param non-empty-list<ActiveRecordInterface|array> $primaryModels
650+
* @psalm-param-out non-empty-list<ActiveRecordInterface|array> $primaryModels
643651
*/
644652
public function populateRelation(string $name, array &$primaryModels): array;
645653
}

src/ActiveQueryTrait.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,28 +107,35 @@ public function with(array|string ...$with): static
107107
*
108108
* @throws InvalidConfigException
109109
* @return ActiveRecordInterface[]|array[] The model instances.
110+
*
111+
* @psalm-param non-empty-list<array> $rows
112+
* @psalm-return non-empty-list<ActiveRecordInterface|array>
110113
*/
111114
protected function createModels(array $rows): array
112115
{
113116
if ($this->asArray) {
114117
return $rows;
115118
}
116119

117-
$arClassInstance = [];
118-
119-
foreach ($rows as $row) {
120-
$arClass = $this->getARInstance();
120+
if ($this->resultCallback !== null) {
121+
$rows = ($this->resultCallback)($rows);
121122

122-
if (method_exists($arClass, 'instantiate')) {
123-
$arClass = $arClass->instantiate($row);
123+
if ($rows[0] instanceof ActiveRecordInterface) {
124+
/** @psalm-var non-empty-list<ActiveRecordInterface> */
125+
return $rows;
124126
}
127+
}
128+
129+
$models = [];
125130

131+
foreach ($rows as $row) {
132+
$arClass = $this->getARInstance();
126133
$arClass->populateRecord($row);
127134

128-
$arClassInstance[] = $arClass;
135+
$models[] = $arClass;
129136
}
130137

131-
return $arClassInstance;
138+
return $models;
132139
}
133140

134141
/**
@@ -144,7 +151,8 @@ protected function createModels(array $rows): array
144151
* @throws ReflectionException
145152
* @throws Throwable
146153
*
147-
* @param-out ActiveRecordInterface[]|array[] $models
154+
* @psalm-param non-empty-list<ActiveRecordInterface|array> $models
155+
* @psalm-param-out non-empty-list<ActiveRecordInterface|array> $models
148156
*/
149157
public function findWith(array $with, array &$models): void
150158
{

src/ActiveRelationTrait.php

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,8 @@ public function relatedRecords(): ActiveRecordInterface|array|null
202202
*
203203
* @throws InvalidConfigException
204204
*
205-
* @param-out ActiveRecordInterface[]|array[] $result
205+
* @psalm-param non-empty-list<ActiveRecordInterface|array> $result
206+
* @psalm-param-out non-empty-list<ActiveRecordInterface|array> $result
206207
*/
207208
private function addInverseRelations(array &$result): void
208209
{
@@ -232,9 +233,10 @@ private function addInverseRelations(array &$result): void
232233
}
233234

234235
/**
235-
* @return ActiveRecordInterface[]|array[]
236+
* @psalm-param non-empty-list<ActiveRecordInterface|array> $primaryModels
237+
* @psalm-param-out non-empty-list<ActiveRecordInterface|array> $primaryModels
236238
*
237-
* @param-out ActiveRecordInterface[]|array[] $primaryModels
239+
* @return ActiveRecordInterface[]|array[]
238240
*/
239241
public function populateRelation(string $name, array &$primaryModels): array
240242
{
@@ -262,16 +264,16 @@ public function populateRelation(string $name, array &$primaryModels): array
262264
$models = [$this->one()];
263265
$this->populateInverseRelation($models, $primaryModels);
264266

265-
$primaryModel = reset($primaryModels);
267+
$primaryModel = $primaryModels[0];
266268

267269
if ($primaryModel instanceof ActiveRecordInterface) {
268270
$primaryModel->populateRelation($name, $models[0]);
269271
} else {
270272
/**
271-
* @var array[] $primaryModels
272-
* @psalm-suppress PossiblyNullArrayOffset
273+
* @psalm-var non-empty-list<array> $primaryModels
274+
* @psalm-suppress UndefinedInterfaceMethod
273275
*/
274-
$primaryModels[key($primaryModels)][$name] = $models[0];
276+
$primaryModels[0][$name] = $models[0];
275277
}
276278

277279
return $models;
@@ -319,12 +321,14 @@ public function populateRelation(string $name, array &$primaryModels): array
319321

320322
/**
321323
* @throws \Yiisoft\Definitions\Exception\InvalidConfigException
324+
*
325+
* @psalm-param non-empty-list<ActiveRecordInterface|array> $primaryModels
322326
*/
323327
private function populateInverseRelation(
324328
array &$models,
325329
array $primaryModels,
326330
): void {
327-
if ($this->inverseOf === null || empty($models) || empty($primaryModels)) {
331+
if ($this->inverseOf === null || empty($models)) {
328332
return;
329333
}
330334

@@ -643,13 +647,11 @@ private function getModelKeys(ActiveRecordInterface|array $model, array $propert
643647
* @throws Throwable
644648
* @throws \Yiisoft\Definitions\Exception\InvalidConfigException
645649
* @return array[]
650+
*
651+
* @psalm-param non-empty-list<ActiveRecordInterface|array> $primaryModels
646652
*/
647653
private function findJunctionRows(array $primaryModels): array
648654
{
649-
if (empty($primaryModels)) {
650-
return [];
651-
}
652-
653655
$this->filterByModels($primaryModels);
654656

655657
/** @var array[] */

0 commit comments

Comments
 (0)