Skip to content

Commit 8c1b480

Browse files
committed
refactor: Optional DataCaster creation in Entity
1 parent f96cc88 commit 8c1b480

3 files changed

Lines changed: 78 additions & 11 deletions

File tree

system/Entity/Entity.php

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ class Entity implements JsonSerializable
127127
/**
128128
* The data caster.
129129
*/
130-
protected DataCaster $dataCaster;
130+
protected ?DataCaster $dataCaster = null;
131131

132132
/**
133133
* Holds info whenever properties have to be casted.
@@ -146,12 +146,7 @@ class Entity implements JsonSerializable
146146
*/
147147
public function __construct(?array $data = null)
148148
{
149-
$this->dataCaster = new DataCaster(
150-
array_merge($this->defaultCastHandlers, $this->castHandlers),
151-
null,
152-
null,
153-
false,
154-
);
149+
$this->dataCaster = $this->dataCaster();
155150

156151
$this->syncOriginal();
157152

@@ -568,10 +563,37 @@ protected function mutateDate($value)
568563
*/
569564
protected function castAs($value, string $attribute, string $method = 'get')
570565
{
571-
return $this->dataCaster
572-
// @TODO if $casts is readonly, we don't need the setTypes() method.
573-
->setTypes($this->casts)
574-
->castAs($value, $attribute, $method);
566+
if ($this->dataCaster() instanceof DataCaster) {
567+
return $this->dataCaster
568+
// @TODO if $casts is readonly, we don't need the setTypes() method.
569+
->setTypes($this->casts)
570+
->castAs($value, $attribute, $method);
571+
}
572+
573+
return $value;
574+
}
575+
576+
/**
577+
* This method allows you to refuse to contain an unnecessary DataCaster if you do not use casting.
578+
*/
579+
protected function dataCaster(): ?DataCaster
580+
{
581+
if (! $this->_cast) {
582+
$this->dataCaster = null;
583+
584+
return null;
585+
}
586+
587+
if (! $this->dataCaster instanceof DataCaster) {
588+
$this->dataCaster = new DataCaster(
589+
array_merge($this->defaultCastHandlers, $this->castHandlers),
590+
null,
591+
null,
592+
false,
593+
);
594+
}
595+
596+
return $this->dataCaster;
575597
}
576598

577599
/**
@@ -598,6 +620,9 @@ public function cast(?bool $cast = null)
598620

599621
$this->_cast = $cast;
600622

623+
// Synchronize option with DataCaster initialization
624+
$this->dataCaster();
625+
601626
return $this;
602627
}
603628

tests/system/Entity/EntityTest.php

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use ArrayIterator;
1717
use ArrayObject;
1818
use Closure;
19+
use CodeIgniter\DataCaster\DataCaster;
1920
use CodeIgniter\Entity\Exceptions\CastException;
2021
use CodeIgniter\HTTP\URI;
2122
use CodeIgniter\I18n\Time;
@@ -1485,6 +1486,39 @@ public function testJsonSerializableEntity(): void
14851486
$this->assertSame(json_encode($entity->toArray()), json_encode($entity));
14861487
}
14871488

1489+
public function testDataCasterInit(): void
1490+
{
1491+
$entity = new class () extends Entity {
1492+
protected $attributes = [
1493+
'first' => '12345',
1494+
];
1495+
protected $casts = [
1496+
'first' => 'integer',
1497+
];
1498+
};
1499+
1500+
$getDataCaster = $this->getPrivateMethodInvoker($entity, 'dataCaster');
1501+
1502+
$this->assertInstanceOf(DataCaster::class, $getDataCaster());
1503+
$this->assertInstanceOf(DataCaster::class, $this->getPrivateProperty($entity, 'dataCaster'));
1504+
$this->assertSame(12345, $entity->first);
1505+
1506+
// Disable casting, do not load DataCaster
1507+
$entity->cast(false);
1508+
$this->assertNull($getDataCaster());
1509+
$this->assertNull($this->getPrivateProperty($entity, 'dataCaster'));
1510+
$this->assertIsString($entity->first);
1511+
1512+
// Method castAs() depends on the $_cast option
1513+
$this->assertSame('12345', $this->getPrivateMethodInvoker($entity, 'castAs')('12345', 'first'));
1514+
1515+
// Restore casting
1516+
$entity->cast(true);
1517+
$this->assertInstanceOf(DataCaster::class, $getDataCaster());
1518+
$this->assertInstanceOf(DataCaster::class, $this->getPrivateProperty($entity, 'dataCaster'));
1519+
$this->assertSame(12345, $entity->first);
1520+
}
1521+
14881522
private function getEntity(): object
14891523
{
14901524
return new class () extends Entity {

user_guide_src/source/changelogs/v4.7.0.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,13 @@ parameter is ``true``. Previously, properties containing arrays were not recursi
111111
If you were relying on the old behavior where arrays remained unconverted, you will need to update
112112
your code.
113113

114+
Entity and DataCaster
115+
---------------------
116+
117+
Previously, the ``DataCaster`` object was always initialized, even if you did not use the ``$_cast = false`` type casting.
118+
Now, the object is created on-demand and deleted when type casting is disabled.
119+
In general, the change does not break the existing process, it should be remembered that now in some cases ``$dataCaster`` may be nullable.
120+
114121
Encryption Handlers
115122
-------------------
116123

@@ -302,6 +309,7 @@ Changes
302309
*******
303310

304311
- **Cookie:** The ``CookieInterface::EXPIRES_FORMAT`` has been changed to ``D, d M Y H:i:s T`` to follow the recommended format in RFC 7231.
312+
- **Entity:** The protected property ``CodeIgniter\Entity\Entity::$dataCaster`` can be nullable.
305313
- **Format:** Added support for configuring ``json_encode()`` maximum depth via ``Config\Format::$jsonEncodeDepth``.
306314
- **Paths:** Added support for changing the location of the ``.env`` file via the ``Paths::$envDirectory`` property.
307315
- **Toolbar:** Added ``$disableOnHeaders`` property to **app/Config/Toolbar.php**.

0 commit comments

Comments
 (0)