Skip to content

Commit

Permalink
Added findOrFail to Hyperf\Database\Model\Collection (#7192)
Browse files Browse the repository at this point in the history
  • Loading branch information
People-Sea authored Dec 12, 2024
1 parent 1df8908 commit a16b070
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/Model/Collection.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
use Hyperf\Stringable\Str;
use RuntimeException;

use function Hyperf\Collection\head;
use function Hyperf\Support\value;

/**
Expand Down Expand Up @@ -63,6 +64,37 @@ public function find($key, $default = null)
}, $default);
}

/**
* Find a model in the collection by key or throw an exception.
*
* @return TModel
*
* @throws ModelNotFoundException
*/
public function findOrFail(mixed $key)
{
$result = $this->find($key);

if (is_array($key) && count($result) === count(array_unique($key))) {
return $result;
}
if (! is_array($key) && ! is_null($result)) {
return $result;
}

$exception = new ModelNotFoundException();

if (! $model = head($this->items)) {
throw $exception;
}

$ids = is_array($key) ? array_diff($key, $result->modelKeys()) : $key;

$exception->setModel(get_class($model), $ids);

throw $exception;
}

/**
* Load a set of relationships onto the collection.
*
Expand Down
54 changes: 54 additions & 0 deletions tests/ModelCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Hyperf\Database\ConnectionResolverInterface;
use Hyperf\Database\Model\Collection;
use Hyperf\Database\Model\Model;
use Hyperf\Database\Model\ModelNotFoundException;
use Hyperf\Database\Model\Register;
use Hyperf\Database\Schema\Schema;
use Hyperf\Engine\Channel;
Expand Down Expand Up @@ -239,6 +240,59 @@ public function testFindMethodFindsManyModelsById()
$this->assertEquals([2, 3], $c->find([2, 3, 4])->pluck('id')->all());
}

public function testFindOrFailFindsModelById()
{
$mockModel = m::mock(Model::class);
$mockModel->shouldReceive('getKey')->andReturn(1);
$c = new Collection([$mockModel]);

$this->assertSame($mockModel, $c->findOrFail(1));
}

public function testFindOrFailFindsManyModelsById()
{
$model1 = (new TestUserModel())->forceFill(['id' => 1]);
$model2 = (new TestUserModel())->forceFill(['id' => 2]);

$c = new Collection();
$this->assertInstanceOf(Collection::class, $c->findOrFail([]));
$this->assertCount(0, $c->findOrFail([]));

$c->push($model1);
$this->assertCount(1, $c->findOrFail([1]));
$this->assertEquals(1, $c->findOrFail([1])->first()->id);

$c->push($model2);
$this->assertCount(2, $c->findOrFail([1, 2]));

$this->expectException(ModelNotFoundException::class);
$this->expectExceptionMessage('No query results for model [HyperfTest\Database\TestUserModel] 3');

$c->findOrFail([1, 2, 3]);
}

public function testFindOrFailThrowsExceptionWithMessageWhenOtherModelsArePresent()
{
$model = (new TestUserModel())->forceFill(['id' => 1]);

$c = new Collection([$model]);

$this->expectException(ModelNotFoundException::class);
$this->expectExceptionMessage('No query results for model [HyperfTest\Database\TestUserModel] 2');

$c->findOrFail(2);
}

public function testFindOrFailThrowsExceptionWithoutMessageWhenOtherModelsAreNotPresent()
{
$c = new Collection();

$this->expectException(ModelNotFoundException::class);
$this->expectExceptionMessage('');

$c->findOrFail(1);
}

public function testLoadMethodEagerLoadsGivenRelationships()
{
$c = $this->getMockBuilder(Collection::class)->onlyMethods(['first'])->setConstructorArgs([['foo']])->getMock();
Expand Down

0 comments on commit a16b070

Please sign in to comment.