Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ These methods enable adding, removing, and modifying elements in the Collection.
```

```php
$collection ->add('X', 'Y', 'Z');
$collection->add('X', 'Y', 'Z');
```

#### Removing elements
Expand Down
4 changes: 1 addition & 3 deletions src/Internal/Operations/Order/Sort.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ public function apply(iterable $elements): Generator
: $this->predicate;

$ascendingPredicate = static fn(mixed $first, mixed $second): int => $predicate($first, $second);
$descendingPredicate = is_null($this->predicate)
? static fn(mixed $first, mixed $second): int => $predicate($second, $first)
: $predicate;
$descendingPredicate = static fn(mixed $first, mixed $second): int => $predicate($second, $first);

match ($this->order) {
Order::ASCENDING_KEY => ksort($temporaryElements),
Expand Down
15 changes: 14 additions & 1 deletion src/Internal/Operations/Transform/JoinToString.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,19 @@ public static function from(iterable $elements): JoinToString

public function joinTo(string $separator): string
{
return implode($separator, iterator_to_array($this->elements));
$result = '';
$first = true;

foreach ($this->elements as $element) {
if ($first) {
$result = $element;
$first = false;
Comment on lines +25 to +28

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Cast first element to string before returning

The new manual join assigns the first element directly to $result and returns it when the iterable has only one element. With declare(strict_types=1), returning a non-string (e.g., Collection::createFrom([1])->joinToString(','), [null], or an object without __toString) will throw a TypeError, whereas the previous implode() behavior always produced a string. Casting the first element to string (or using implode on a built array) would preserve the prior behavior for single-element collections.

Useful? React with 👍 / 👎.

continue;
}

$result .= sprintf('%s%s', $separator, $element);
}

return $result;
}
}
23 changes: 23 additions & 0 deletions tests/Operations/Order/CollectionSortOperationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,29 @@ public function testSortDescendingByValue(iterable $elements, iterable $expected
self::assertSame($expected, $actual->toArray());
}

public function testSortDescendingByValueWithPredicate(): void
{
/** @Given a collection with unordered Amount objects */
$collection = Collection::createFrom(elements: [
new Amount(value: 100.50, currency: Currency::USD),
new Amount(value: 150.75, currency: Currency::EUR),
new Amount(value: 200.00, currency: Currency::USD)
]);

/** @When sorting the collection in descending order by value with a custom predicate */
$actual = $collection->sort(
order: Order::DESCENDING_VALUE,
predicate: static fn(Amount $first, Amount $second): int => $first->value <=> $second->value
);

/** @Then the collection should be sorted by value in descending order */
self::assertSame([
2 => ['value' => 200.00, 'currency' => Currency::USD->name],
1 => ['value' => 150.75, 'currency' => Currency::EUR->name],
0 => ['value' => 100.50, 'currency' => Currency::USD->name]
], $actual->toArray());
}

public static function ascendingKeySortDataProvider(): iterable
{
yield 'Floats ascending by key' => [
Expand Down