From db12b6f5ead387d386c0ddc3cdec7a5b166bc584 Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Fri, 15 Nov 2024 13:56:31 +0100 Subject: [PATCH 01/10] add chunk, eachChunk and tests for chunk --- README.md | 6 +++++ src/Collection.php | 5 ++++ src/CollectionTrait.php | 24 ++++++++++++++++++++ tests/CollectionTest.php | 49 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+) diff --git a/README.md b/README.md index 7a586db..f0e0430 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,12 @@ composer install composer test-coverage ``` +To run tests in a docker container (without coverage): + +```bash +docker run -it --rm --workdir /app --volume .:/app php:8.1 php vendor/bin/phpunit tests/ 1 ↵ +``` + ## Usage The library defines interfaces to deal with collections and also boilerplate code with default implementations. diff --git a/src/Collection.php b/src/Collection.php index 6cf5988..9c3b19b 100644 --- a/src/Collection.php +++ b/src/Collection.php @@ -10,12 +10,17 @@ interface Collection extends FromIterable, ToArray { public function add(mixed $value): self|static; + /** @return self[]|static[] */ + public function chunk(int $size): array; + public function diff(self $other): self|static; public function duplicates(bool $strict = true, bool $uniques = false): self|static; public function each(callable $function, bool $rewind = true): self|static; + public function eachChunk(int $size, callable $function): self|static; + public function empty(): bool; public function has(mixed $value, bool $strict = true): bool; diff --git a/src/CollectionTrait.php b/src/CollectionTrait.php index 94b6cae..def06f6 100644 --- a/src/CollectionTrait.php +++ b/src/CollectionTrait.php @@ -34,6 +34,21 @@ public function add($value): self|static return $this; } + /** @return self[] */ + public function chunk(int $size): array + { + if ($size < 1) { + return [$this]; + } + + return array_map( + static function(array $uuids) { + return self::fromIterable($uuids); + }, + array_chunk($this->toArray(), $size) + ); + } + public function diff(Collection $other): self|static { if (!$other instanceof static) { @@ -84,6 +99,15 @@ public function each(callable $function, bool $rewind = true): self|static return $this; } + public function eachChunk(int $size, callable $function): self|static + { + foreach ($this->chunk($size) as $chunk) { + $function($chunk); + } + + return $this; + } + public function empty(): bool { return 0 === $this->count(); diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php index f438748..6be189d 100644 --- a/tests/CollectionTest.php +++ b/tests/CollectionTest.php @@ -485,6 +485,55 @@ public function testReverse(): void self::assertEquals([5, 4, 3, 2, 1], CollectionStub::fromIterable([1, 2, 3, 4, 5])->reverse()->toArray()); } + #[DataProvider('chunkDataProvider')] + public function testChunk(Collection $collectionToChunk, int $chunkSize, array $expectedChunks): void + { + self::assertEquals( + $expectedChunks, + $collectionToChunk->chunk($chunkSize) + ); + } + + public static function chunkDataProvider(): array + { + return [ + 'chunk_size_0' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 0, + [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + ], + ], + 'chunk_size_2' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 2, + [ + CollectionStub::fromIterable([1, 2]), + CollectionStub::fromIterable([3, 4]), + CollectionStub::fromIterable([5]), + ], + ], + 'chunk_size_1' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 1, + [ + CollectionStub::fromIterable([1]), + CollectionStub::fromIterable([2]), + CollectionStub::fromIterable([3]), + CollectionStub::fromIterable([4]), + CollectionStub::fromIterable([5]), + ], + ], + 'chunk_size_5' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 5, + [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + ], + ], + ]; + } + public function testDiff(): void { $collection1 = CollectionStub::fromIterable([1, 2, 3, 4, 5]); From f92e273c62f4e6ee7eb2c5105e95ae5e971b2d11 Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Fri, 15 Nov 2024 14:27:36 +0100 Subject: [PATCH 02/10] update docs, test chunkEach method --- docs/collection-interfaces.md | 17 +++++++++++ docs/collection-trait.md | 8 ++++++ tests/CollectionTest.php | 54 +++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+) diff --git a/docs/collection-interfaces.md b/docs/collection-interfaces.md index f37f9b0..ddfe0ab 100644 --- a/docs/collection-interfaces.md +++ b/docs/collection-interfaces.md @@ -44,6 +44,15 @@ This method is defined to be a fluent version of `ArrayIterator::append`. To do $collection->add($item1)->add($item2); ``` +### chunk + +```php + /** @return self[]|static[] */ + public function chunk(int $size): array +``` + +This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current Collection based on the chunk size provided. + ### diff ```php @@ -77,6 +86,14 @@ Callable signature: function(mixed $element, string|float|int|bool|null $elementKey): void; ``` +### eachChunk + +```php +public function eachChunk(int $size, callable $function): self|static +``` + +This method chunks the collection and executes the given anonymous function with each chunk. + ### empty ```php diff --git a/docs/collection-trait.md b/docs/collection-trait.md index 5c4cb55..7fada76 100644 --- a/docs/collection-trait.md +++ b/docs/collection-trait.md @@ -95,6 +95,10 @@ $collection->toArray(); Internally it is call the `ArrayIterator::append` and returning the instance to allow fluent calls. +### chunk + +This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current Collection based on the chunk size provided. + ## diff To check the difference between two collections first it checks that the other collection is of the same type as the current one. @@ -117,6 +121,10 @@ Finally, it will return the duplicated collection, optionally calling the `uniqu Internally, this method will iterate through each item of a collection, optionally rewind it at the end of the iteration, calling the anonymous function for each element. +### eachChunk + +This method chunks the collection and executes the given anonymous function with each chunk. + ## empty Internally is checking if the `ArrayIterator::count` returns 0 diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php index 6be189d..7f97d59 100644 --- a/tests/CollectionTest.php +++ b/tests/CollectionTest.php @@ -602,6 +602,60 @@ public static function eachDataProvider(): array ]; } + #[DataProvider('chunkEachDataProvider')] + public function testChunkEach(Collection $collectionToChunk, int $chunkSize, array $expectedChunks): void + { + $expectedLambda = function(CollectionStub $collection) use ($expectedChunks): void { + static $i = 0; + self::assertEquals($collection, $expectedChunks[$i++]); + }; + + $collectionToChunk->eachChunk($chunkSize, $expectedLambda); + } + + public static function chunkEachDataProvider(): array + { + $expectedFunction = static function(CollectionStub $stub): void { + }; + + return [ + 'chunk_each_size_0' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 0, + [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + ], + ], + 'chunk_each_size_2' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 2, + [ + CollectionStub::fromIterable([1, 2]), + CollectionStub::fromIterable([3, 4]), + CollectionStub::fromIterable([5]), + ], + ], + 'chunk_each_size_1' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 1, + [ + CollectionStub::fromIterable([1]), + CollectionStub::fromIterable([2]), + CollectionStub::fromIterable([3]), + CollectionStub::fromIterable([4]), + CollectionStub::fromIterable([5]), + ], + ], + 'chunk_each_size_5' => [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + 5, + [ + CollectionStub::fromIterable([1, 2, 3, 4, 5]), + ], + ], + ]; + } + #[DataProvider('mapDataProvider')] public function testMap(bool $rewind, ?array $expectedCurrent, bool $expectException): void { From 3f78ea5edca08e12372fcb7f387b5ac076bbf9ff Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Fri, 15 Nov 2024 14:29:45 +0100 Subject: [PATCH 03/10] update docs --- docs/collection-interfaces.md | 4 ++-- docs/collection-trait.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/collection-interfaces.md b/docs/collection-interfaces.md index ddfe0ab..e10911b 100644 --- a/docs/collection-interfaces.md +++ b/docs/collection-interfaces.md @@ -47,8 +47,8 @@ $collection->add($item1)->add($item2); ### chunk ```php - /** @return self[]|static[] */ - public function chunk(int $size): array +/** @return self[]|static[] */ +public function chunk(int $size): array ``` This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current Collection based on the chunk size provided. diff --git a/docs/collection-trait.md b/docs/collection-trait.md index 7fada76..89d6ae1 100644 --- a/docs/collection-trait.md +++ b/docs/collection-trait.md @@ -95,7 +95,7 @@ $collection->toArray(); Internally it is call the `ArrayIterator::append` and returning the instance to allow fluent calls. -### chunk +## chunk This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current Collection based on the chunk size provided. @@ -121,7 +121,7 @@ Finally, it will return the duplicated collection, optionally calling the `uniqu Internally, this method will iterate through each item of a collection, optionally rewind it at the end of the iteration, calling the anonymous function for each element. -### eachChunk +## eachChunk This method chunks the collection and executes the given anonymous function with each chunk. From f6a9b994f5057e8a928d913ef0e6fa847b71c379 Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Fri, 15 Nov 2024 14:56:32 +0100 Subject: [PATCH 04/10] remove unused variable --- tests/CollectionTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php index 7f97d59..2d0d397 100644 --- a/tests/CollectionTest.php +++ b/tests/CollectionTest.php @@ -615,9 +615,6 @@ public function testChunkEach(Collection $collectionToChunk, int $chunkSize, arr public static function chunkEachDataProvider(): array { - $expectedFunction = static function(CollectionStub $stub): void { - }; - return [ 'chunk_each_size_0' => [ CollectionStub::fromIterable([1, 2, 3, 4, 5]), From d3232760be533c7919e897b051e9b2207d2fa5be Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Mon, 18 Nov 2024 11:46:53 +0100 Subject: [PATCH 05/10] Update README, rename var in chunk method --- README.md | 2 +- src/CollectionTrait.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f0e0430..f2d555b 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ composer test-coverage To run tests in a docker container (without coverage): ```bash -docker run -it --rm --workdir /app --volume .:/app php:8.1 php vendor/bin/phpunit tests/ 1 ↵ +docker run -it --rm --workdir /app --volume .:/app php:8.1 php vendor/bin/phpunit tests/ ``` ## Usage diff --git a/src/CollectionTrait.php b/src/CollectionTrait.php index def06f6..5526b27 100644 --- a/src/CollectionTrait.php +++ b/src/CollectionTrait.php @@ -42,8 +42,8 @@ public function chunk(int $size): array } return array_map( - static function(array $uuids) { - return self::fromIterable($uuids); + static function(array $chunk) { + return self::fromIterable($chunk); }, array_chunk($this->toArray(), $size) ); From 29793656516475c9a19ee5ef1fad681d69f0b992 Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Mon, 18 Nov 2024 11:51:49 +0100 Subject: [PATCH 06/10] Use an arrow function in chunk method --- src/CollectionTrait.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/CollectionTrait.php b/src/CollectionTrait.php index 5526b27..06bc535 100644 --- a/src/CollectionTrait.php +++ b/src/CollectionTrait.php @@ -42,9 +42,7 @@ public function chunk(int $size): array } return array_map( - static function(array $chunk) { - return self::fromIterable($chunk); - }, + static fn(array $chunk) => self::fromIterable($chunk), array_chunk($this->toArray(), $size) ); } From 9e974f65370065cbbb393817c9596c177c72a45a Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Mon, 18 Nov 2024 13:18:53 +0100 Subject: [PATCH 07/10] Update based on PR feedback --- README.md | 6 ------ docs/collection-interfaces.md | 2 +- docs/collection-trait.md | 4 ++-- src/CollectionTrait.php | 2 +- tests/CollectionTest.php | 18 ++++++++++-------- 5 files changed, 14 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f2d555b..7a586db 100644 --- a/README.md +++ b/README.md @@ -33,12 +33,6 @@ composer install composer test-coverage ``` -To run tests in a docker container (without coverage): - -```bash -docker run -it --rm --workdir /app --volume .:/app php:8.1 php vendor/bin/phpunit tests/ -``` - ## Usage The library defines interfaces to deal with collections and also boilerplate code with default implementations. diff --git a/docs/collection-interfaces.md b/docs/collection-interfaces.md index e10911b..1e3cbbe 100644 --- a/docs/collection-interfaces.md +++ b/docs/collection-interfaces.md @@ -51,7 +51,7 @@ $collection->add($item1)->add($item2); public function chunk(int $size): array ``` -This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current Collection based on the chunk size provided. +This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current collection based on the chunk size provided. ### diff diff --git a/docs/collection-trait.md b/docs/collection-trait.md index 89d6ae1..d312c7d 100644 --- a/docs/collection-trait.md +++ b/docs/collection-trait.md @@ -97,7 +97,7 @@ Internally it is call the `ArrayIterator::append` and returning the instance to ## chunk -This method [mirrors the behavior of `array_chunk`](https://www.php.net/manual/function.array-chunk.php) and returns a zero indexed numeric array of the current Collection based on the chunk size provided. +Internally this method chunks [a copy](https://www.php.net/manual/arrayobject.getarraycopy.php) of the collection with the [`array_chunk` php function](https://www.php.net/manual/function.array-chunk.php), returning a zero indexed array of collections of the same type as the initial one. ## diff @@ -123,7 +123,7 @@ Internally, this method will iterate through each item of a collection, optional ## eachChunk -This method chunks the collection and executes the given anonymous function with each chunk. +Internally, this method calls the [chunk](#chunk) function and then executes the passed anonymous function with each chunk. ## empty diff --git a/src/CollectionTrait.php b/src/CollectionTrait.php index 06bc535..c31d169 100644 --- a/src/CollectionTrait.php +++ b/src/CollectionTrait.php @@ -43,7 +43,7 @@ public function chunk(int $size): array return array_map( static fn(array $chunk) => self::fromIterable($chunk), - array_chunk($this->toArray(), $size) + array_chunk($this->getArrayCopy(), $size) ); } diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php index 2d0d397..43c2851 100644 --- a/tests/CollectionTest.php +++ b/tests/CollectionTest.php @@ -486,11 +486,11 @@ public function testReverse(): void } #[DataProvider('chunkDataProvider')] - public function testChunk(Collection $collectionToChunk, int $chunkSize, array $expectedChunks): void + public function testChunk(Collection $collection, int $chunkSize, array $expectedChunks): void { self::assertEquals( $expectedChunks, - $collectionToChunk->chunk($chunkSize) + $collection->chunk($chunkSize) ); } @@ -603,14 +603,16 @@ public static function eachDataProvider(): array } #[DataProvider('chunkEachDataProvider')] - public function testChunkEach(Collection $collectionToChunk, int $chunkSize, array $expectedChunks): void + public function testChunkEach(Collection $collection, int $chunkSize, array $expectedChunks): void { - $expectedLambda = function(CollectionStub $collection) use ($expectedChunks): void { - static $i = 0; - self::assertEquals($collection, $expectedChunks[$i++]); - }; + $i = 0; - $collectionToChunk->eachChunk($chunkSize, $expectedLambda); + $collection->eachChunk( + $chunkSize, + function(CollectionStub $collection) use (&$i, $expectedChunks): void { + self::assertEquals($collection, $expectedChunks[$i++]); + } + ); } public static function chunkEachDataProvider(): array From 1a43ac21ff1512d7f881b3509c8a015c4c542503 Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Mon, 18 Nov 2024 13:24:27 +0100 Subject: [PATCH 08/10] fix typo --- docs/collection-trait.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/collection-trait.md b/docs/collection-trait.md index d312c7d..f3125ba 100644 --- a/docs/collection-trait.md +++ b/docs/collection-trait.md @@ -123,7 +123,7 @@ Internally, this method will iterate through each item of a collection, optional ## eachChunk -Internally, this method calls the [chunk](#chunk) function and then executes the passed anonymous function with each chunk. +Internally, this method calls the [chunk](#chunk) method and then executes the passed anonymous function with each chunk. ## empty From 8201081872ddf77195093c7b79068219bb28520f Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Mon, 18 Nov 2024 13:42:33 +0100 Subject: [PATCH 09/10] Update docs for eachChunk --- docs/collection-interfaces.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/collection-interfaces.md b/docs/collection-interfaces.md index 1e3cbbe..d26a1d7 100644 --- a/docs/collection-interfaces.md +++ b/docs/collection-interfaces.md @@ -92,7 +92,13 @@ function(mixed $element, string|float|int|bool|null $elementKey): void; public function eachChunk(int $size, callable $function): self|static ``` -This method chunks the collection and executes the given anonymous function with each chunk. +This method chunks the collection using the passed `$size` and executes the given anonymous function with each chunk. + +Callable signature: + +```php +function(CollectionInterface $collection): void; +``` ### empty From 7e504434c3ad87877fe3981867267f673806f6dc Mon Sep 17 00:00:00 2001 From: Tyler Ashton Date: Mon, 18 Nov 2024 13:48:32 +0100 Subject: [PATCH 10/10] update w/ PR feedback --- docs/collection-trait.md | 2 +- tests/CollectionTest.php | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/docs/collection-trait.md b/docs/collection-trait.md index f3125ba..2f5aec1 100644 --- a/docs/collection-trait.md +++ b/docs/collection-trait.md @@ -97,7 +97,7 @@ Internally it is call the `ArrayIterator::append` and returning the instance to ## chunk -Internally this method chunks [a copy](https://www.php.net/manual/arrayobject.getarraycopy.php) of the collection with the [`array_chunk` php function](https://www.php.net/manual/function.array-chunk.php), returning a zero indexed array of collections of the same type as the initial one. +Internally this method chunks the collection (by getting a copy with [getArrayCopy](https://www.php.net/manual/en/arrayiterator.getarraycopy.php) method) with the PHP [array_chunk](https://www.php.net/manual/function.array-chunk.php) function, returning a zero indexed array of collections of the same type as the initial one. ## diff diff --git a/tests/CollectionTest.php b/tests/CollectionTest.php index 43c2851..1c87f4f 100644 --- a/tests/CollectionTest.php +++ b/tests/CollectionTest.php @@ -488,10 +488,7 @@ public function testReverse(): void #[DataProvider('chunkDataProvider')] public function testChunk(Collection $collection, int $chunkSize, array $expectedChunks): void { - self::assertEquals( - $expectedChunks, - $collection->chunk($chunkSize) - ); + self::assertEquals($expectedChunks, $collection->chunk($chunkSize)); } public static function chunkDataProvider(): array