diff --git a/src/BaseActiveRecord.php b/src/BaseActiveRecord.php index bdbdd4d1d..f4e9cee8c 100644 --- a/src/BaseActiveRecord.php +++ b/src/BaseActiveRecord.php @@ -658,13 +658,7 @@ public function save(array $attributeNames = null): bool public function setAttribute(string $name, mixed $value): void { if ($this->hasAttribute($name)) { - if ( - !empty($this->relationsDependencies[$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 . '".'); } @@ -1281,4 +1275,19 @@ public function toArray(): array } return $data; } + + /** + * Sets the named attribute value without checking if the attribute exists. + */ + protected function setAttributeInternal(string $name, mixed $value): void + { + if ( + !empty($this->relationsDependencies[$name]) + && ($value === null || $value !== ($this->attributes[$name] ?? null)) + ) { + $this->resetDependentRelations($name); + } + + $this->attributes[$name] = $value; + } } diff --git a/src/BaseActiveRecordTrait.php b/src/BaseActiveRecordTrait.php index c5061b1ac..9d917aabb 100644 --- a/src/BaseActiveRecordTrait.php +++ b/src/BaseActiveRecordTrait.php @@ -44,12 +44,8 @@ trait BaseActiveRecordTrait */ public function __get(string $name) { - if (isset($this->attributes[$name]) || array_key_exists($name, $this->attributes)) { - return $this->attributes[$name]; - } - if ($this->hasAttribute($name)) { - return null; + return $this->getAttribute($name); } if (isset($this->related[$name]) || array_key_exists($name, $this->related)) { @@ -171,10 +167,7 @@ public function __isset(string $name): bool public function __unset(string $name): void { if ($this->hasAttribute($name)) { - unset($this->attributes[$name]); - if (!empty($this->relationsDependencies[$name])) { - $this->resetDependentRelations($name); - } + $this->setAttributeInternal($name, null); } elseif (array_key_exists($name, $this->related)) { unset($this->related[$name]); } @@ -193,13 +186,8 @@ public function __unset(string $name): void public function __set(string $name, mixed $value): void { if ($this->hasAttribute($name)) { - if ( - !empty($this->relationsDependencies[$name]) - && (!array_key_exists($name, $this->attributes) || $this->attributes[$name] !== $value) - ) { - $this->resetDependentRelations($name); - } - $this->attributes[$name] = $value; + $this->setAttributeInternal($name, $value); + return; } if (method_exists($this, 'get' . ucfirst($name))) { diff --git a/tests/ActiveRecordTest.php b/tests/ActiveRecordTest.php index 4d054d29e..078331dcc 100644 --- a/tests/ActiveRecordTest.php +++ b/tests/ActiveRecordTest.php @@ -10,6 +10,7 @@ use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Cat; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Customer; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerClosureField; +use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerExtraAttributes; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\CustomerWithAlias; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Dog; use Yiisoft\ActiveRecord\Tests\Stubs\ActiveRecord\Item; @@ -763,4 +764,14 @@ public function testToArrayWithClosure(): void $customer->toArray(), ); } + + public function testGetExtraArrtibute() + { + $this->checkFixture($this->db, 'customer'); + + $customerQuery = new ActiveQuery(CustomerExtraAttributes::class, $this->db); + $customer = $customerQuery->findOne(1); + + $this->assertSame($customer->sex, 'm'); + } } diff --git a/tests/Stubs/ActiveRecord/CustomerExtraAttributes.php b/tests/Stubs/ActiveRecord/CustomerExtraAttributes.php new file mode 100644 index 000000000..44de67406 --- /dev/null +++ b/tests/Stubs/ActiveRecord/CustomerExtraAttributes.php @@ -0,0 +1,48 @@ + 'm', + ]; + + public function getTableName(): string + { + return 'customer'; + } + + public function getAttribute(string $name): mixed + { + if (array_key_exists($name, $this->extraAttributes)) { + return $this->extraAttributes[$name]; + } + + return parent::getAttribute($name); + } + + public function getAttributes(array $names = null, array $except = []): array + { + return array_merge(parent::getAttributes($names, $except), $this->extraAttributes); + } + + public function hasAttribute($name): bool + { + return array_key_exists($name, $this->extraAttributes) || parent::hasAttribute($name); + } +}