diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 5220ae5b0aa8..ffb693cae467 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -456,11 +456,19 @@ public function __set(string $key, $value = null) $value = $this->castAs($value, $key, 'set'); - // if a set* method exists for this key, use that method to + // if a setter method exists for this key, use that method to // insert this value. should be outside $isNullable check, // so maybe wants to do sth with null value automatically $method = 'set' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $key))); + // If a "`_set` + $key" method exists, it is a setter. + if (method_exists($this, '_' . $method)) { + $this->{'_' . $method}($value); + + return $this; + } + + // If a "`set` + $key" method exists, it is also a setter. if (method_exists($this, $method) && $method !== 'setAttributes') { $this->{$method}($value); @@ -499,9 +507,13 @@ public function __get(string $key) // Convert to CamelCase for the method $method = 'get' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $key))); - // if a get* method exists for this key, + // if a getter method exists for this key, // use that method to insert this value. - if (method_exists($this, $method)) { + if (method_exists($this, '_' . $method)) { + // If a "`_get` + $key" method exists, it is a getter. + $result = $this->{'_' . $method}(); + } elseif (method_exists($this, $method)) { + // If a "`get` + $key" method exists, it is also a getter. $result = $this->{$method}(); } diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 79aeb53f3199..41192e3f9805 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -82,6 +82,19 @@ public function testGetterSetters() $this->assertSame('bar:thanks:bar', $entity->bar); } + public function testNewGetterSetters() + { + $entity = $this->getNewSetterGetterEntity(); + + $entity->bar = 'thanks'; + + $this->assertSame('bar:thanks:bar', $entity->bar); + + $entity->setBar('BAR'); + + $this->assertSame('BAR', $entity->getBar()); + } + public function testUnsetUnsetsAttribute() { $entity = $this->getEntity(); @@ -1096,6 +1109,52 @@ public function getFakeBar() }; } + protected function getNewSetterGetterEntity() + { + return new class () extends Entity { + protected $attributes = [ + 'foo' => null, + 'bar' => null, + 'default' => 'sumfin', + 'created_at' => null, + ]; + protected $original = [ + 'foo' => null, + 'bar' => null, + 'default' => 'sumfin', + 'created_at' => null, + ]; + protected $datamap = [ + 'createdAt' => 'created_at', + ]; + private string $bar; + + public function setBar($value) + { + $this->bar = $value; + + return $this; + } + + public function getBar() + { + return $this->bar; + } + + public function _setBar($value) + { + $this->attributes['bar'] = "bar:{$value}"; + + return $this; + } + + public function _getBar() + { + return "{$this->attributes['bar']}:bar"; + } + }; + } + protected function getMappedEntity() { return new class () extends Entity { diff --git a/user_guide_src/source/changelogs/v4.4.0.rst b/user_guide_src/source/changelogs/v4.4.0.rst index 24ef1efc1707..19663e6b524d 100644 --- a/user_guide_src/source/changelogs/v4.4.0.rst +++ b/user_guide_src/source/changelogs/v4.4.0.rst @@ -65,6 +65,9 @@ Others Model ===== +- Added special getter/setter to Entity to avoid method name conflicts. + See :ref:`entities-special-getter-setter`. + Libraries ========= diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index df625dd73833..b93777ea125e 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -131,6 +131,25 @@ business logic and create objects that are pleasant to use. .. literalinclude:: entities/007.php +.. _entities-special-getter-setter: + +Special Getter/Setter +--------------------- + +.. versionadded:: 4.4.0 + +For example, if your Entity's parent class already has a ``getParent()`` method +defined, and your Entity also has a column named ``parent``, when you try to add +business logic to the ``getParent()`` method in your Entity class, the method is +already defined. + +In such a case, you can use the special getter/setter. Instead of ``getX()``/``setX()``, +set ``_getX()``/``_setX()``. + +In the above example, if your Entity has the ``_getParent()`` method, the method +will be used when you get ``$entity->parent``, and the ``_setParent()`` method +will be used when you set ``$entity->parent``. + Data Mapping ============