From 15c4574074799249450406c2380c07cc05e0b0e9 Mon Sep 17 00:00:00 2001 From: Gustavo Freze Date: Tue, 24 Dec 2024 11:28:41 -0300 Subject: [PATCH 1/2] fix: Fixes Collection to array mapping. --- composer.json | 2 +- .../Mappers/Collection/ArrayMapper.php | 2 +- .../Mappers/Collection/CollectionMapper.php | 2 +- tests/IterableMapperTest.php | 495 ++++++++++++++++++ tests/Models/Collection.php | 134 +++++ tests/Models/InvoiceSummaries.php | 11 - tests/Models/InvoiceSummary.php | 12 - 7 files changed, 632 insertions(+), 26 deletions(-) create mode 100644 tests/IterableMapperTest.php create mode 100644 tests/Models/Collection.php delete mode 100644 tests/Models/InvoiceSummaries.php delete mode 100644 tests/Models/InvoiceSummary.php diff --git a/composer.json b/composer.json index 0cd789b..94fd469 100644 --- a/composer.json +++ b/composer.json @@ -43,7 +43,7 @@ }, "require": { "php": "^8.3", - "tiny-blocks/collection": "1.7.0" + "tiny-blocks/collection": "1.8.0" }, "require-dev": { "phpmd/phpmd": "^2.15", diff --git a/src/Internal/Mappers/Collection/ArrayMapper.php b/src/Internal/Mappers/Collection/ArrayMapper.php index a8bc1e7..bee2d5a 100644 --- a/src/Internal/Mappers/Collection/ArrayMapper.php +++ b/src/Internal/Mappers/Collection/ArrayMapper.php @@ -16,7 +16,7 @@ public function map(mixed $value, KeyPreservation $keyPreservation): array if ($valueMapper->valueIsCollectible(value: $value)) { $collectionMapper = new CollectionMapper(valueMapper: $valueMapper); - $mappedValues = $collectionMapper->map(value: $value, keyPreservation: $keyPreservation); + return $collectionMapper->map(value: $value, keyPreservation: $keyPreservation); } $reflectionClass = new ReflectionClass($value); diff --git a/src/Internal/Mappers/Collection/CollectionMapper.php b/src/Internal/Mappers/Collection/CollectionMapper.php index c5f1a44..01455c8 100644 --- a/src/Internal/Mappers/Collection/CollectionMapper.php +++ b/src/Internal/Mappers/Collection/CollectionMapper.php @@ -21,6 +21,6 @@ public function map(Collectible $value, KeyPreservation $keyPreservation): array $mappedValues[$key] = $this->valueMapper->map(value: $element, keyPreservation: $keyPreservation); } - return $mappedValues; + return $keyPreservation->shouldPreserveKeys() ? $mappedValues : array_values($mappedValues); } } diff --git a/tests/IterableMapperTest.php b/tests/IterableMapperTest.php new file mode 100644 index 0000000..1c44fff --- /dev/null +++ b/tests/IterableMapperTest.php @@ -0,0 +1,495 @@ +toJson(); + + /** @Then the result should match the expected */ + self::assertJsonStringEqualsJsonString($expected, $actual); + } + + #[DataProvider('dataProviderForToArray')] + public function testCollectionToArray(iterable $elements, iterable $expected): void + { + /** @Given a collection with elements */ + $collection = Collection::createFrom(elements: $elements); + + /** @When converting the collection to array */ + $actual = $collection->toArray(); + + /** @Then the result should match the expected */ + self::assertSame($expected, $actual); + self::assertSame(count($expected), $collection->count()); + } + + #[DataProvider('dataProviderForToJsonDiscardKeys')] + public function testCollectionToJsonDiscardKeys(iterable $elements, string $expected): void + { + /** @Given a collection with elements */ + $collection = Collection::createFrom(elements: $elements); + + /** @When converting the collection to JSON while discarding keys */ + $actual = $collection->toJson(keyPreservation: KeyPreservation::DISCARD); + + /** @Then the result should match the expected */ + self::assertJsonStringEqualsJsonString($expected, $actual); + } + + #[DataProvider('dataProviderForToJsonPreserveKeys')] + public function testCollectionToJsonPreserveKeys(iterable $elements, string $expected): void + { + /** @Given a collection with elements */ + $collection = Collection::createFrom(elements: $elements); + + /** @When converting the collection to JSON while preserve keys */ + $actual = $collection->toJson(); + + /** @Then the result should match the expected */ + self::assertJsonStringEqualsJsonString($expected, $actual); + } + + #[DataProvider('dataProviderForToArrayDiscardKeys')] + public function testCollectionToArrayDiscardKeys(iterable $elements, iterable $expected): void + { + /** @Given a collection with elements */ + $collection = Collection::createFrom(elements: $elements); + + /** @When converting the collection to array while discarding keys */ + $actual = $collection->toArray(keyPreservation: KeyPreservation::DISCARD); + + /** @Then the result should match the expected */ + self::assertSame($expected, $actual); + self::assertSame(count($expected), $collection->count()); + } + + #[DataProvider('dataProviderForToArrayPreserveKeys')] + public function testCollectionToArrayPreserveKeys(iterable $elements, iterable $expected): void + { + /** @Given a collection with elements */ + $collection = Collection::createFrom(elements: $elements); + + /** @When converting the collection to array while preserve keys */ + $actual = $collection->toArray(); + + /** @Then the result should match the expected */ + self::assertSame($expected, $actual); + self::assertSame(count($expected), $collection->count()); + } + + public function testInvalidCollectionValueToArrayReturnsEmptyArray(): void + { + /** @Given a collection with an invalid item (e.g., a function that cannot be serialized) */ + $collection = Collection::createFrom(elements: [fn(): null => null, fn(): null => null]); + + /** @When attempting to serialize the collection containing the invalid items */ + $actual = $collection->toJson(); + + /** @Then the invalid item should be serialized as an empty array in the JSON output */ + self::assertSame('[]', $actual); + } + + public static function dataProviderForToJson(): iterable + { + return [ + 'Empty collection' => [ + 'elements' => [], + 'expected' => '[]' + ], + 'Order collection' => [ + 'elements' => [ + new Order( + id: '2c485713-521c-4d91-b9e7-1294f132ad2e', + items: (static function () { + yield ['name' => 'Macbook Pro']; + yield ['name' => 'iPhone XYZ']; + })(), + createdAt: DateTimeImmutable::createFromFormat( + 'Y-m-d H:i:s', + '2000-01-01 00:00:00', + new DateTimeZone('America/Sao_Paulo') + ) + ) + ], + 'expected' => '[{"id":"2c485713-521c-4d91-b9e7-1294f132ad2e","items":[{"name":"Macbook Pro"},{"name":"iPhone XYZ"}],"createdAt":"2000-01-01T00:00:00-02:00"}]' + ], + 'Scalar collection' => [ + 'elements' => ['iPhone', PHP_INT_MAX, 123.456, ['nested' => PHP_INT_MAX], PHP_INT_MIN], + 'expected' => '["iPhone", 9223372036854775807, 123.456, {"nested":9223372036854775807}, -9223372036854775808]' + ], + 'Dragon collection' => [ + 'elements' => [ + new Dragon( + name: 'Ignithar Blazeheart', + type: DragonType::FIRE, + power: 10000000.00, + skills: DragonSkills::cases() + ) + ], + 'expected' => '[{"name":"Ignithar Blazeheart","type":"FIRE","power":10000000,"skills":["fly","spell","regeneration","elemental_breath"]}]' + ], + 'Decimal collection' => [ + 'elements' => [ + new Decimal(value: 100.00), + new Decimal(value: 123.45), + new Decimal(value: 999.99), + ], + 'expected' => '[{"value":100},{"value":123.45},{"value":999.99}]' + ], + 'Product collection' => [ + 'elements' => [ + new Product( + name: 'Macbook Pro', + amount: Amount::from(value: 1600.00, currency: Currency::USD), + stockBatch: new ArrayIterator([1000, 2000, 3000]) + ) + ], + 'expected' => '[{"name":"Macbook Pro","amount":{"value":1600,"currency":"USD"},"stockBatch":[1000,2000,3000]}]' + ], + 'Expiration date collection' => [ + 'elements' => [ + new ExpirationDate( + value: new DateTimeImmutable( + '2000-01-01 00:00:00', + new DateTimeZone('UTC') + ) + ) + ], + 'expected' => '[{"value": "2000-01-01 00:00:00"}]' + ], + 'Shipping object with no addresses' => [ + 'elements' => [ + new Shipping(id: PHP_INT_MAX, addresses: new ShippingAddresses()) + ], + 'expected' => '[{"id":9223372036854775807,"addresses":[]}]' + ], + 'Shipping object with a single address' => [ + 'elements' => [ + new Shipping( + id: PHP_INT_MIN, + addresses: new ShippingAddresses( + elements: [ + new ShippingAddress( + city: 'São Paulo', + state: ShippingState::SP, + street: 'Avenida Paulista', + number: 100, + country: ShippingCountry::BRAZIL + ) + ] + ) + ) + ], + 'expected' => '[{"id":-9223372036854775808,"addresses":[{"city":"São Paulo","state":"SP","street":"Avenida Paulista","number":100,"country":"BR"}]}]' + ], + 'Shipping object with multiple addresses' => [ + 'elements' => [ + new Shipping( + id: 100000, + addresses: new ShippingAddresses( + elements: [ + new ShippingAddress( + city: 'New York', + state: ShippingState::NY, + street: '5th Avenue', + number: 1, + country: ShippingCountry::UNITED_STATES + ), + new ShippingAddress( + city: 'New York', + state: ShippingState::NY, + street: 'Broadway', + number: 42, + country: ShippingCountry::UNITED_STATES + ) + ] + ) + ) + ], + 'expected' => '[{"id":100000,"addresses":[{"city":"New York","state":"NY","street":"5th Avenue","number":1,"country":"US"},{"city":"New York","state":"NY","street":"Broadway","number":42,"country":"US"}]}]' + ] + ]; + } + + public static function dataProviderForToArray(): iterable + { + return [ + 'Order collection' => [ + 'elements' => [ + new Order( + id: '2c485713-521c-4d91-b9e7-1294f132ad2e', + items: (static function () { + yield ['name' => 'Macbook Pro']; + yield ['name' => 'iPhone XYZ']; + })(), + createdAt: DateTimeImmutable::createFromFormat( + 'Y-m-d H:i:s', + '2000-01-01 00:00:00', + new DateTimeZone('America/Sao_Paulo') + ) + ) + ], + 'expected' => [ + [ + 'id' => '2c485713-521c-4d91-b9e7-1294f132ad2e', + 'items' => [['name' => 'Macbook Pro'], ['name' => 'iPhone XYZ']], + 'createdAt' => '2000-01-01T00:00:00-02:00' + ] + ] + ], + 'Dragon collection' => [ + 'elements' => [ + new Dragon( + name: 'Ignithar Blazeheart', + type: DragonType::FIRE, + power: 10000000.00, + skills: DragonSkills::cases() + ) + ], + 'expected' => [ + [ + 'name' => 'Ignithar Blazeheart', + 'type' => 'FIRE', + 'power' => 10000000.00, + 'skills' => ['fly', 'spell', 'regeneration', 'elemental_breath'] + ] + ] + ], + 'Decimal collection' => [ + 'elements' => [ + new Decimal(value: 100.00), + new Decimal(value: 123.45), + new Decimal(value: 999.99), + ], + 'expected' => [ + ['value' => 100.00], + ['value' => 123.45], + ['value' => 999.99] + ] + ], + 'Product collection' => [ + 'elements' => [ + new Product( + name: 'Macbook Pro', + amount: Amount::from(value: 1600.00, currency: Currency::USD), + stockBatch: new ArrayIterator([1000, 2000, 3000]) + ) + ], + 'expected' => [ + [ + 'name' => 'Macbook Pro', + 'amount' => ['value' => 1600.00, 'currency' => Currency::USD->value], + 'stockBatch' => [1000, 2000, 3000] + ] + ] + ], + 'Expiration date collection' => [ + 'elements' => [ + new ExpirationDate( + value: new DateTimeImmutable( + '2000-01-01 00:00:00', + new DateTimeZone('UTC') + ) + ) + ], + 'expected' => [['value' => '2000-01-01 00:00:00']] + ], + 'Shipping object with no addresses' => [ + 'elements' => [ + new Shipping(id: PHP_INT_MAX, addresses: new ShippingAddresses()) + ], + 'expected' => [ + [ + 'id' => PHP_INT_MAX, + 'addresses' => [] + ] + ] + ], + 'Shipping object with a single address' => [ + 'elements' => [ + new Shipping( + id: PHP_INT_MIN, + addresses: new ShippingAddresses( + elements: [ + new ShippingAddress( + city: 'São Paulo', + state: ShippingState::SP, + street: 'Avenida Paulista', + number: 100, + country: ShippingCountry::BRAZIL + ) + ] + ) + ) + ], + 'expected' => [ + [ + 'id' => PHP_INT_MIN, + 'addresses' => [ + [ + 'city' => 'São Paulo', + 'state' => ShippingState::SP->name, + 'street' => 'Avenida Paulista', + 'number' => 100, + 'country' => ShippingCountry::BRAZIL->value + ] + ] + ] + ] + ], + 'Shipping object with multiple addresses' => [ + 'elements' => [ + new Shipping( + id: 100000, + addresses: new ShippingAddresses( + elements: [ + new ShippingAddress( + city: 'New York', + state: ShippingState::NY, + street: '5th Avenue', + number: 1, + country: ShippingCountry::UNITED_STATES + ), + new ShippingAddress( + city: 'New York', + state: ShippingState::NY, + street: 'Broadway', + number: 42, + country: ShippingCountry::UNITED_STATES + ) + ] + ) + ) + ], + 'expected' => [ + [ + 'id' => 100000, + 'addresses' => [ + [ + 'city' => 'New York', + 'state' => ShippingState::NY->name, + 'street' => '5th Avenue', + 'number' => 1, + 'country' => ShippingCountry::UNITED_STATES->value + ], + [ + 'city' => 'New York', + 'state' => ShippingState::NY->name, + 'street' => 'Broadway', + 'number' => 42, + 'country' => ShippingCountry::UNITED_STATES->value + ] + ] + ] + ] + ] + ]; + } + + public static function dataProviderForToJsonDiscardKeys(): iterable + { + return [ + 'Scalar collection' => [ + 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], + 'expected' => '[12.34,"apple",100,true]' + ], + 'ArrayIterator collection' => [ + 'elements' => new ArrayIterator([ + 'float' => 12.34, + 'string' => 'apple', + 'integer' => 100, + 'boolean' => true + ]), + 'expected' => '[12.34,"apple",100,true]' + ] + ]; + } + + public static function dataProviderForToJsonPreserveKeys(): iterable + { + return [ + 'Scalar collection' => [ + 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], + 'expected' => '{"float":12.34,"string":"apple","integer":100,"boolean":true}' + ], + 'ArrayIterator collection' => [ + 'elements' => new ArrayIterator([ + 'float' => 12.34, + 'string' => 'apple', + 'integer' => 100, + 'boolean' => true + ]), + 'expected' => '{"float":12.34,"string":"apple","integer":100,"boolean":true}' + ] + ]; + } + + public static function dataProviderForToArrayDiscardKeys(): iterable + { + return [ + 'Scalar collection' => [ + 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], + 'expected' => [12.34, 'apple', 100, true] + ], + 'ArrayIterator collection' => [ + 'elements' => new ArrayIterator([ + 'float' => 12.34, + 'string' => 'apple', + 'integer' => 100, + 'boolean' => true + ]), + 'expected' => [12.34, 'apple', 100, true] + ] + ]; + } + + public static function dataProviderForToArrayPreserveKeys(): iterable + { + return [ + 'Scalar collection' => [ + 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], + 'expected' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true] + ], + 'ArrayIterator collection' => [ + 'elements' => new ArrayIterator([ + 'float' => 12.34, + 'string' => 'apple', + 'integer' => 100, + 'boolean' => true + ]), + 'expected' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true] + ] + ]; + } +} diff --git a/tests/Models/Collection.php b/tests/Models/Collection.php new file mode 100644 index 0000000..5b3ed52 --- /dev/null +++ b/tests/Models/Collection.php @@ -0,0 +1,134 @@ +iterator = $iterator; + } + + public static function createFrom(iterable $elements): Collectible + { + return new Collection(iterator: $elements); + } + + public static function createFromEmpty(): Collectible + { + // TODO: Implement createFromEmpty() method. + } + + public function add(...$elements): Collectible + { + // TODO: Implement add() method. + } + + public function contains(mixed $element): bool + { + // TODO: Implement contains() method. + } + + public function count(): int + { + return iterator_count($this->iterator); + } + + public function each(Closure ...$actions): Collectible + { + // TODO: Implement each() method. + } + + public function equals(Collectible $other): bool + { + // TODO: Implement equals() method. + } + + public function filter(?Closure ...$predicates): Collectible + { + // TODO: Implement filter() method. + } + + public function findBy(Closure ...$predicates): mixed + { + // TODO: Implement findBy() method. + } + + public function first(mixed $defaultValueIfNotFound = null): mixed + { + // TODO: Implement first() method. + } + + public function getBy(int $index, mixed $defaultValueIfNotFound = null): mixed + { + // TODO: Implement getBy() method. + } + + public function getIterator(): Traversable + { + yield from $this->iterator; + } + + public function groupBy(Closure $grouping): Collectible + { + // TODO: Implement groupBy() method. + } + + public function isEmpty(): bool + { + // TODO: Implement isEmpty() method. + } + + public function joinToString(string $separator): string + { + // TODO: Implement joinToString() method. + } + + public function last(mixed $defaultValueIfNotFound = null): mixed + { + // TODO: Implement last() method. + } + + public function map(Closure ...$transformations): Collectible + { + // TODO: Implement map() method. + } + + public function remove(mixed $element): Collectible + { + // TODO: Implement remove() method. + } + + public function removeAll(?Closure $filter = null): Collectible + { + // TODO: Implement removeAll() method. + } + + public function reduce(Closure $aggregator, mixed $initial): mixed + { + // TODO: Implement reduce() method. + } + + public function sort(Order $order = Order::ASCENDING_KEY, ?Closure $predicate = null): Collectible + { + // TODO: Implement sort() method. + } + + public function slice(int $index, int $length = -1): Collectible + { + // TODO: Implement slice() method. + } +} diff --git a/tests/Models/InvoiceSummaries.php b/tests/Models/InvoiceSummaries.php deleted file mode 100644 index f4b6a1d..0000000 --- a/tests/Models/InvoiceSummaries.php +++ /dev/null @@ -1,11 +0,0 @@ - Date: Tue, 24 Dec 2024 11:36:43 -0300 Subject: [PATCH 2/2] fix: Fixes Collection to array mapping. --- tests/IterableMapperTest.php | 495 ----------------------------------- tests/Models/Collection.php | 27 +- 2 files changed, 22 insertions(+), 500 deletions(-) delete mode 100644 tests/IterableMapperTest.php diff --git a/tests/IterableMapperTest.php b/tests/IterableMapperTest.php deleted file mode 100644 index 1c44fff..0000000 --- a/tests/IterableMapperTest.php +++ /dev/null @@ -1,495 +0,0 @@ -toJson(); - - /** @Then the result should match the expected */ - self::assertJsonStringEqualsJsonString($expected, $actual); - } - - #[DataProvider('dataProviderForToArray')] - public function testCollectionToArray(iterable $elements, iterable $expected): void - { - /** @Given a collection with elements */ - $collection = Collection::createFrom(elements: $elements); - - /** @When converting the collection to array */ - $actual = $collection->toArray(); - - /** @Then the result should match the expected */ - self::assertSame($expected, $actual); - self::assertSame(count($expected), $collection->count()); - } - - #[DataProvider('dataProviderForToJsonDiscardKeys')] - public function testCollectionToJsonDiscardKeys(iterable $elements, string $expected): void - { - /** @Given a collection with elements */ - $collection = Collection::createFrom(elements: $elements); - - /** @When converting the collection to JSON while discarding keys */ - $actual = $collection->toJson(keyPreservation: KeyPreservation::DISCARD); - - /** @Then the result should match the expected */ - self::assertJsonStringEqualsJsonString($expected, $actual); - } - - #[DataProvider('dataProviderForToJsonPreserveKeys')] - public function testCollectionToJsonPreserveKeys(iterable $elements, string $expected): void - { - /** @Given a collection with elements */ - $collection = Collection::createFrom(elements: $elements); - - /** @When converting the collection to JSON while preserve keys */ - $actual = $collection->toJson(); - - /** @Then the result should match the expected */ - self::assertJsonStringEqualsJsonString($expected, $actual); - } - - #[DataProvider('dataProviderForToArrayDiscardKeys')] - public function testCollectionToArrayDiscardKeys(iterable $elements, iterable $expected): void - { - /** @Given a collection with elements */ - $collection = Collection::createFrom(elements: $elements); - - /** @When converting the collection to array while discarding keys */ - $actual = $collection->toArray(keyPreservation: KeyPreservation::DISCARD); - - /** @Then the result should match the expected */ - self::assertSame($expected, $actual); - self::assertSame(count($expected), $collection->count()); - } - - #[DataProvider('dataProviderForToArrayPreserveKeys')] - public function testCollectionToArrayPreserveKeys(iterable $elements, iterable $expected): void - { - /** @Given a collection with elements */ - $collection = Collection::createFrom(elements: $elements); - - /** @When converting the collection to array while preserve keys */ - $actual = $collection->toArray(); - - /** @Then the result should match the expected */ - self::assertSame($expected, $actual); - self::assertSame(count($expected), $collection->count()); - } - - public function testInvalidCollectionValueToArrayReturnsEmptyArray(): void - { - /** @Given a collection with an invalid item (e.g., a function that cannot be serialized) */ - $collection = Collection::createFrom(elements: [fn(): null => null, fn(): null => null]); - - /** @When attempting to serialize the collection containing the invalid items */ - $actual = $collection->toJson(); - - /** @Then the invalid item should be serialized as an empty array in the JSON output */ - self::assertSame('[]', $actual); - } - - public static function dataProviderForToJson(): iterable - { - return [ - 'Empty collection' => [ - 'elements' => [], - 'expected' => '[]' - ], - 'Order collection' => [ - 'elements' => [ - new Order( - id: '2c485713-521c-4d91-b9e7-1294f132ad2e', - items: (static function () { - yield ['name' => 'Macbook Pro']; - yield ['name' => 'iPhone XYZ']; - })(), - createdAt: DateTimeImmutable::createFromFormat( - 'Y-m-d H:i:s', - '2000-01-01 00:00:00', - new DateTimeZone('America/Sao_Paulo') - ) - ) - ], - 'expected' => '[{"id":"2c485713-521c-4d91-b9e7-1294f132ad2e","items":[{"name":"Macbook Pro"},{"name":"iPhone XYZ"}],"createdAt":"2000-01-01T00:00:00-02:00"}]' - ], - 'Scalar collection' => [ - 'elements' => ['iPhone', PHP_INT_MAX, 123.456, ['nested' => PHP_INT_MAX], PHP_INT_MIN], - 'expected' => '["iPhone", 9223372036854775807, 123.456, {"nested":9223372036854775807}, -9223372036854775808]' - ], - 'Dragon collection' => [ - 'elements' => [ - new Dragon( - name: 'Ignithar Blazeheart', - type: DragonType::FIRE, - power: 10000000.00, - skills: DragonSkills::cases() - ) - ], - 'expected' => '[{"name":"Ignithar Blazeheart","type":"FIRE","power":10000000,"skills":["fly","spell","regeneration","elemental_breath"]}]' - ], - 'Decimal collection' => [ - 'elements' => [ - new Decimal(value: 100.00), - new Decimal(value: 123.45), - new Decimal(value: 999.99), - ], - 'expected' => '[{"value":100},{"value":123.45},{"value":999.99}]' - ], - 'Product collection' => [ - 'elements' => [ - new Product( - name: 'Macbook Pro', - amount: Amount::from(value: 1600.00, currency: Currency::USD), - stockBatch: new ArrayIterator([1000, 2000, 3000]) - ) - ], - 'expected' => '[{"name":"Macbook Pro","amount":{"value":1600,"currency":"USD"},"stockBatch":[1000,2000,3000]}]' - ], - 'Expiration date collection' => [ - 'elements' => [ - new ExpirationDate( - value: new DateTimeImmutable( - '2000-01-01 00:00:00', - new DateTimeZone('UTC') - ) - ) - ], - 'expected' => '[{"value": "2000-01-01 00:00:00"}]' - ], - 'Shipping object with no addresses' => [ - 'elements' => [ - new Shipping(id: PHP_INT_MAX, addresses: new ShippingAddresses()) - ], - 'expected' => '[{"id":9223372036854775807,"addresses":[]}]' - ], - 'Shipping object with a single address' => [ - 'elements' => [ - new Shipping( - id: PHP_INT_MIN, - addresses: new ShippingAddresses( - elements: [ - new ShippingAddress( - city: 'São Paulo', - state: ShippingState::SP, - street: 'Avenida Paulista', - number: 100, - country: ShippingCountry::BRAZIL - ) - ] - ) - ) - ], - 'expected' => '[{"id":-9223372036854775808,"addresses":[{"city":"São Paulo","state":"SP","street":"Avenida Paulista","number":100,"country":"BR"}]}]' - ], - 'Shipping object with multiple addresses' => [ - 'elements' => [ - new Shipping( - id: 100000, - addresses: new ShippingAddresses( - elements: [ - new ShippingAddress( - city: 'New York', - state: ShippingState::NY, - street: '5th Avenue', - number: 1, - country: ShippingCountry::UNITED_STATES - ), - new ShippingAddress( - city: 'New York', - state: ShippingState::NY, - street: 'Broadway', - number: 42, - country: ShippingCountry::UNITED_STATES - ) - ] - ) - ) - ], - 'expected' => '[{"id":100000,"addresses":[{"city":"New York","state":"NY","street":"5th Avenue","number":1,"country":"US"},{"city":"New York","state":"NY","street":"Broadway","number":42,"country":"US"}]}]' - ] - ]; - } - - public static function dataProviderForToArray(): iterable - { - return [ - 'Order collection' => [ - 'elements' => [ - new Order( - id: '2c485713-521c-4d91-b9e7-1294f132ad2e', - items: (static function () { - yield ['name' => 'Macbook Pro']; - yield ['name' => 'iPhone XYZ']; - })(), - createdAt: DateTimeImmutable::createFromFormat( - 'Y-m-d H:i:s', - '2000-01-01 00:00:00', - new DateTimeZone('America/Sao_Paulo') - ) - ) - ], - 'expected' => [ - [ - 'id' => '2c485713-521c-4d91-b9e7-1294f132ad2e', - 'items' => [['name' => 'Macbook Pro'], ['name' => 'iPhone XYZ']], - 'createdAt' => '2000-01-01T00:00:00-02:00' - ] - ] - ], - 'Dragon collection' => [ - 'elements' => [ - new Dragon( - name: 'Ignithar Blazeheart', - type: DragonType::FIRE, - power: 10000000.00, - skills: DragonSkills::cases() - ) - ], - 'expected' => [ - [ - 'name' => 'Ignithar Blazeheart', - 'type' => 'FIRE', - 'power' => 10000000.00, - 'skills' => ['fly', 'spell', 'regeneration', 'elemental_breath'] - ] - ] - ], - 'Decimal collection' => [ - 'elements' => [ - new Decimal(value: 100.00), - new Decimal(value: 123.45), - new Decimal(value: 999.99), - ], - 'expected' => [ - ['value' => 100.00], - ['value' => 123.45], - ['value' => 999.99] - ] - ], - 'Product collection' => [ - 'elements' => [ - new Product( - name: 'Macbook Pro', - amount: Amount::from(value: 1600.00, currency: Currency::USD), - stockBatch: new ArrayIterator([1000, 2000, 3000]) - ) - ], - 'expected' => [ - [ - 'name' => 'Macbook Pro', - 'amount' => ['value' => 1600.00, 'currency' => Currency::USD->value], - 'stockBatch' => [1000, 2000, 3000] - ] - ] - ], - 'Expiration date collection' => [ - 'elements' => [ - new ExpirationDate( - value: new DateTimeImmutable( - '2000-01-01 00:00:00', - new DateTimeZone('UTC') - ) - ) - ], - 'expected' => [['value' => '2000-01-01 00:00:00']] - ], - 'Shipping object with no addresses' => [ - 'elements' => [ - new Shipping(id: PHP_INT_MAX, addresses: new ShippingAddresses()) - ], - 'expected' => [ - [ - 'id' => PHP_INT_MAX, - 'addresses' => [] - ] - ] - ], - 'Shipping object with a single address' => [ - 'elements' => [ - new Shipping( - id: PHP_INT_MIN, - addresses: new ShippingAddresses( - elements: [ - new ShippingAddress( - city: 'São Paulo', - state: ShippingState::SP, - street: 'Avenida Paulista', - number: 100, - country: ShippingCountry::BRAZIL - ) - ] - ) - ) - ], - 'expected' => [ - [ - 'id' => PHP_INT_MIN, - 'addresses' => [ - [ - 'city' => 'São Paulo', - 'state' => ShippingState::SP->name, - 'street' => 'Avenida Paulista', - 'number' => 100, - 'country' => ShippingCountry::BRAZIL->value - ] - ] - ] - ] - ], - 'Shipping object with multiple addresses' => [ - 'elements' => [ - new Shipping( - id: 100000, - addresses: new ShippingAddresses( - elements: [ - new ShippingAddress( - city: 'New York', - state: ShippingState::NY, - street: '5th Avenue', - number: 1, - country: ShippingCountry::UNITED_STATES - ), - new ShippingAddress( - city: 'New York', - state: ShippingState::NY, - street: 'Broadway', - number: 42, - country: ShippingCountry::UNITED_STATES - ) - ] - ) - ) - ], - 'expected' => [ - [ - 'id' => 100000, - 'addresses' => [ - [ - 'city' => 'New York', - 'state' => ShippingState::NY->name, - 'street' => '5th Avenue', - 'number' => 1, - 'country' => ShippingCountry::UNITED_STATES->value - ], - [ - 'city' => 'New York', - 'state' => ShippingState::NY->name, - 'street' => 'Broadway', - 'number' => 42, - 'country' => ShippingCountry::UNITED_STATES->value - ] - ] - ] - ] - ] - ]; - } - - public static function dataProviderForToJsonDiscardKeys(): iterable - { - return [ - 'Scalar collection' => [ - 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], - 'expected' => '[12.34,"apple",100,true]' - ], - 'ArrayIterator collection' => [ - 'elements' => new ArrayIterator([ - 'float' => 12.34, - 'string' => 'apple', - 'integer' => 100, - 'boolean' => true - ]), - 'expected' => '[12.34,"apple",100,true]' - ] - ]; - } - - public static function dataProviderForToJsonPreserveKeys(): iterable - { - return [ - 'Scalar collection' => [ - 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], - 'expected' => '{"float":12.34,"string":"apple","integer":100,"boolean":true}' - ], - 'ArrayIterator collection' => [ - 'elements' => new ArrayIterator([ - 'float' => 12.34, - 'string' => 'apple', - 'integer' => 100, - 'boolean' => true - ]), - 'expected' => '{"float":12.34,"string":"apple","integer":100,"boolean":true}' - ] - ]; - } - - public static function dataProviderForToArrayDiscardKeys(): iterable - { - return [ - 'Scalar collection' => [ - 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], - 'expected' => [12.34, 'apple', 100, true] - ], - 'ArrayIterator collection' => [ - 'elements' => new ArrayIterator([ - 'float' => 12.34, - 'string' => 'apple', - 'integer' => 100, - 'boolean' => true - ]), - 'expected' => [12.34, 'apple', 100, true] - ] - ]; - } - - public static function dataProviderForToArrayPreserveKeys(): iterable - { - return [ - 'Scalar collection' => [ - 'elements' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true], - 'expected' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true] - ], - 'ArrayIterator collection' => [ - 'elements' => new ArrayIterator([ - 'float' => 12.34, - 'string' => 'apple', - 'integer' => 100, - 'boolean' => true - ]), - 'expected' => ['float' => 12.34, 'string' => 'apple', 'integer' => 100, 'boolean' => true] - ] - ]; - } -} diff --git a/tests/Models/Collection.php b/tests/Models/Collection.php index 5b3ed52..3f07d85 100644 --- a/tests/Models/Collection.php +++ b/tests/Models/Collection.php @@ -6,14 +6,14 @@ use Closure; use TinyBlocks\Collection\Collectible; -use TinyBlocks\Collection\Internal\Operations\Order\Order; +use TinyBlocks\Collection\PreserveKeys; use TinyBlocks\Mapper\IterableMappability; use TinyBlocks\Mapper\IterableMapper; use Traversable; -final readonly class Collection implements Collectible, IterableMapper +final readonly class Collection implements Collectible { - use IterableMappability; + //use IterableMappability; private iterable $iterator; @@ -72,6 +72,11 @@ public function first(mixed $defaultValueIfNotFound = null): mixed // TODO: Implement first() method. } + public function flatten(): Collectible + { + // TODO: Implement flatten() method. + } + public function getBy(int $index, mixed $defaultValueIfNotFound = null): mixed { // TODO: Implement getBy() method. @@ -122,8 +127,10 @@ public function reduce(Closure $aggregator, mixed $initial): mixed // TODO: Implement reduce() method. } - public function sort(Order $order = Order::ASCENDING_KEY, ?Closure $predicate = null): Collectible - { + public function sort( + \TinyBlocks\Collection\Order $order = \TinyBlocks\Collection\Order::ASCENDING_KEY, + ?Closure $predicate = null + ): Collectible { // TODO: Implement sort() method. } @@ -131,4 +138,14 @@ public function slice(int $index, int $length = -1): Collectible { // TODO: Implement slice() method. } + + public function toArray(PreserveKeys $preserveKeys = PreserveKeys::PRESERVE): array + { + // TODO: Implement toArray() method. + } + + public function toJson(PreserveKeys $preserveKeys = PreserveKeys::PRESERVE): string + { + // TODO: Implement toJson() method. + } }