Skip to content

Commit

Permalink
Use InteractsWithDictionary in Eloquent collection (#46196)
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 authored Feb 21, 2023
1 parent 9776ba7 commit d91e03a
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 d91e03a

Please sign in to comment.