Skip to content

Commit

Permalink
Use InteractsWithDictionary in Eloquent collection
Browse files Browse the repository at this point in the history
This improves the behaviour of database collections when using non-scalar primary keys by using the same dictionary behaviour used elsewhere.
  • Loading branch information
alcaeus committed Feb 21, 2023
1 parent 975807b commit d7f2afb
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 6 deletions.
15 changes: 9 additions & 6 deletions src/Illuminate/Database/Eloquent/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Contracts\Queue\QueueableCollection;
use Illuminate\Contracts\Queue\QueueableEntity;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Relations\Concerns\InteractsWithDictionary;
use Illuminate\Support\Arr;
use Illuminate\Support\Collection as BaseCollection;
use LogicException;
Expand All @@ -17,6 +18,8 @@
*/
class Collection extends BaseCollection implements QueueableCollection
{
use InteractsWithDictionary;

/**
* Find a model in the collection by key.
*
Expand Down Expand Up @@ -322,7 +325,7 @@ public function merge($items)
$dictionary = $this->getDictionary();

foreach ($items as $item) {
$dictionary[$item->getKey()] = $item;
$dictionary[$this->getDictionaryKey($item->getKey())] = $item;
}

return new static(array_values($dictionary));
Expand Down Expand Up @@ -398,7 +401,7 @@ public function diff($items)
$dictionary = $this->getDictionary($items);

foreach ($this->items as $item) {
if (! isset($dictionary[$item->getKey()])) {
if (! isset($dictionary[$this->getDictionaryKey($item->getKey())])) {
$diff->add($item);
}
}
Expand All @@ -423,7 +426,7 @@ public function intersect($items)
$dictionary = $this->getDictionary($items);

foreach ($this->items as $item) {
if (isset($dictionary[$item->getKey()])) {
if (isset($dictionary[$this->getDictionaryKey($item->getKey())])) {
$intersect->add($item);
}
}
Expand Down Expand Up @@ -459,7 +462,7 @@ public function only($keys)
return new static($this->items);
}

$dictionary = Arr::only($this->getDictionary(), $keys);
$dictionary = Arr::only($this->getDictionary(), array_map($this->getDictionaryKey(...), (array) $keys));

return new static(array_values($dictionary));
}
Expand All @@ -472,7 +475,7 @@ public function only($keys)
*/
public function except($keys)
{
$dictionary = Arr::except($this->getDictionary(), $keys);
$dictionary = Arr::except($this->getDictionary(), array_map($this->getDictionaryKey(...), (array) $keys));

return new static(array_values($dictionary));
}
Expand Down Expand Up @@ -545,7 +548,7 @@ public function getDictionary($items = null)
$dictionary = [];

foreach ($items as $value) {
$dictionary[$value->getKey()] = $value;
$dictionary[$this->getDictionaryKey($value->getKey())] = $value;
}

return $dictionary;
Expand Down
31 changes: 31 additions & 0 deletions tests/Database/DatabaseEloquentCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,25 @@ public function testLoadExistsShouldCastBool()
$this->assertContainsOnly('bool', $commentsExists);
}

public function testWithNonScalarKey()
{
$fooKey = new EloquentTestKey('foo');
$foo = m::mock(Model::class);
$foo->shouldReceive('getKey')->andReturn($fooKey);

$barKey = new EloquentTestKey('bar');
$bar = m::mock(Model::class);
$bar->shouldReceive('getKey')->andReturn($barKey);

$collection = new Collection([$foo, $bar]);

$this->assertCount(1, $collection->only([$fooKey]));
$this->assertSame($foo, $collection->only($fooKey)->first());

$this->assertCount(1, $collection->except([$fooKey]));
$this->assertSame($bar, $collection->except($fooKey)->first());
}

/**
* Helpers...
*/
Expand Down Expand Up @@ -689,3 +708,15 @@ class EloquentTestCommentModel extends Model
protected $guarded = [];
public $timestamps = false;
}

class EloquentTestKey
{
public function __construct(private readonly string $key)
{
}

public function __toString()
{
return $this->key;
}
}

0 comments on commit d7f2afb

Please sign in to comment.