From 0d51f69e1ffcb4b71df53979c9ec92ff4cd212f6 Mon Sep 17 00:00:00 2001 From: Tigrov Date: Fri, 21 Jun 2024 18:48:44 +0700 Subject: [PATCH] Replace the factory with an instance or Closure --- src/AbstractActiveRecord.php | 3 +- src/ActiveQuery.php | 37 +++++++++++++------ src/ActiveQueryInterface.php | 2 +- tests/ActiveQueryTest.php | 29 +++++++++++++++ .../ActiveRecord/CustomerWithConstructor.php | 4 +- 5 files changed, 59 insertions(+), 16 deletions(-) diff --git a/src/AbstractActiveRecord.php b/src/AbstractActiveRecord.php index 0be18c184..3a59df9f3 100644 --- a/src/AbstractActiveRecord.php +++ b/src/AbstractActiveRecord.php @@ -48,7 +48,6 @@ abstract class AbstractActiveRecord implements ActiveRecordInterface public function __construct( private ConnectionInterface $db, - private ActiveRecordFactory|null $arFactory = null, private string $tableName = '' ) { } @@ -323,7 +322,7 @@ public function insert(array $attributes = null): bool */ public function instantiateQuery(string $arClass): ActiveQueryInterface { - return new ActiveQuery($arClass, $this->db, $this->arFactory); + return new ActiveQuery($arClass, $this->db); } /** diff --git a/src/ActiveQuery.php b/src/ActiveQuery.php index b68f9a808..3008a97ed 100644 --- a/src/ActiveQuery.php +++ b/src/ActiveQuery.php @@ -111,15 +111,13 @@ class ActiveQuery extends Query implements ActiveQueryInterface private string|null $sql = null; private array|string|null $on = null; private array $joinWith = []; - private ActiveRecordInterface|null $arInstance = null; /** - * @psalm-param class-string $arClass + * @psalm-param class-string|ActiveRecordInterface|Closure $arClass */ final public function __construct( - protected string $arClass, + protected string|ActiveRecordInterface|Closure $arClass, protected ConnectionInterface $db, - private ActiveRecordFactory|null $arFactory = null, private string $tableName = '' ) { parent::__construct($db); @@ -301,7 +299,7 @@ private function removeDuplicatedModels(array $models): array $pks = $this->getARInstance()->primaryKey(); if (empty($pks)) { - throw new InvalidConfigException("Primary key of '$this->arClass' can not be empty."); + throw new InvalidConfigException("Primary key of '{$this->getARClassName()}' can not be empty."); } foreach ($pks as $pk) { @@ -323,7 +321,7 @@ private function removeDuplicatedModels(array $models): array $pks = $model->getPrimaryKey(true); if (empty($pks)) { - throw new InvalidConfigException("Primary key of '$this->arClass' can not be empty."); + throw new InvalidConfigException("Primary key of '{$this->getARClassName()}' can not be empty."); } foreach ($pks as $pk) { @@ -803,7 +801,7 @@ public function orOnCondition(array|string $condition, array $params = []): self public function viaTable(string $tableName, array $link, callable $callable = null): self { - $arClass = $this->primaryModel ? $this->primaryModel::class : $this->arClass; + $arClass = $this->primaryModel ?? $this->arClass; $arClassInstance = new self($arClass, $this->db); /** @psalm-suppress UndefinedMethod */ @@ -882,7 +880,7 @@ public function getSql(): string|null return $this->sql; } - public function getARClass(): string|null + public function getARClass(): string|ActiveRecordInterface|Closure { return $this->arClass; } @@ -976,16 +974,33 @@ public function sql(string|null $value): self return $this; } + public function getARClassName(): string + { + if ($this->arClass instanceof ActiveRecordInterface) { + return $this->arClass::class; + } + + if ($this->arClass instanceof Closure) { + return ($this->arClass)()::class; + } + + return $this->arClass; + } + public function getARInstance(): ActiveRecordInterface { - if ($this->arFactory !== null) { - return $this->arFactory->createAR($this->arClass, $this->tableName, $this->db); + if ($this->arClass instanceof ActiveRecordInterface) { + return $this->arClass; + } + + if ($this->arClass instanceof Closure) { + return ($this->arClass)(); } /** @psalm-var class-string $class */ $class = $this->arClass; - return new $class($this->db, null, $this->tableName); + return new $class($this->db, $this->tableName); } private function createInstance(): static diff --git a/src/ActiveQueryInterface.php b/src/ActiveQueryInterface.php index e058256f9..7799cd14f 100644 --- a/src/ActiveQueryInterface.php +++ b/src/ActiveQueryInterface.php @@ -298,7 +298,7 @@ public function getTablesUsedInFrom(): array; */ public function getSql(): string|null; - public function getARClass(): string|null; + public function getARClass(): string|ActiveRecordInterface|Closure; /** * Creates an {@see ActiveQuery} instance with a given SQL statement. diff --git a/tests/ActiveQueryTest.php b/tests/ActiveQueryTest.php index 6d604d5af..8be1f17df 100644 --- a/tests/ActiveQueryTest.php +++ b/tests/ActiveQueryTest.php @@ -2664,4 +2664,33 @@ public function testEqual(): void $customerB = (new ActiveQuery(Item::class, $this->db))->findOne(1); $this->assertFalse($customerA->equals($customerB)); } + + public function testARClassAsString(): void + { + $query = new ActiveQuery(Customer::class, $this->db); + + $this->assertSame($query->getARClass(), Customer::class); + $this->assertSame($query->getARClassName(), Customer::class); + $this->assertInstanceOf(Customer::class, $query->getARInstance()); + } + + public function testARClassAsInstance(): void + { + $customer = new Customer($this->db); + $query = new ActiveQuery($customer, $this->db); + + $this->assertSame($query->getARClass(), $customer); + $this->assertSame($query->getARClassName(), Customer::class); + $this->assertInstanceOf(Customer::class, $query->getARInstance()); + } + + public function testARClassAsClosure(): void + { + $closure = fn () => new Customer($this->db); + $query = new ActiveQuery($closure, $this->db); + + $this->assertSame($query->getARClass(), $closure); + $this->assertSame($query->getARClassName(), Customer::class); + $this->assertInstanceOf(Customer::class, $query->getARInstance()); + } } diff --git a/tests/Stubs/ActiveRecord/CustomerWithConstructor.php b/tests/Stubs/ActiveRecord/CustomerWithConstructor.php index 29a310198..48f3e4e3a 100644 --- a/tests/Stubs/ActiveRecord/CustomerWithConstructor.php +++ b/tests/Stubs/ActiveRecord/CustomerWithConstructor.php @@ -23,9 +23,9 @@ final class CustomerWithConstructor extends ActiveRecord protected bool|string|null $bool_status = false; protected int|null $profile_id = null; - public function __construct(ConnectionInterface $db, private Aliases $aliases) + public function __construct(ConnectionInterface $db, string $tableName = '', private Aliases|null $aliases = null) { - parent::__construct($db); + parent::__construct($db, $tableName); } public function getTableName(): string