From 85191ef5938740f852492f06f501b6a8b10c8a61 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Tue, 26 May 2026 16:08:55 +0700 Subject: [PATCH 1/4] Add generic type annotations --- src/AbstractActiveRecord.php | 19 +++++++++++-- src/ActiveQuery.php | 50 ++++++++++++++++++++++++----------- src/ActiveQueryInterface.php | 36 +++++++++++++++++++------ src/ActiveRecordInterface.php | 19 +++++++++---- src/Trait/RepositoryTrait.php | 21 ++++++++------- 5 files changed, 105 insertions(+), 40 deletions(-) diff --git a/src/AbstractActiveRecord.php b/src/AbstractActiveRecord.php index 511e629cd..d46e196a2 100644 --- a/src/AbstractActiveRecord.php +++ b/src/AbstractActiveRecord.php @@ -47,7 +47,6 @@ * * See {@see ActiveRecord} for a concrete implementation. * - * @psalm-import-type ModelClass from ActiveQuery * @psalm-import-type RawFrom from QueryInterface */ abstract class AbstractActiveRecord implements ActiveRecordInterface @@ -61,6 +60,12 @@ abstract class AbstractActiveRecord implements ActiveRecordInterface /** @var string[][] */ private array $relationsDependencies = []; + /** + * @template T as ActiveRecordInterface + * @template TModelClass as T|class-string|null + * @psalm-param TModelClass $modelClass + * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), false> + */ public function createQuery(ActiveRecordInterface|string|null $modelClass = null): ActiveQueryInterface { $modelClass ??= $this; @@ -419,8 +424,15 @@ public function populateRelation(string $name, array|ActiveRecordInterface|null $this->related[$name] = $records; } + /** + * @template T as ActiveRecordInterface + * @template TModelClass as T|class-string|null + * @psalm-param TModelClass $modelClass + * @psalm-return ActiveQuery<(TModelClass is null ? static : T), false> + */ public static function query(ActiveRecordInterface|string|null $modelClass = null): ActiveQueryInterface { + /** @psalm-var ActiveQuery<(TModelClass is null ? static : T), false> */ return new ActiveQuery($modelClass ?? static::class); } @@ -822,8 +834,10 @@ protected function retrieveRelation(string $name): ActiveRecordInterface|array|n * * @return ActiveQueryInterface The relational query object. * - * @psalm-param ModelClass $modelClass + * @template T as ActiveRecordInterface + * @psalm-param T|class-string $modelClass * @psalm-param array $link + * @psalm-return ActiveQueryInterface * * @see AbstractActiveRecord::hasOne() * @see AbstractActiveRecord::hasMany() @@ -833,6 +847,7 @@ protected function createRelationQuery( array $link, bool $multiple, ): ActiveQueryInterface { + /** @psalm-var ActiveQueryInterface */ return $this->createQuery($modelClass)->primaryModel($this)->link($link)->multiple($multiple); } diff --git a/src/ActiveQuery.php b/src/ActiveQuery.php index b18b94507..b9b568ea6 100644 --- a/src/ActiveQuery.php +++ b/src/ActiveQuery.php @@ -106,10 +106,11 @@ * and {@see ActiveQuery::on()} which adds a condition that is to be added to relational * query join condition. * - * @psalm-type ModelClass = ActiveRecordInterface|class-string + * @template TModel as ActiveRecordInterface + * @template TAsArray as ?bool + * @implements ActiveQueryInterface * @psalm-import-type IndexBy from QueryInterface * @psalm-import-type Join from QueryInterface - * @psalm-import-type ActiveQueryResult from ActiveQueryInterface * @psalm-import-type Via from ActiveQueryInterface * * @psalm-property IndexBy|null $indexBy @@ -117,9 +118,11 @@ */ class ActiveQuery extends Query implements ActiveQueryInterface { + /** @psalm-var TModel $model */ private ActiveRecordInterface $model; private ?string $sql = null; private array|ExpressionInterface|string|null $on = null; + /** @psalm-var TAsArray $asArray */ private ?bool $asArray = null; private array $with = []; private bool $multiple = false; @@ -155,7 +158,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface private array|ActiveQueryInterface|null $via = null; /** - * @psalm-param ModelClass $modelClass + * @psalm-param TModel|class-string $modelClass */ final public function __construct( ActiveRecordInterface|string $modelClass, @@ -180,9 +183,17 @@ public function __clone() } } + /** + * @template T as ?bool + * @psalm-param T $value + * @psalm-return static + */ public function asArray(?bool $value = true): static { + /** @psalm-suppress InvalidPropertyAssignmentValue */ $this->asArray = $value; + + /** @psalm-var static */ return $this; } @@ -325,11 +336,13 @@ public function populate(array $rows): array $this->findWith($this->with, $models); } + /** @psalm-var non-empty-list<(TAsArray is true ? array : TModel)> $models */ $this->addInverseRelations($models); return $models; } + /** @psalm-return (TAsArray is true ? array : TModel)|null */ public function one(): array|ActiveRecordInterface|null { if ($this->shouldEmulateExecution()) { @@ -451,6 +464,7 @@ public function viaTable(string $tableName, array $link, ?callable $callable = n { $model = $this->primaryModel ?? $this->model; + /** @psalm-suppress UnsafeGenericInstantiation, InvalidTemplateParam */ $relation = (new static($model)) ->from([$tableName]) ->link($link) @@ -509,6 +523,7 @@ public function getSql(): ?string return $this->sql; } + /** @psalm-return (TAsArray is true ? array : TModel)|null */ public function findByPk(array|float|int|string $values): array|ActiveRecordInterface|null { $values = (array) $values; @@ -543,6 +558,7 @@ public function sql(?string $value): static return $this; } + /** @psalm-return TModel */ public function getModel(): ActiveRecordInterface { return clone $this->model; @@ -686,7 +702,7 @@ protected function index(array $rows): array * @return ActiveRecordInterface[]|array[] The model instances. * * @psalm-param non-empty-list> $rows - * @psalm-return non-empty-list + * @psalm-return non-empty-list<(TAsArray is true ? array : TModel)> */ protected function createModels(array $rows): array { @@ -702,12 +718,12 @@ protected function createModels(array $rows): array $rows = ($this->resultCallback)($rows); if ($rows[0] instanceof ActiveRecordInterface) { - /** @psalm-var non-empty-list */ + /** @psalm-var non-empty-list */ return $rows; } } - /** @var non-empty-list> $rows */ + /** @psalm-var non-empty-list> $rows */ return array_map( fn(array $row) => $this->getModel()->populateRecord($row), $rows, @@ -758,9 +774,10 @@ private function removeDuplicatedRows(array $rows): array return array_values(array_combine($hash, $rows)); } - private function createInstance(): static + private function createInstance(): ActiveQueryInterface { - return (new static($this->model)) + return $this->model + ->createQuery() ->where($this->getWhere()) ->limit($this->getLimit()) ->offset($this->getOffset()) @@ -780,7 +797,7 @@ private function createInstance(): static /** * @psalm-param array $row - * @psalm-return ActiveQueryResult + * @psalm-return (TAsArray is true ? array : TModel) */ private function populateOne(array $row): ActiveRecordInterface|array { @@ -800,8 +817,8 @@ private function populateOne(array $row): ActiveRecordInterface|array * @throws ReflectionException * @throws Throwable * - * @psalm-param non-empty-list $models - * @psalm-param-out non-empty-list $models + * @psalm-param non-empty-list> $models + * @psalm-param-out non-empty-list> $models */ private function findWith(array $with, array &$models): void { @@ -872,14 +889,13 @@ private function normalizeRelations(ActiveRecordInterface $model, array $with): * @param ActiveRecordInterface[]|array[] $result the array of related records as generated * by {@see ActiveQuery::populate()} * - * @throws InvalidConfigException - * - * @psalm-param non-empty-list $result - * @psalm-param-out non-empty-list $result + * @psalm-param non-empty-list<(TAsArray is true ? array : TModel)> $result + * @psalm-param-out non-empty-list<(TAsArray is true ? array : TModel)> $result */ private function addInverseRelations(array &$result): void { if ($this->inverseOf === null) { + /** @psalm-var non-empty-list<(TAsArray is true ? array : TModel)> $result */ return; } @@ -889,7 +905,7 @@ private function addInverseRelations(array &$result): void $inverseRelation = $relatedModel->relationQuery($this->inverseOf); $primaryModel = $inverseRelation->isMultiple() ? [$this->primaryModel] : $this->primaryModel; - /** @var ActiveRecordInterface $relatedModel */ + /** @psalm-var TModel $relatedModel */ foreach ($result as $relatedModel) { $relatedModel->populateRelation($this->inverseOf, $primaryModel); } @@ -902,5 +918,7 @@ private function addInverseRelations(array &$result): void $relatedModel[$this->inverseOf] = $primaryModel; } } + + /** @psalm-var non-empty-list<(TAsArray is true ? array : TModel)> $result */ } } diff --git a/src/ActiveQueryInterface.php b/src/ActiveQueryInterface.php index ad8432ead..4474a6b1f 100644 --- a/src/ActiveQueryInterface.php +++ b/src/ActiveQueryInterface.php @@ -19,11 +19,12 @@ /** * A common interface to be implemented by active record query classes. * - * That are methods for all normal queries that return active records but also relational queries in which the query + * These are methods for all normal queries that return active records but also relational queries in which the query * represents a relation between two active record classes and will return related records only. * + * @template TModel as ActiveRecordInterface + * @template TAsArray as ?bool * @psalm-type Via = array{string, ActiveQueryInterface, bool}|ActiveQueryInterface - * @psalm-type ActiveQueryResult = ActiveRecordInterface|array */ interface ActiveQueryInterface extends QueryInterface { @@ -39,16 +40,20 @@ interface ActiveQueryInterface extends QueryInterface * on {@see ActiveQueryInterface::isAsArray()} result. * Empty array if the query results in nothing. * - * @psalm-return array + * @psalm-return (TAsArray is true ? array> : TModel[]) */ public function all(): array; /** * Sets the {@see ActiveQuery::$asArray} property. * - * @param bool|null $value Whether to return the query results in terms of arrays instead of Active Records. + * @param ?bool $value Whether to return the query results in terms of arrays instead of Active Records. * * @return static The query object itself. + * + * @template T as ?bool + * @psalm-param T $value + * @psalm-return static */ public function asArray(?bool $value = true): static; @@ -217,6 +222,7 @@ public function getJoinsWith(): array; * * @psalm-param array|string $with * @psalm-param array|string $joinType + * @psalm-return static */ public function joinWith( array|string $with, @@ -372,8 +378,8 @@ public function sql(?string $value): static; * @psalm-param list> $rows * @psalm-return ( * $rows is non-empty-list> - * ? non-empty-list - * : list + * ? non-empty-list<(TAsArray is true ? array : TModel)> + * : list<(TAsArray is true ? array : TModel)> * ) */ public function populate(array $rows): array; @@ -446,6 +452,12 @@ public function getInverseOf(): ?string; * @throws Throwable if the relation is invalid. * * @return ActiveRecordInterface|ActiveRecordInterface[]|array|array[]|null the related record(s). + * + * @psalm-return ( + * TAsArray is true + * ? array|array> + * : TModel|TModel[] + * )|null */ public function relatedRecords(): ActiveRecordInterface|array|null; @@ -483,12 +495,16 @@ public function relatedRecords(): ActiveRecordInterface|array|null; * $customer = $customerQuery->findByPk($id); * } * ``` + * + * @psalm-return (TAsArray is true ? array : TModel)|null */ public function findByPk(array|float|int|string $values): array|ActiveRecordInterface|null; /** * Returns a value indicating whether the query result rows should be returned as arrays instead of Active Record * models. + * + * @psalm-return TAsArray */ public function isAsArray(): ?bool; @@ -547,6 +563,8 @@ public function getLink(): array; /** * @return ActiveRecordInterface The model instance associated with this query. + * + * @psalm-return TModel */ public function getModel(): ActiveRecordInterface; @@ -581,6 +599,8 @@ public function isMultiple(): bool; * * @return ActiveRecordInterface|array|null The first row as an `array` or instance of {@see ActiveRecordInterface} * of the query result, depends on {@see ActiveQueryInterface::isAsArray()} result. `null` if the query results in nothing. + * + * @psalm-return (TAsArray is true ? array : TModel)|null */ public function one(): array|ActiveRecordInterface|null; @@ -595,8 +615,8 @@ public function one(): array|ActiveRecordInterface|null; * {@see ActiveQueryInterface::link()} is invalid. * @return ActiveRecordInterface[]|array[] The related models. * - * @psalm-param non-empty-list $primaryModels - * @psalm-param-out non-empty-list $primaryModels + * @psalm-param non-empty-list> $primaryModels + * @psalm-param-out non-empty-list> $primaryModels */ public function populateRelation(string $name, array &$primaryModels): array; } diff --git a/src/ActiveRecordInterface.php b/src/ActiveRecordInterface.php index c68bb9098..3ad4ff392 100644 --- a/src/ActiveRecordInterface.php +++ b/src/ActiveRecordInterface.php @@ -17,7 +17,6 @@ use Yiisoft\Db\Schema\TableSchemaInterface; /** - * @psalm-import-type ModelClass from ActiveQuery * @psalm-import-type RawFrom from QueryInterface */ interface ActiveRecordInterface @@ -42,7 +41,10 @@ public function column(string $propertyName): ColumnInterface; * @param ActiveRecordInterface|string|null $modelClass The class name of the related record, or an instance * of the related record. If `null`, the current model will be used. * - * @psalm-param ModelClass|null $modelClass + * @template T as ActiveRecordInterface + * @template TModelClass as T|class-string|null + * @psalm-param TModelClass $modelClass + * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), false> */ public function createQuery(self|string|null $modelClass = null): ActiveQueryInterface; @@ -299,8 +301,10 @@ public function hasProperty(string $name): bool; * * @return ActiveQueryInterface The relational query object. * - * @psalm-param ModelClass $modelClass + * @template T as ActiveRecordInterface + * @psalm-param T|class-string $modelClass * @psalm-param array $link + * @psalm-return ActiveQueryInterface */ public function hasMany(self|string $modelClass, array $link): ActiveQueryInterface; @@ -336,8 +340,10 @@ public function hasMany(self|string $modelClass, array $link): ActiveQueryInterf * * @return ActiveQueryInterface The relational query object. * - * @psalm-param ModelClass $modelClass + * @template T as ActiveRecordInterface + * @psalm-param T|class-string $modelClass * @psalm-param array $link + * @psalm-return ActiveQueryInterface */ public function hasOne(self|string $modelClass, array $link): ActiveQueryInterface; @@ -458,7 +464,10 @@ public function populateRelation(string $name, array|self|null $records): void; * @param ActiveRecordInterface|string|null $modelClass The class name of the related record, or an instance * of the related record. If `null`, the current model class will be used. * - * @psalm-param ModelClass|null $modelClass + * @template T as ActiveRecordInterface + * @template TModelClass as T|class-string|null + * @psalm-param TModelClass $modelClass + * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), false> */ public static function query(self|string|null $modelClass = null): ActiveQueryInterface; diff --git a/src/Trait/RepositoryTrait.php b/src/Trait/RepositoryTrait.php index 9b5a6923b..78ebc07f6 100644 --- a/src/Trait/RepositoryTrait.php +++ b/src/Trait/RepositoryTrait.php @@ -50,6 +50,8 @@ trait RepositoryTrait * @param array|ExpressionInterface|string|null $condition The condition to be applied to the query where clause. * No condition is applied if `null` (by default). * @param array $params The parameters to be bound to the SQL statement during execution. + * + * @psalm-return ActiveQueryInterface */ public static function find(array|string|ExpressionInterface|null $condition = null, array $params = []): ActiveQueryInterface { @@ -98,7 +100,7 @@ public static function find(array|string|ExpressionInterface|null $condition = n * Returns all records if `null` (by default). * @param array $params The parameters to be bound to the SQL statement during execution. * - * @return ActiveRecordInterface[]|array[] An array of ActiveRecord instance, or an empty array if nothing matches. + * @return static[]|array[] An array of ActiveRecord instance, or an empty array if nothing matches. */ public static function findAll(array|string|ExpressionInterface|null $condition = null, array $params = []): array { @@ -118,8 +120,7 @@ public static function findAll(array|string|ExpressionInterface|null $condition * * @throws NotFoundException * - * @return ActiveRecordInterface[]|array[] An array of ActiveRecord instance, or throws {@see NotFoundException} - * if nothing matches. + * @return static[]|array[] An array of ActiveRecord instance, or throws {@see NotFoundException} if nothing matches. */ public static function findAllOrFail(array|string|ExpressionInterface|null $condition = null, array $params = []): array { @@ -158,7 +159,7 @@ public static function findAllOrFail(array|string|ExpressionInterface|null $cond * * @param array|float|int|string $values The primary key value(s) to find the record. * - * @return ActiveRecordInterface|array|null Instance matching the primary key value(s), or `null` if nothing matches. + * @return static|array|null Instance matching the primary key value(s), or `null` if nothing matches. */ public static function findByPk(array|float|int|string $values): array|ActiveRecordInterface|null { @@ -176,10 +177,10 @@ public static function findByPk(array|float|int|string $values): array|ActiveRec * * @throws NotFoundException * - * @return ActiveRecordInterface|array|null Instance matching the primary key value(s), + * @return static|array Instance matching the primary key value(s), * or throws {@see NotFoundException} if nothing matches. */ - public static function findByPkOrFail(array|float|int|string $values): array|ActiveRecordInterface|null + public static function findByPkOrFail(array|float|int|string $values): array|ActiveRecordInterface { return static::findByPk($values) ?? throw new NotFoundException('No records found.'); } @@ -204,6 +205,8 @@ public static function findByPkOrFail(array|float|int|string $values): array|Act * @param array $params The parameters to be bound to the SQL statement during execution. * * @return ActiveQueryInterface The newly created {@see ActiveQueryInterface} instance. + * + * @psalm-return ActiveQueryInterface */ public static function findBySql(string $sql, array $params = []): ActiveQueryInterface { @@ -246,7 +249,7 @@ public static function findBySql(string $sql, array $params = []): ActiveQueryIn * Returns the first record if `null` (by default). * @param array $params The parameters to be bound to the SQL statement during execution. * - * @return ActiveRecordInterface|array|null Instance matching the condition, or `null` if nothing matches. + * @return static|array|null Instance matching the condition, or `null` if nothing matches. */ public static function findOne( array|string|ExpressionInterface|null $condition = null, @@ -268,13 +271,13 @@ public static function findOne( * * @throws NotFoundException * - * @return ActiveRecordInterface|array|null Instance matching the condition, or throws {@see NotFoundException} + * @return static|array Instance matching the condition, or throws {@see NotFoundException} * if nothing matches. */ public static function findOneOrFail( array|string|ExpressionInterface|null $condition = null, array $params = [], - ): ActiveRecordInterface|array|null { + ): ActiveRecordInterface|array { return static::findOne($condition, $params) ?? throw new NotFoundException('No records found.'); } } From 136843187849fd01091eda9820d86ec5307cf3e6 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Tue, 26 May 2026 16:13:02 +0700 Subject: [PATCH 2/4] Fix --- src/ActiveQuery.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ActiveQuery.php b/src/ActiveQuery.php index b9b568ea6..0bcdc9f78 100644 --- a/src/ActiveQuery.php +++ b/src/ActiveQuery.php @@ -778,7 +778,7 @@ private function createInstance(): ActiveQueryInterface { return $this->model ->createQuery() - ->where($this->getWhere()) + ->setWhere($this->getWhere()) ->limit($this->getLimit()) ->offset($this->getOffset()) ->orderBy($this->getOrderBy()) From 6136c56ba8975d5856a213652a150ef86be23da4 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Tue, 26 May 2026 16:46:01 +0700 Subject: [PATCH 3/4] Change `false` to `null` by default --- src/AbstractActiveRecord.php | 10 +++++----- src/ActiveRecordInterface.php | 8 ++++---- src/Trait/RepositoryTrait.php | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/AbstractActiveRecord.php b/src/AbstractActiveRecord.php index d46e196a2..6ee393ab9 100644 --- a/src/AbstractActiveRecord.php +++ b/src/AbstractActiveRecord.php @@ -64,7 +64,7 @@ abstract class AbstractActiveRecord implements ActiveRecordInterface * @template T as ActiveRecordInterface * @template TModelClass as T|class-string|null * @psalm-param TModelClass $modelClass - * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), false> + * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), null> */ public function createQuery(ActiveRecordInterface|string|null $modelClass = null): ActiveQueryInterface { @@ -428,11 +428,11 @@ public function populateRelation(string $name, array|ActiveRecordInterface|null * @template T as ActiveRecordInterface * @template TModelClass as T|class-string|null * @psalm-param TModelClass $modelClass - * @psalm-return ActiveQuery<(TModelClass is null ? static : T), false> + * @psalm-return ActiveQuery<(TModelClass is null ? static : T), null> */ public static function query(ActiveRecordInterface|string|null $modelClass = null): ActiveQueryInterface { - /** @psalm-var ActiveQuery<(TModelClass is null ? static : T), false> */ + /** @psalm-var ActiveQuery<(TModelClass is null ? static : T), null> */ return new ActiveQuery($modelClass ?? static::class); } @@ -837,7 +837,7 @@ protected function retrieveRelation(string $name): ActiveRecordInterface|array|n * @template T as ActiveRecordInterface * @psalm-param T|class-string $modelClass * @psalm-param array $link - * @psalm-return ActiveQueryInterface + * @psalm-return ActiveQueryInterface * * @see AbstractActiveRecord::hasOne() * @see AbstractActiveRecord::hasMany() @@ -847,7 +847,7 @@ protected function createRelationQuery( array $link, bool $multiple, ): ActiveQueryInterface { - /** @psalm-var ActiveQueryInterface */ + /** @psalm-var ActiveQueryInterface */ return $this->createQuery($modelClass)->primaryModel($this)->link($link)->multiple($multiple); } diff --git a/src/ActiveRecordInterface.php b/src/ActiveRecordInterface.php index 3ad4ff392..fcfc5948e 100644 --- a/src/ActiveRecordInterface.php +++ b/src/ActiveRecordInterface.php @@ -44,7 +44,7 @@ public function column(string $propertyName): ColumnInterface; * @template T as ActiveRecordInterface * @template TModelClass as T|class-string|null * @psalm-param TModelClass $modelClass - * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), false> + * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), null> */ public function createQuery(self|string|null $modelClass = null): ActiveQueryInterface; @@ -304,7 +304,7 @@ public function hasProperty(string $name): bool; * @template T as ActiveRecordInterface * @psalm-param T|class-string $modelClass * @psalm-param array $link - * @psalm-return ActiveQueryInterface + * @psalm-return ActiveQueryInterface */ public function hasMany(self|string $modelClass, array $link): ActiveQueryInterface; @@ -343,7 +343,7 @@ public function hasMany(self|string $modelClass, array $link): ActiveQueryInterf * @template T as ActiveRecordInterface * @psalm-param T|class-string $modelClass * @psalm-param array $link - * @psalm-return ActiveQueryInterface + * @psalm-return ActiveQueryInterface */ public function hasOne(self|string $modelClass, array $link): ActiveQueryInterface; @@ -467,7 +467,7 @@ public function populateRelation(string $name, array|self|null $records): void; * @template T as ActiveRecordInterface * @template TModelClass as T|class-string|null * @psalm-param TModelClass $modelClass - * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), false> + * @psalm-return ActiveQueryInterface<(TModelClass is null ? static : T), null> */ public static function query(self|string|null $modelClass = null): ActiveQueryInterface; diff --git a/src/Trait/RepositoryTrait.php b/src/Trait/RepositoryTrait.php index 78ebc07f6..fb084b108 100644 --- a/src/Trait/RepositoryTrait.php +++ b/src/Trait/RepositoryTrait.php @@ -51,7 +51,7 @@ trait RepositoryTrait * No condition is applied if `null` (by default). * @param array $params The parameters to be bound to the SQL statement during execution. * - * @psalm-return ActiveQueryInterface + * @psalm-return ActiveQueryInterface */ public static function find(array|string|ExpressionInterface|null $condition = null, array $params = []): ActiveQueryInterface { @@ -206,7 +206,7 @@ public static function findByPkOrFail(array|float|int|string $values): array|Act * * @return ActiveQueryInterface The newly created {@see ActiveQueryInterface} instance. * - * @psalm-return ActiveQueryInterface + * @psalm-return ActiveQueryInterface */ public static function findBySql(string $sql, array $params = []): ActiveQueryInterface { From 13012a436a4eff42e3e9e98d738a64d92a2aa7da Mon Sep 17 00:00:00 2001 From: Tigrov Date: Tue, 26 May 2026 17:05:00 +0700 Subject: [PATCH 4/4] Revert changes in `createInstance()` --- src/ActiveQuery.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ActiveQuery.php b/src/ActiveQuery.php index 0bcdc9f78..ceb8e86d5 100644 --- a/src/ActiveQuery.php +++ b/src/ActiveQuery.php @@ -774,11 +774,11 @@ private function removeDuplicatedRows(array $rows): array return array_values(array_combine($hash, $rows)); } - private function createInstance(): ActiveQueryInterface + private function createInstance(): static { - return $this->model - ->createQuery() - ->setWhere($this->getWhere()) + /** @psalm-suppress UnsafeGenericInstantiation, InvalidTemplateParam */ + return (new static($this->model)) + ->where($this->getWhere()) ->limit($this->getLimit()) ->offset($this->getOffset()) ->orderBy($this->getOrderBy())