From 8cccbb09914eb555b73f75761a641cb53b7760b1 Mon Sep 17 00:00:00 2001 From: Gustavo Freze Date: Mon, 9 Feb 2026 21:59:56 -0300 Subject: [PATCH] fix: Fixes mapping for Traversable objects in IterableExtractor. --- src/Internal/Extractors/IterableExtractor.php | 4 +++ tests/CollectionMappingTest.php | 27 ++++++++++++++++ tests/Models/Invoice.php | 12 +++++++ tests/Models/InvoiceSummaries.php | 31 +++++++++++++++++++ tests/Models/Invoices.php | 29 +++++++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 tests/Models/Invoice.php create mode 100644 tests/Models/InvoiceSummaries.php create mode 100644 tests/Models/Invoices.php diff --git a/src/Internal/Extractors/IterableExtractor.php b/src/Internal/Extractors/IterableExtractor.php index 7ada306..221b847 100644 --- a/src/Internal/Extractors/IterableExtractor.php +++ b/src/Internal/Extractors/IterableExtractor.php @@ -14,6 +14,10 @@ public function __construct(private ReflectionExtractor $extractor) public function extract(object $object): array { + if ($object instanceof Traversable) { + return iterator_to_array($object); + } + $properties = $this->extractor->extractProperties(object: $object); $candidates = array_filter( diff --git a/tests/CollectionMappingTest.php b/tests/CollectionMappingTest.php index d081251..7ac48df 100644 --- a/tests/CollectionMappingTest.php +++ b/tests/CollectionMappingTest.php @@ -17,6 +17,9 @@ use Test\TinyBlocks\Mapper\Models\Description; use Test\TinyBlocks\Mapper\Models\Employee; use Test\TinyBlocks\Mapper\Models\Employees; +use Test\TinyBlocks\Mapper\Models\Invoice; +use Test\TinyBlocks\Mapper\Models\Invoices; +use Test\TinyBlocks\Mapper\Models\InvoiceSummaries; use Test\TinyBlocks\Mapper\Models\Member; use Test\TinyBlocks\Mapper\Models\MemberId; use Test\TinyBlocks\Mapper\Models\Members; @@ -89,6 +92,30 @@ public function testCollectionOfScalars(): void self::assertSame('mixed', $attributes->getType()); } + public function testCollectionOfTraversable(): void + { + /** @Given an InvoiceSummaries collection with traversable invoices */ + $invoiceSummaries = InvoiceSummaries::createFrom( + invoices: Invoices::createFrom(elements: [ + new Invoice(id: 'INV001', amount: 100.0, customer: 'Customer A'), + new Invoice(id: 'INV002', amount: 150.5, customer: 'Customer B'), + new Invoice(id: 'INV003', amount: 200.75, customer: 'Customer C') + ]) + ); + + /** @When mapping the InvoiceSummaries collection to an array */ + $actual = $invoiceSummaries->toArray(); + + /** @Then the mapped array should have expected values */ + $expected = [ + 'INV001' => ['id' => 'INV001', 'amount' => 100.0, 'customer' => 'Customer A'], + 'INV002' => ['id' => 'INV002', 'amount' => 150.5, 'customer' => 'Customer B'], + 'INV003' => ['id' => 'INV003', 'amount' => 200.75, 'customer' => 'Customer C'] + ]; + + self::assertSame($expected, $actual); + } + #[DataProvider('collectionDiscardKeysProvider')] public function testCollectionDiscardKeys(IterableMapper $collection, array $expected): void { diff --git a/tests/Models/Invoice.php b/tests/Models/Invoice.php new file mode 100644 index 0000000..f287baf --- /dev/null +++ b/tests/Models/Invoice.php @@ -0,0 +1,12 @@ +invoices as $invoice) { + yield $invoice->id => $invoice; + } + } +} diff --git a/tests/Models/Invoices.php b/tests/Models/Invoices.php new file mode 100644 index 0000000..6375bb8 --- /dev/null +++ b/tests/Models/Invoices.php @@ -0,0 +1,29 @@ +elements; + } +}