Skip to content

Commit

Permalink
Allow groupBy to work with enums. (cakephp#17574)
Browse files Browse the repository at this point in the history
Allow groupBy() to work with enums.

Remove exception for unit enums for indexBy().
  • Loading branch information
dereuromark authored Feb 8, 2024
1 parent 5ff7598 commit 9f1435a
Show file tree
Hide file tree
Showing 3 changed files with 116 additions and 5 deletions.
14 changes: 13 additions & 1 deletion src/Collection/CollectionTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,12 @@ public function groupBy(callable|string $path): CollectionInterface
'Use a callback to return a default value for that path.'
);
}
if ($pathValue instanceof BackedEnum) {
$pathValue = $pathValue->value;
} elseif ($pathValue instanceof UnitEnum) {
$pathValue = $pathValue->name;
}

$group[$pathValue][] = $value;
}

Expand All @@ -313,6 +319,12 @@ public function indexBy(callable|string $path): CollectionInterface
'Use a callback to return a default value for that path.'
);
}
if ($pathValue instanceof BackedEnum) {
$pathValue = $pathValue->value;
} elseif ($pathValue instanceof UnitEnum) {
$pathValue = $pathValue->name;
}

$group[$pathValue] = $value;
}

Expand Down Expand Up @@ -617,7 +629,7 @@ public function combine(
if ($mapKey instanceof BackedEnum) {
$mapKey = $mapKey->value;
} elseif ($mapKey instanceof UnitEnum) {
throw new InvalidArgumentException('Cannot index by path that is a non-backed enum.');
$mapKey = $mapKey->name;
}

$mapReduce->emit($rowVal($value, $key), $mapKey);
Expand Down
106 changes: 102 additions & 4 deletions tests/TestCase/Collection/CollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use TestApp\Collection\TestCollection;
use TestApp\Model\Enum\ArticleStatus;
use TestApp\Model\Enum\NonBacked;
use TestApp\Model\Enum\Priority;
use function Cake\Collection\collection;

/**
Expand Down Expand Up @@ -707,6 +708,54 @@ public function testGroupByDeepKey(): void
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests grouping by an enum key
*/
public function testGroupByEnum(): void
{
$items = [
['id' => 1, 'name' => 'foo', 'thing' => NonBacked::Basic],
['id' => 2, 'name' => 'bar', 'thing' => NonBacked::Advanced],
['id' => 3, 'name' => 'baz', 'thing' => NonBacked::Basic],
];
$collection = new Collection($items);
$grouped = $collection->groupBy('thing');
$expected = [
NonBacked::Basic->name => [
['id' => 1, 'name' => 'foo', 'thing' => NonBacked::Basic],
['id' => 3, 'name' => 'baz', 'thing' => NonBacked::Basic],
],
NonBacked::Advanced->name => [
['id' => 2, 'name' => 'bar', 'thing' => NonBacked::Advanced],
],
];
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests grouping by a backed enum key
*/
public function testGroupByBackedEnum(): void
{
$items = [
['id' => 1, 'name' => 'foo', 'thing' => Priority::Medium],
['id' => 2, 'name' => 'bar', 'thing' => Priority::High],
['id' => 3, 'name' => 'baz', 'thing' => Priority::Medium],
];
$collection = new Collection($items);
$grouped = $collection->groupBy('thing');
$expected = [
Priority::Medium->value => [
['id' => 1, 'name' => 'foo', 'thing' => Priority::Medium],
['id' => 3, 'name' => 'baz', 'thing' => Priority::Medium],
],
Priority::High->value => [
['id' => 2, 'name' => 'bar', 'thing' => Priority::High],
],
];
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests passing an invalid path to groupBy.
*/
Expand All @@ -721,6 +770,7 @@ public function testGroupByInvalidPath(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot group by path that does not exist or contains a null value.');

$collection->groupBy('missing');
}

Expand Down Expand Up @@ -780,6 +830,46 @@ public function testIndexByCallback(iterable $items): void
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests indexBy with an enum
*/
public function testIndexByEnum(): void
{
$items = [
['id' => 1, 'name' => 'foo', 'thing' => NonBacked::Basic],
['id' => 2, 'name' => 'bar', 'thing' => NonBacked::Advanced],
];
$collection = new Collection($items);
$grouped = $collection->indexBy(function ($element) {
return $element['thing'];
});
$expected = [
NonBacked::Basic->name => ['id' => 1, 'name' => 'foo', 'thing' => NonBacked::Basic],
NonBacked::Advanced->name => ['id' => 2, 'name' => 'bar', 'thing' => NonBacked::Advanced],
];
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests indexBy with a backed enum
*/
public function testIndexByBackedEnum(): void
{
$items = [
['id' => 1, 'name' => 'foo', 'thing' => Priority::Medium],
['id' => 2, 'name' => 'bar', 'thing' => Priority::High],
];
$collection = new Collection($items);
$grouped = $collection->indexBy(function ($element) {
return $element['thing'];
});
$expected = [
Priority::Medium->value => ['id' => 1, 'name' => 'foo', 'thing' => Priority::Medium],
Priority::High->value => ['id' => 2, 'name' => 'bar', 'thing' => Priority::High],
];
$this->assertEquals($expected, iterator_to_array($grouped));
}

/**
* Tests indexBy with a deep property
*/
Expand Down Expand Up @@ -813,6 +903,7 @@ public function testIndexByInvalidPath(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot index by path that does not exist or contains a null value');

$collection->indexBy('missing');
}

Expand All @@ -830,6 +921,7 @@ public function testIndexByInvalidPathCallback(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot index by path that does not exist or contains a null value');

$collection->indexBy(function ($e) {
return null;
});
Expand Down Expand Up @@ -1279,12 +1371,11 @@ function ($value, $key) {

public function testCombineWithNonBackedEnum(): void
{
$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot index by path that is a non-backed enum.');
(new Collection([
$collection = (new Collection([
['amount' => 10, 'type' => NonBacked::Basic],
['amount' => 2, 'type' => NonBacked::Basic],
['amount' => 2, 'type' => NonBacked::Advanced],
]))->combine('type', 'amount');
$this->assertEquals(['Basic' => 10, 'Advanced' => 2], $collection->toArray());
}

public function testCombineNullKey(): void
Expand All @@ -1297,6 +1388,7 @@ public function testCombineNullKey(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot index by path that does not exist or contains a null value');

(new Collection($items))->combine('id', 'name');
}

Expand All @@ -1310,6 +1402,7 @@ public function testCombineNullGroup(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot group by path that does not exist or contains a null value');

(new Collection($items))->combine('id', 'name', 'parent');
}

Expand All @@ -1323,6 +1416,7 @@ public function testCombineGroupNullKey(): void

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('Cannot index by path that does not exist or contains a null value');

(new Collection($items))->combine('id', 'name', 'parent');
}

Expand Down Expand Up @@ -2226,8 +2320,10 @@ public function testLastNtWithCountable(): void
public function testLastNtWithNegative($data): void
{
$collection = new Collection($data);

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The takeLast method requires a number greater than 0.');

$collection->takeLast(-1)->toArray();
}

Expand Down Expand Up @@ -2580,6 +2676,7 @@ public function testCartesianProduct(): void
public function testCartesianProductMultidimensionalArray(): void
{
$this->expectException(LogicException::class);

$collection = new Collection([
[
'names' => [
Expand Down Expand Up @@ -2622,6 +2719,7 @@ public function testTranspose(): void
public function testTransposeUnEvenLengthShouldThrowException(): void
{
$this->expectException(LogicException::class);

$collection = new Collection([
['Products', '2012', '2013', '2014'],
['Product A', '200', '100', '50'],
Expand Down
1 change: 1 addition & 0 deletions tests/test_app/TestApp/Model/Enum/NonBacked.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@
enum NonBacked
{
case Basic;
case Advanced;
}

0 comments on commit 9f1435a

Please sign in to comment.