Skip to content

Commit a16b070

Browse files
authored
Added findOrFail to Hyperf\Database\Model\Collection (#7192)
1 parent 1df8908 commit a16b070

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

src/Model/Collection.php

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use Hyperf\Stringable\Str;
2222
use RuntimeException;
2323

24+
use function Hyperf\Collection\head;
2425
use function Hyperf\Support\value;
2526

2627
/**
@@ -63,6 +64,37 @@ public function find($key, $default = null)
6364
}, $default);
6465
}
6566

67+
/**
68+
* Find a model in the collection by key or throw an exception.
69+
*
70+
* @return TModel
71+
*
72+
* @throws ModelNotFoundException
73+
*/
74+
public function findOrFail(mixed $key)
75+
{
76+
$result = $this->find($key);
77+
78+
if (is_array($key) && count($result) === count(array_unique($key))) {
79+
return $result;
80+
}
81+
if (! is_array($key) && ! is_null($result)) {
82+
return $result;
83+
}
84+
85+
$exception = new ModelNotFoundException();
86+
87+
if (! $model = head($this->items)) {
88+
throw $exception;
89+
}
90+
91+
$ids = is_array($key) ? array_diff($key, $result->modelKeys()) : $key;
92+
93+
$exception->setModel(get_class($model), $ids);
94+
95+
throw $exception;
96+
}
97+
6698
/**
6799
* Load a set of relationships onto the collection.
68100
*

tests/ModelCollectionTest.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
use Hyperf\Database\ConnectionResolverInterface;
1818
use Hyperf\Database\Model\Collection;
1919
use Hyperf\Database\Model\Model;
20+
use Hyperf\Database\Model\ModelNotFoundException;
2021
use Hyperf\Database\Model\Register;
2122
use Hyperf\Database\Schema\Schema;
2223
use Hyperf\Engine\Channel;
@@ -239,6 +240,59 @@ public function testFindMethodFindsManyModelsById()
239240
$this->assertEquals([2, 3], $c->find([2, 3, 4])->pluck('id')->all());
240241
}
241242

243+
public function testFindOrFailFindsModelById()
244+
{
245+
$mockModel = m::mock(Model::class);
246+
$mockModel->shouldReceive('getKey')->andReturn(1);
247+
$c = new Collection([$mockModel]);
248+
249+
$this->assertSame($mockModel, $c->findOrFail(1));
250+
}
251+
252+
public function testFindOrFailFindsManyModelsById()
253+
{
254+
$model1 = (new TestUserModel())->forceFill(['id' => 1]);
255+
$model2 = (new TestUserModel())->forceFill(['id' => 2]);
256+
257+
$c = new Collection();
258+
$this->assertInstanceOf(Collection::class, $c->findOrFail([]));
259+
$this->assertCount(0, $c->findOrFail([]));
260+
261+
$c->push($model1);
262+
$this->assertCount(1, $c->findOrFail([1]));
263+
$this->assertEquals(1, $c->findOrFail([1])->first()->id);
264+
265+
$c->push($model2);
266+
$this->assertCount(2, $c->findOrFail([1, 2]));
267+
268+
$this->expectException(ModelNotFoundException::class);
269+
$this->expectExceptionMessage('No query results for model [HyperfTest\Database\TestUserModel] 3');
270+
271+
$c->findOrFail([1, 2, 3]);
272+
}
273+
274+
public function testFindOrFailThrowsExceptionWithMessageWhenOtherModelsArePresent()
275+
{
276+
$model = (new TestUserModel())->forceFill(['id' => 1]);
277+
278+
$c = new Collection([$model]);
279+
280+
$this->expectException(ModelNotFoundException::class);
281+
$this->expectExceptionMessage('No query results for model [HyperfTest\Database\TestUserModel] 2');
282+
283+
$c->findOrFail(2);
284+
}
285+
286+
public function testFindOrFailThrowsExceptionWithoutMessageWhenOtherModelsAreNotPresent()
287+
{
288+
$c = new Collection();
289+
290+
$this->expectException(ModelNotFoundException::class);
291+
$this->expectExceptionMessage('');
292+
293+
$c->findOrFail(1);
294+
}
295+
242296
public function testLoadMethodEagerLoadsGivenRelationships()
243297
{
244298
$c = $this->getMockBuilder(Collection::class)->onlyMethods(['first'])->setConstructorArgs([['foo']])->getMock();

0 commit comments

Comments
 (0)