Skip to content

Commit 0d112cf

Browse files
committed
handle native SPL iterators
1 parent 0296b72 commit 0d112cf

File tree

2 files changed

+54
-5
lines changed

2 files changed

+54
-5
lines changed

system/Entity/Entity.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
use Exception;
3636
use JsonSerializable;
3737
use ReturnTypeWillChange;
38+
use Traversable;
3839
use UnitEnum;
3940

4041
/**
@@ -370,16 +371,18 @@ private function normalizeValue(mixed $data): mixed
370371
$objectData = $data->jsonSerialize();
371372
} elseif (method_exists($data, 'toArray')) {
372373
$objectData = $data->toArray();
374+
} elseif ($data instanceof Traversable) {
375+
$objectData = iterator_to_array($data);
376+
} elseif ($data instanceof DateTimeInterface) {
377+
return [
378+
'__class' => $data::class,
379+
'__datetime' => $data->format(DATE_RFC3339_EXTENDED),
380+
];
373381
} elseif ($data instanceof UnitEnum) {
374382
return [
375383
'__class' => $data::class,
376384
'__enum' => $data instanceof BackedEnum ? $data->value : $data->name,
377385
];
378-
} elseif ($data instanceof DateTimeInterface) {
379-
return [
380-
'__class' => $data::class,
381-
'__datetime' => $data->format(DATE_ATOM),
382-
];
383386
} else {
384387
$objectData = get_object_vars($data);
385388
}

tests/system/Entity/EntityTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
namespace CodeIgniter\Entity;
1515

16+
use ArrayIterator;
17+
use ArrayObject;
1618
use Closure;
1719
use CodeIgniter\Entity\Exceptions\CastException;
1820
use CodeIgniter\HTTP\URI;
@@ -2198,4 +2200,48 @@ public function testHasChangedWithDateTimeInterface(): void
21982200
$entity->created_at = new DateTime('2024-01-01 12:00:00', new DateTimeZone('America/New_York'));
21992201
$this->assertTrue($entity->hasChanged('created_at'));
22002202
}
2203+
2204+
public function testHasChangedWithTraversable(): void
2205+
{
2206+
$entity = new class () extends Entity {
2207+
protected $attributes = [
2208+
'items' => null,
2209+
];
2210+
};
2211+
2212+
// Test with ArrayObject
2213+
$entity->items = new ArrayObject(['a', 'b', 'c']);
2214+
$entity->syncOriginal();
2215+
2216+
$this->assertFalse($entity->hasChanged('items'));
2217+
2218+
$entity->items = new ArrayObject(['a', 'b', 'd']);
2219+
$this->assertTrue($entity->hasChanged('items'));
2220+
2221+
$entity->syncOriginal();
2222+
$entity->items = new ArrayObject(['a', 'b', 'd']);
2223+
$this->assertFalse($entity->hasChanged('items'));
2224+
2225+
// Test with ArrayIterator
2226+
$entity->items = new ArrayIterator(['x', 'y', 'z']);
2227+
$entity->syncOriginal();
2228+
$entity->items = new ArrayIterator(['x', 'y', 'modified']);
2229+
$this->assertTrue($entity->hasChanged('items'));
2230+
2231+
// Test with nested objects inside collection (verifies recursive normalization)
2232+
$obj1 = new stdClass();
2233+
$obj1->name = 'first';
2234+
2235+
$obj2 = new stdClass();
2236+
$obj2->name = 'second';
2237+
2238+
$entity->items = new ArrayObject([$obj1, $obj2]);
2239+
$entity->syncOriginal();
2240+
2241+
$obj3 = new stdClass();
2242+
$obj3->name = 'modified';
2243+
2244+
$entity->items = new ArrayObject([$obj3, $obj2]);
2245+
$this->assertTrue($entity->hasChanged('items'));
2246+
}
22012247
}

0 commit comments

Comments
 (0)