diff --git a/src/AbstractActiveRecord.php b/src/AbstractActiveRecord.php index 7433529fc..7bc696e02 100644 --- a/src/AbstractActiveRecord.php +++ b/src/AbstractActiveRecord.php @@ -49,8 +49,7 @@ abstract class AbstractActiveRecord implements ActiveRecordInterface private array $relationsDependencies = []; public function __construct( - private ConnectionInterface $db, - private string $tableName = '' + private ConnectionInterface $db ) { } @@ -1250,11 +1249,7 @@ protected function resetDependentRelations(string $attribute): void public function getTableName(): string { - if ($this->tableName === '') { - $this->tableName = '{{%' . DbStringHelper::pascalCaseToId(DbStringHelper::baseName(static::class)) . '}}'; - } - - return $this->tableName; + return '{{%' . DbStringHelper::pascalCaseToId(DbStringHelper::baseName(static::class)) . '}}'; } protected function db(): ConnectionInterface diff --git a/src/ActiveQuery.php b/src/ActiveQuery.php index 0b2a18567..7b678f019 100644 --- a/src/ActiveQuery.php +++ b/src/ActiveQuery.php @@ -119,8 +119,7 @@ class ActiveQuery extends Query implements ActiveQueryInterface */ final public function __construct( protected string|ActiveRecordInterface|Closure $arClass, - protected ConnectionInterface $db, - private string $tableName = '' + protected ConnectionInterface $db ) { parent::__construct($db); } @@ -1002,7 +1001,7 @@ public function getARInstance(): ActiveRecordInterface /** @psalm-var class-string $class */ $class = $this->arClass; - return new $class($this->db, $this->tableName); + return new $class($this->db); } private function createInstance(): static diff --git a/src/ActiveRecordFactory.php b/src/ActiveRecordFactory.php index 876487e7a..795e3b585 100644 --- a/src/ActiveRecordFactory.php +++ b/src/ActiveRecordFactory.php @@ -4,6 +4,7 @@ namespace Yiisoft\ActiveRecord; +use Closure; use Yiisoft\Db\Connection\ConnectionInterface; use Yiisoft\Definitions\Exception\CircularReferenceException; use Yiisoft\Definitions\Exception\InvalidConfigException; @@ -11,6 +12,9 @@ use Yiisoft\Factory\Factory; use Yiisoft\Factory\NotFoundException; +/** + * @psalm-import-type ARClass from ActiveQueryInterface + */ final class ActiveRecordFactory { public function __construct(private Factory $factory) @@ -21,8 +25,6 @@ public function __construct(private Factory $factory) * Allows you to create an active record instance through the factory. * * @param string $arClass active record class. - * @param string $tableName The name of the table associated with this ActiveRecord class, if its empty string the - * name will be generated automatically by calling {@see getTableName()} in the active record class. * @param ConnectionInterface|null $db the database connection used for creating active record instances. * * @throws CircularReferenceException @@ -37,16 +39,11 @@ public function __construct(private Factory $factory) */ public function createAR( string $arClass, - string $tableName = '', ConnectionInterface $db = null ): ActiveRecordInterface { $params = []; $params['class'] = $arClass; - if ($tableName !== '') { - $params['__construct()']['tableName'] = $tableName; - } - if ($db !== null) { $params['__construct()']['db'] = $db; } @@ -57,9 +54,8 @@ public function createAR( /** * Allows you to create an active query instance through the factory. * - * @param string $arClass active record class. - * @param string $tableName The name of the table associated with this ActiveRecord class, if its empty string the - * name will be generated automatically by calling {@see getTableName()} in the active record class. + * @param ActiveRecordInterface|Closure|string $arClass the active record class, active record instance or closure + * returning active record instance. * @param string $queryClass custom query active query class. * @param ConnectionInterface|null $db the database connection used for creating active query instances. * @@ -67,10 +63,11 @@ public function createAR( * @throws InvalidConfigException * @throws NotFoundException * @throws NotInstantiableException + * + * @psalm-param ARClass $arClass */ public function createQueryTo( - string $arClass, - string $tableName = '', + string|ActiveRecordInterface|Closure $arClass, string $queryClass = ActiveQuery::class, ConnectionInterface $db = null ): ActiveQueryInterface { @@ -81,10 +78,6 @@ public function createQueryTo( ], ]; - if ($tableName !== '') { - $params['__construct()']['tableName'] = $tableName; - } - if ($db !== null) { $params['__construct()']['db'] = $db; } diff --git a/src/Trait/CustomTableNameTrait.php b/src/Trait/CustomTableNameTrait.php new file mode 100644 index 000000000..3a752a171 --- /dev/null +++ b/src/Trait/CustomTableNameTrait.php @@ -0,0 +1,30 @@ +tableName = $tableName; + return $new; + } + + public function getTableName(): string + { + return $this->tableName ??= parent::getTableName(); + } +} diff --git a/tests/ActiveQueryTest.php b/tests/ActiveQueryTest.php index 84174f5f4..a9fb46a96 100644 --- a/tests/ActiveQueryTest.php +++ b/tests/ActiveQueryTest.php @@ -1851,8 +1851,17 @@ public function testRelationWhereParams(string $orderTableName, string $orderIte $this->checkFixture($this->db, 'order'); - $order = new Order(db: $this->db, tableName: $orderTableName); - $orderItem = new OrderItem(db: $this->db, tableName: $orderItemTableName); + $order = new Order($this->db); + $orderItem = new OrderItem($this->db); + + $this->assertSame('order', $order->getTableName()); + $this->assertSame('order_item', $orderItem->getTableName()); + + $order = $order->withTableName($orderTableName); + $orderItem = $orderItem->withTableName($orderItemTableName); + + $this->assertSame($orderTableName, $order->getTableName()); + $this->assertSame($orderItemTableName, $orderItem->getTableName()); $orderQuery = new ActiveQuery(Order::class, $this->db); $order = $orderQuery->findOne(1); diff --git a/tests/ActiveRecordFactoryTest.php b/tests/ActiveRecordFactoryTest.php index 59ed3f938..11399df8b 100644 --- a/tests/ActiveRecordFactoryTest.php +++ b/tests/ActiveRecordFactoryTest.php @@ -6,6 +6,7 @@ use Yiisoft\ActiveRecord\ActiveQuery; use Yiisoft\ActiveRecord\ActiveRecordFactory; +use Yiisoft\ActiveRecord\ActiveRecordInterface; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\ArrayAndJsonTypes; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerQuery; @@ -33,11 +34,15 @@ public function testCreateARWithConnection(): void public function testCreateARWithTableName(): void { - $customerAR = $this->arFactory->createAR(ArrayAndJsonTypes::class, 'array_and_json_types'); - $tableName = $customerAR->getTableName(); + $model = $this->arFactory->createAR(ArrayAndJsonTypes::class); - $this->assertSame('array_and_json_types', $tableName); - $this->assertInstanceOf(ArrayAndJsonTypes::class, $customerAR); + $this->assertSame('{{%array_and_json_types}}', $model->getTableName()); + $this->assertInstanceOf(ArrayAndJsonTypes::class, $model); + + $model = $model->withTableName('array_and_json_types'); + + $this->assertSame('array_and_json_types', $model->getTableName()); + $this->assertInstanceOf(ArrayAndJsonTypes::class, $model); } public function testCreateQueryTo(): void @@ -70,14 +75,15 @@ public function testCreateQueryToWithConnection(): void public function testCreateQueryToWithTableName(): void { /** example create active query */ - $customerQuery = $this->arFactory->createQueryTo( - arClass: ArrayAndJsonTypes::class, - tableName: 'array_and_json_types', + $modelQuery = $this->arFactory->createQueryTo( + arClass: fn (): ActiveRecordInterface => $this->arFactory + ->createAR(ArrayAndJsonTypes::class) + ->withTableName('array_and_json_types'), ); - $tableName = $customerQuery->getARInstance()->getTableName(); + $tableName = $modelQuery->getARInstance()->getTableName(); $this->assertSame('array_and_json_types', $tableName); - $this->assertInstanceOf(ActiveQuery::class, $customerQuery); + $this->assertInstanceOf(ActiveQuery::class, $modelQuery); } public function testGetArInstanceWithConstructor(): void diff --git a/tests/Stubs/ActiveRecord/ArrayAndJsonTypes.php b/tests/Stubs/ActiveRecord/ArrayAndJsonTypes.php index 7cdcfc7ea..080f1f0e8 100644 --- a/tests/Stubs/ActiveRecord/ArrayAndJsonTypes.php +++ b/tests/Stubs/ActiveRecord/ArrayAndJsonTypes.php @@ -5,12 +5,15 @@ namespace Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord; +use Yiisoft\ActiveRecord\Trait\CustomTableNameTrait; use Yiisoft\Db\Expression\ArrayExpression; use Yiisoft\Db\Expression\Expression; use Yiisoft\Db\Expression\JsonExpression; final class ArrayAndJsonTypes extends ActiveRecord { + use CustomTableNameTrait; + public int $id; public array|ArrayExpression|null $intarray_col = null; public array|ArrayExpression|null $textarray2_col = null; diff --git a/tests/Stubs/ActiveRecord/CustomerWithConstructor.php b/tests/Stubs/ActiveRecord/CustomerWithConstructor.php index 48f3e4e3a..90de7bb58 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, string $tableName = '', private Aliases|null $aliases = null) + public function __construct(ConnectionInterface $db, private Aliases|null $aliases = null) { - parent::__construct($db, $tableName); + parent::__construct($db); } public function getTableName(): string diff --git a/tests/Stubs/ActiveRecord/Order.php b/tests/Stubs/ActiveRecord/Order.php index 83494c81d..ae3518977 100644 --- a/tests/Stubs/ActiveRecord/Order.php +++ b/tests/Stubs/ActiveRecord/Order.php @@ -7,12 +7,15 @@ use Yiisoft\ActiveRecord\ActiveQuery; use Yiisoft\ActiveRecord\ActiveQueryInterface; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord; +use Yiisoft\ActiveRecord\Trait\CustomTableNameTrait; /** * Class Order. */ class Order extends ActiveRecord { + use CustomTableNameTrait; + public const TABLE_NAME = 'order'; protected int|null $id; @@ -24,7 +27,7 @@ class Order extends ActiveRecord public function getTableName(): string { - return self::TABLE_NAME; + return $this->tableName ??= self::TABLE_NAME; } public function getId(): int|null diff --git a/tests/Stubs/ActiveRecord/OrderItem.php b/tests/Stubs/ActiveRecord/OrderItem.php index 3c25586a7..5560d75fb 100644 --- a/tests/Stubs/ActiveRecord/OrderItem.php +++ b/tests/Stubs/ActiveRecord/OrderItem.php @@ -7,12 +7,15 @@ use Yiisoft\ActiveRecord\ActiveQuery; use Yiisoft\ActiveRecord\ActiveQueryInterface; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord; +use Yiisoft\ActiveRecord\Trait\CustomTableNameTrait; /** * Class OrderItem. */ final class OrderItem extends ActiveRecord { + use CustomTableNameTrait; + protected int $order_id; protected int $item_id; protected int $quantity; @@ -20,7 +23,7 @@ final class OrderItem extends ActiveRecord public function getTableName(): string { - return 'order_item'; + return $this->tableName ??= 'order_item'; } public function fields(): array