diff --git a/src/Trait/MagicPropertiesTrait.php b/src/Trait/MagicPropertiesTrait.php index df2d854f3..c6cd58bda 100644 --- a/src/Trait/MagicPropertiesTrait.php +++ b/src/Trait/MagicPropertiesTrait.php @@ -28,6 +28,12 @@ /** * Trait to define magic methods to access values of an ActiveRecord instance. * + * @method array getOldAttributes() + * @see AbstractActiveRecord::getOldAttributes() + * + * @method mixed getOldAttribute(string $name) + * @see AbstractActiveRecord::getOldAttribute() + * * @method array getRelatedRecords() * @see AbstractActiveRecord::getRelatedRecords() * @@ -122,6 +128,10 @@ public function __unset(string $name): void if ($this->hasAttribute($name)) { unset($this->attributes[$name]); + if (property_exists($this, $name)) { + $this->$name = null; + } + if ($this->hasDependentRelations($name)) { $this->resetDependentRelations($name); } @@ -142,14 +152,7 @@ public function __unset(string $name): void public function __set(string $name, mixed $value): void { if ($this->hasAttribute($name)) { - if ( - $this->hasDependentRelations($name) - && (!array_key_exists($name, $this->attributes) || $this->attributes[$name] !== $value) - ) { - $this->resetDependentRelations($name); - } - - $this->attributes[$name] = $value; + $this->setAttributeInternal($name, $value); return; } @@ -170,6 +173,10 @@ public function __set(string $name, mixed $value): void public function getAttribute(string $name): mixed { + if (property_exists($this, $name)) { + return get_object_vars($this)[$name] ?? null; + } + return $this->attributes[$name] ?? null; } @@ -192,37 +199,31 @@ public function hasAttribute(string $name): bool public function isAttributeChanged(string $name, bool $identical = true): bool { - if (isset($this->attributes[$name], $this->oldAttributes[$name])) { - return $this->attributes[$name] !== $this->oldAttributes[$name]; + $hasOldAttribute = array_key_exists($name, $this->getOldAttributes()); + + if (!$hasOldAttribute) { + return property_exists($this, $name) && array_key_exists($name, get_object_vars($this)) + || array_key_exists($name, $this->attributes); } - return isset($this->attributes[$name]) || isset($this->oldAttributes[$name]); + if (property_exists($this, $name)) { + return !array_key_exists($name, get_object_vars($this)) + || $this->getOldAttribute($name) !== $this->$name; + } + + return !array_key_exists($name, $this->attributes) + || $this->getOldAttribute($name) !== $this->attributes[$name]; } public function setAttribute(string $name, mixed $value): void { if ($this->hasAttribute($name)) { - if ( - $this->hasDependentRelations($name) - && (!array_key_exists($name, $this->attributes) || $this->attributes[$name] !== $value) - ) { - $this->resetDependentRelations($name); - } - $this->attributes[$name] = $value; + $this->setAttributeInternal($name, $value); } else { throw new InvalidArgumentException(static::class . ' has no attribute named "' . $name . '".'); } } - protected function populateAttribute(string $name, mixed $value): void - { - if (property_exists($this, $name)) { - $this->$name = $value; - } else { - $this->attributes[$name] = $value; - } - } - /** * Returns a value indicating whether a property is defined for this component. * @@ -263,4 +264,24 @@ public function canSetProperty(string $name, bool $checkVars = true): bool || ($checkVars && property_exists($this, $name)) || $this->hasAttribute($name); } + + protected function populateAttribute(string $name, mixed $value): void + { + if (property_exists($this, $name)) { + $this->$name = $value; + } else { + $this->attributes[$name] = $value; + } + } + + private function setAttributeInternal(string $name, mixed $value): void + { + if ($this->hasDependentRelations($name) + && ($value === null || $this->getAttribute($name) !== $value) + ) { + $this->resetDependentRelations($name); + } + + $this->populateAttribute($name, $value); + } }