diff --git a/src/Trait/MagicRelationsTrait.php b/src/Trait/MagicRelationsTrait.php index 86ae03247..abc92f58b 100644 --- a/src/Trait/MagicRelationsTrait.php +++ b/src/Trait/MagicRelationsTrait.php @@ -10,15 +10,19 @@ use Yiisoft\ActiveRecord\ActiveRecordInterface; use Yiisoft\Db\Exception\InvalidArgumentException; +use function get_class_methods; use function is_a; use function lcfirst; use function method_exists; +use function str_ends_with; +use function str_starts_with; use function substr; use function ucfirst; /** * Trait to define {@see ActiveRecordInterface::relationQuery()} method to access relation queries of an ActiveRecord - * instance. + * instance. Also, it defines {@see ActiveRecordInterface::relationNames()} method to get names of all relations + * defined in the ActiveRecord class. */ trait MagicRelationsTrait { @@ -75,4 +79,36 @@ public function relationQuery(string $name): ActiveQueryInterface return $this->$getter(); } + + /** + * Returns names of all relations defined in the ActiveRecord class using getter methods with `get` prefix and + * `Query` suffix. + * + * @throws ReflectionException + * @return string[] + */ + public function relationNames(): array + { + $methods = get_class_methods($this); + + $relations = []; + + foreach ($methods as $method) { + if (str_starts_with($method, 'get') && str_ends_with($method, 'Query')) { + $reflection = new ReflectionMethod($this, $method); + $type = $reflection->getReturnType(); + + if ( + $type === null + || !is_a('\\' . $type->getName(), ActiveQueryInterface::class, true) + ) { + continue; + } + + $relations[] = lcfirst(substr($method, 3, -5)); + } + } + + return $relations; + } } diff --git a/tests/MagicActiveRecordTest.php b/tests/MagicActiveRecordTest.php index daa91778a..64a2eee1d 100644 --- a/tests/MagicActiveRecordTest.php +++ b/tests/MagicActiveRecordTest.php @@ -7,6 +7,7 @@ use DivisionByZeroError; use ReflectionException; use Yiisoft\ActiveRecord\ActiveQuery; +use Yiisoft\ActiveRecord\Tests\Stubs\MagicActiveRecord\Alpha; use Yiisoft\ActiveRecord\Tests\Stubs\MagicActiveRecord\Animal; use Yiisoft\ActiveRecord\Tests\Stubs\MagicActiveRecord\Cat; use Yiisoft\ActiveRecord\Tests\Stubs\MagicActiveRecord\Customer; @@ -948,4 +949,34 @@ public function testGetDirtyAttributesWithProperties(): void $customer->getDirtyAttributes(['id', 'email', 'address', 'unknown']), ); } + + public function testRelationNames(): void + { + $this->checkFixture($this->db(), 'animal'); + + $animal = new Animal(); + + $this->assertEmpty($animal->relationNames()); + + $alpha = new Alpha(); + + $this->assertSame(['betas'], $alpha->relationNames()); + + $customer = new Customer(); + + $this->assertSame([ + 'profile', + 'ordersPlain', + 'orders', + 'ordersNoOrder', + 'expensiveOrders', + 'ordersWithItems', + 'expensiveOrdersWithNullFK', + 'ordersWithNullFK', + 'orders2', + 'orderItems', + 'orderItems2', + 'items2', + ], $customer->relationNames()); + } }