From 13c782f851932bf22d815060990d178f30482bcf Mon Sep 17 00:00:00 2001 From: Sergei Tigrov Date: Sun, 19 May 2024 21:32:30 +0700 Subject: [PATCH] Create `MagicRelationsTrait` (#317) --- src/ActiveRecord.php | 2 + src/BaseActiveRecordTrait.php | 64 ------------------------- src/Trait/MagicRelationsTrait.php | 79 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 64 deletions(-) create mode 100644 src/Trait/MagicRelationsTrait.php diff --git a/src/ActiveRecord.php b/src/ActiveRecord.php index 901a5f8f5..8150debe0 100644 --- a/src/ActiveRecord.php +++ b/src/ActiveRecord.php @@ -10,6 +10,7 @@ use Yiisoft\ActiveRecord\Trait\ArrayableTrait; use Yiisoft\ActiveRecord\Trait\ArrayAccessTrait; use Yiisoft\ActiveRecord\Trait\ArrayIteratorTrait; +use Yiisoft\ActiveRecord\Trait\MagicRelationsTrait; use Yiisoft\Arrays\ArrayableInterface; use Yiisoft\Db\Exception\Exception; use Yiisoft\Db\Exception\InvalidArgumentException; @@ -95,6 +96,7 @@ class ActiveRecord extends BaseActiveRecord implements ArrayableInterface, Array use ArrayableTrait; use ArrayAccessTrait; use ArrayIteratorTrait; + use MagicRelationsTrait; /** * The insert operation. This is mainly used when overriding {@see transactions()} to specify which operations are diff --git a/src/BaseActiveRecordTrait.php b/src/BaseActiveRecordTrait.php index f727847a9..d29e0e94e 100644 --- a/src/BaseActiveRecordTrait.php +++ b/src/BaseActiveRecordTrait.php @@ -4,10 +4,8 @@ namespace Yiisoft\ActiveRecord; -use Error; use Exception; use ReflectionException; -use ReflectionMethod; use Throwable; use Yiisoft\Db\Exception\InvalidArgumentException; use Yiisoft\Db\Exception\InvalidCallException; @@ -15,10 +13,8 @@ use Yiisoft\Db\Exception\UnknownPropertyException; use function array_key_exists; -use function lcfirst; use function method_exists; use function property_exists; -use function substr; use function ucfirst; trait BaseActiveRecordTrait @@ -80,66 +76,6 @@ public function checkRelation(string $name): mixed throw new UnknownPropertyException('Getting unknown property: ' . static::class . '::' . $name); } - /** - * Returns the relation object with the specified name. - * - * A relation is defined by a getter method which returns an {@see ActiveQueryInterface} object. - * - * It can be declared in either the Active Record class itself or one of its behaviors. - * - * @param string $name the relation name, e.g. `orders` for a relation defined via `getOrders()` method - * (case-sensitive). - * @param bool $throwException whether to throw exception if the relation does not exist. - * - * @throws InvalidArgumentException if the named relation does not exist. - * @throws ReflectionException - * - * @return ActiveQueryInterface|null the relational query object. If the relation does not exist and - * `$throwException` is `false`, `null` will be returned. - */ - public function getRelation(string $name, bool $throwException = true): ActiveQueryInterface|null - { - $getter = 'get' . ucfirst($name); - - try { - /** the relation could be defined in a behavior */ - $relation = $this->$getter(); - } catch (Error) { - if ($throwException) { - throw new InvalidArgumentException(static::class . ' has no relation named "' . $name . '".'); - } - - return null; - } - - if (!$relation instanceof ActiveQueryInterface) { - if ($throwException) { - throw new InvalidArgumentException(static::class . ' has no relation named "' . $name . '".'); - } - - return null; - } - - if (method_exists($this, $getter)) { - /** relation name is case sensitive, trying to validate it when the relation is defined within this class */ - $method = new ReflectionMethod($this, $getter); - $realName = lcfirst(substr($method->getName(), 3)); - - if ($realName !== $name) { - if ($throwException) { - throw new InvalidArgumentException( - 'Relation names are case sensitive. ' . static::class - . " has a relation named \"$realName\" instead of \"$name\"." - ); - } - - return null; - } - } - - return $relation; - } - /** * Checks if a property value is null. * diff --git a/src/Trait/MagicRelationsTrait.php b/src/Trait/MagicRelationsTrait.php new file mode 100644 index 000000000..649693e7d --- /dev/null +++ b/src/Trait/MagicRelationsTrait.php @@ -0,0 +1,79 @@ +$getter(); + } catch (Error) { + if ($throwException) { + throw new InvalidArgumentException(static::class . ' has no relation named "' . $name . '".'); + } + + return null; + } + + if (!$relation instanceof ActiveQueryInterface) { + if ($throwException) { + throw new InvalidArgumentException(static::class . ' has no relation named "' . $name . '".'); + } + + return null; + } + + if (method_exists($this, $getter)) { + /** relation name is case sensitive, trying to validate it when the relation is defined within this class */ + $method = new ReflectionMethod($this, $getter); + $realName = lcfirst(substr($method->getName(), 3)); + + if ($realName !== $name) { + if ($throwException) { + throw new InvalidArgumentException( + 'Relation names are case sensitive. ' . static::class + . " has a relation named \"$realName\" instead of \"$name\"." + ); + } + + return null; + } + } + + return $relation; + } +}