Skip to content

Commit 58fafbd

Browse files
vjikTigrov
andauthored
Minor refactor + Psalm 1 + Some tests (#483)
Co-authored-by: Sergei Tigrov <rrr-r@ya.ru>
1 parent 6e0e19a commit 58fafbd

17 files changed

Lines changed: 277 additions & 210 deletions

psalm.xml

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,22 @@
11
<?xml version="1.0"?>
22
<psalm
3-
errorLevel="2"
4-
ensureOverrideAttribute="false"
5-
findUnusedBaselineEntry="true"
6-
findUnusedCode="false"
7-
resolveFromConfigFile="true"
8-
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9-
xmlns="https://getpsalm.org/schema/config"
10-
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
3+
errorLevel="1"
4+
findUnusedBaselineEntry="true"
5+
findUnusedCode="false"
6+
ensureOverrideAttribute="false"
7+
strictBinaryOperands="false"
8+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
9+
xmlns="https://getpsalm.org/schema/config"
10+
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
1111
>
12-
<projectFiles>
13-
<directory name="src" />
14-
<ignoreFiles>
15-
<directory name="vendor" />
16-
</ignoreFiles>
17-
</projectFiles>
18-
<issueHandlers>
19-
<MixedAssignment errorLevel="suppress" />
20-
<RiskyTruthyFalsyComparison errorLevel="suppress" />
21-
</issueHandlers>
12+
<projectFiles>
13+
<directory name="src" />
14+
<ignoreFiles>
15+
<directory name="vendor" />
16+
</ignoreFiles>
17+
</projectFiles>
18+
<issueHandlers>
19+
<MixedAssignment errorLevel="suppress" />
20+
<RiskyTruthyFalsyComparison errorLevel="suppress" />
21+
</issueHandlers>
2222
</psalm>

src/AbstractActiveRecord.php

Lines changed: 36 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use Yiisoft\Db\Exception\NotSupportedException;
1919
use Yiisoft\Db\Expression\Expression;
2020
use Yiisoft\Db\Expression\ExpressionInterface;
21+
use Yiisoft\Db\Query\QueryInterface;
2122
use Yiisoft\Db\Query\QueryPartsInterface;
2223

2324
use function array_diff_key;
@@ -48,6 +49,7 @@
4849
* See {@see ActiveRecord} for a concrete implementation.
4950
*
5051
* @psalm-import-type ModelClass from ActiveQuery
52+
* @psalm-import-type RawFrom from QueryInterface
5153
*/
5254
abstract class AbstractActiveRecord implements ActiveRecordInterface
5355
{
@@ -166,16 +168,6 @@ public function oldValue(string $propertyName): mixed
166168
return $this->oldValues[$propertyName] ?? null;
167169
}
168170

169-
/**
170-
* Returns the property values that have been modified since they're loaded or saved most recently.
171-
*
172-
* The comparison of new and old values uses `===`.
173-
*
174-
* @param array|null $propertyNames The names of the properties whose values may be returned if they're changed recently.
175-
* If null, {@see propertyNames()} will be used.
176-
*
177-
* @return array The changed property values (name-value pairs).
178-
*/
179171
public function newValues(array|null $propertyNames = null): array
180172
{
181173
$values = $this->propertyValues($propertyNames);
@@ -330,6 +322,7 @@ public function hasProperty(string $name): bool
330322
* @return ActiveQueryInterface The relational query object.
331323
*
332324
* @psalm-param ModelClass $modelClass
325+
* @psalm-param array<string, string> $link
333326
*/
334327
public function hasMany(ActiveRecordInterface|string $modelClass, array $link): ActiveQueryInterface
335328
{
@@ -369,6 +362,7 @@ public function hasMany(ActiveRecordInterface|string $modelClass, array $link):
369362
* @return ActiveQueryInterface The relational query object.
370363
*
371364
* @psalm-param ModelClass $modelClass
365+
* @psalm-param array<string, string> $link
372366
*/
373367
public function hasOne(ActiveRecordInterface|string $modelClass, array $link): ActiveQueryInterface
374368
{
@@ -436,10 +430,8 @@ public function link(string $relationName, ActiveRecordInterface $linkModel, arr
436430

437431
if (is_array($via)) {
438432
[$viaName, $viaRelation] = $via;
439-
/** @var ActiveQueryInterface $viaRelation */
440433
$viaModel = $viaRelation->getModel();
441434
// unset $viaName so that it can be reloaded to reflect the change.
442-
/** @var string $viaName */
443435
unset($this->related[$viaName]);
444436
} else {
445437
$viaRelation = $via;
@@ -504,15 +496,19 @@ public function link(string $relationName, ActiveRecordInterface $linkModel, arr
504496
if (!$relation->isMultiple()) {
505497
$this->related[$relationName] = $linkModel;
506498
} elseif (isset($this->related[$relationName])) {
507-
/** @psalm-var ActiveRecordInterface[] $this->related[$relationName] */
499+
/**
500+
* Related records are already an array.
501+
* @psalm-var array<string, ActiveRecordInterface[]|array[]> $this->related[$relationName]
502+
*/
508503
$indexBy = $relation->getIndexBy();
509504
if ($indexBy !== null) {
510-
if ($indexBy instanceof Closure) {
511-
$index = $indexBy($linkModel);
512-
} else {
513-
$index = $linkModel->get($indexBy);
514-
}
515-
505+
/**
506+
* We assume that the index is always string, int or null.
507+
* @var int|string|null $index
508+
*/
509+
$index = $indexBy instanceof Closure
510+
? $indexBy($linkModel)
511+
: $linkModel->get($indexBy);
516512
if ($index !== null) {
517513
$this->related[$relationName][$index] = $linkModel;
518514
}
@@ -537,19 +533,9 @@ public function markPropertyChanged(string $name): void
537533
}
538534
}
539535

540-
/**
541-
* Populates an active record object using a row of data from the database/storage.
542-
*
543-
* This is an internal method meant to be called to create active record objects after fetching data from the
544-
* database. It is mainly used by {@see ActiveQuery} to populate the query results into active records.
545-
*
546-
* @param array|object $row Property values (name => value).
547-
*/
548-
public function populateRecord(array|object $row): void
536+
public function populateRecord(array|object $row): static
549537
{
550-
if ($row instanceof ActiveRecordInterface) {
551-
$row = $row->propertyValues();
552-
}
538+
$row = ArArrayHelper::toArray($row);
553539

554540
foreach ($row as $name => $value) {
555541
$this->populateProperty($name, $value);
@@ -558,6 +544,7 @@ public function populateRecord(array|object $row): void
558544

559545
$this->related = [];
560546
$this->relationsDependencies = [];
547+
return $this;
561548
}
562549

563550
public function populateRelation(string $name, array|ActiveRecordInterface|null $records): void
@@ -649,12 +636,12 @@ public function set(string $propertyName, mixed $value): void
649636
* @param array $values Property values (name => value) to be assigned to the model.
650637
*
651638
* @see propertyNames()
639+
*
640+
* @psalm-param array<string, mixed> $values
652641
*/
653642
public function populateProperties(array $values): void
654643
{
655644
$values = array_intersect_key($values, array_flip($this->propertyNames()));
656-
657-
/** @psalm-var mixed $value */
658645
foreach ($values as $name => $value) {
659646
$this->populateProperty($name, $value);
660647
}
@@ -744,6 +731,8 @@ public function updateAll(array $propertyValues, array|string $condition = [], a
744731
* @throws Throwable
745732
*
746733
* @return int The number of rows updated.
734+
*
735+
* @psalm-param RawFrom|null $from
747736
*/
748737
public function updateAllCounters(array $counters, array|string $condition = '', array|ExpressionInterface|string|null $from = null, array $params = []): int
749738
{
@@ -793,6 +782,9 @@ public function updateCounters(array $counters): bool
793782
}
794783

795784
foreach ($counters as $name => $value) {
785+
/**
786+
* @psalm-suppress MixedOperand We assume that the counter value is always an integer.
787+
*/
796788
$value += $this->get($name) ?? 0;
797789
$this->populateProperty($name, $value);
798790
$this->oldValues[$name] = $value;
@@ -1052,6 +1044,7 @@ private function setRelationDependencies(
10521044
* @return ActiveQueryInterface The relational query object.
10531045
*
10541046
* @psalm-param ModelClass $modelClass
1047+
* @psalm-param array<string, string> $link
10551048
*
10561049
* {@see hasOne()}
10571050
* {@see hasMany()}
@@ -1111,6 +1104,8 @@ protected function deleteInternal(): int
11111104
* Defaults to `null`, meaning all changed property values will be returned.
11121105
*
11131106
* @return array The changed property values (name-value pairs).
1107+
*
1108+
* @psalm-return array<string, mixed>
11141109
*/
11151110
protected function newPropertyValues(array|null $properties = null): array
11161111
{
@@ -1175,7 +1170,6 @@ protected function updateInternal(array|null $properties = null): int
11751170
}
11761171

11771172
$values = $this->newPropertyValues($properties);
1178-
11791173
if (empty($values)) {
11801174
return 0;
11811175
}
@@ -1184,6 +1178,10 @@ protected function updateInternal(array|null $properties = null): int
11841178

11851179
if ($this instanceof OptimisticLockInterface) {
11861180
$lock = $this->optimisticLockPropertyName();
1181+
1182+
/**
1183+
* @var int $lockValue We assume that optimistic lock property value is always an integer.
1184+
*/
11871185
$lockValue = $this->get($lock);
11881186

11891187
$condition[$lock] = $lockValue;
@@ -1207,14 +1205,15 @@ protected function updateInternal(array|null $properties = null): int
12071205
return $rows;
12081206
}
12091207

1208+
/**
1209+
* @psalm-param array<string, string> $link
1210+
*/
12101211
private function bindModels(
12111212
array $link,
12121213
ActiveRecordInterface $foreignModel,
12131214
ActiveRecordInterface $primaryModel
12141215
): void {
1215-
/** @psalm-var string[] $link */
12161216
foreach ($link as $fk => $pk) {
1217-
/** @psalm-var mixed $value */
12181217
$value = $primaryModel->get($pk);
12191218

12201219
if ($value === null) {
@@ -1223,11 +1222,8 @@ private function bindModels(
12231222
);
12241223
}
12251224

1226-
/**
1227-
* Relation via array valued property.
1228-
*/
1225+
// Relation via array valued property
12291226
if (is_array($fkValue = $foreignModel->get($fk))) {
1230-
/** @psalm-var mixed */
12311227
$fkValue[] = $value;
12321228
$foreignModel->set($fk, $fkValue);
12331229
} else {

0 commit comments

Comments
 (0)