diff --git a/src/Illuminate/Database/Concerns/BuildsQueries.php b/src/Illuminate/Database/Concerns/BuildsQueries.php index 6a39b4cb8fc4..9aa590654b83 100644 --- a/src/Illuminate/Database/Concerns/BuildsQueries.php +++ b/src/Illuminate/Database/Concerns/BuildsQueries.php @@ -3,6 +3,8 @@ namespace Illuminate\Database\Concerns; use Illuminate\Container\Container; +use Illuminate\Database\MultipleRecordsFoundException; +use Illuminate\Database\NoRecordsFoundException; use Illuminate\Pagination\LengthAwarePaginator; use Illuminate\Pagination\Paginator; @@ -147,6 +149,30 @@ public function first($columns = ['*']) return $this->take(1)->get($columns)->first(); } + /** + * Execute the query and get the first result if it's the sole. + * + * @param array|string $columns + * @return \Illuminate\Database\Eloquent\Model|object|static|null + * + * @throws \Illuminate\Database\NoRecordsFoundException + * @throws \Illuminate\Database\MultipleRecordsFoundException + */ + public function sole($columns = ['*']) + { + $result = $this->take(2)->get($columns); + + if ($result->isEmpty()) { + throw new NoRecordsFoundException(); + } + + if ($result->count() > 1) { + throw new MultipleRecordsFoundException(); + } + + return $result->first(); + } + /** * Apply the callback's query changes if the given "value" is true. * diff --git a/src/Illuminate/Database/MultipleRecordsFoundException.php b/src/Illuminate/Database/MultipleRecordsFoundException.php new file mode 100755 index 000000000000..cccb7e4177bf --- /dev/null +++ b/src/Illuminate/Database/MultipleRecordsFoundException.php @@ -0,0 +1,10 @@ + '1', 'title' => 'Foo Post']; + + $this->assertEquals(1, DB::table('posts')->where('title', 'Foo Post')->sole()->id); + } + + public function testSoleFailsForMultipleRecords() + { + DB::table('posts')->insert([ + ['title' => 'Foo Post', 'content' => 'Lorem Ipsum.', 'created_at' => new Carbon('2017-11-12 13:14:15')], + ]); + + $this->expectException(MultipleRecordsFoundException::class); + + DB::table('posts')->where('title', 'Foo Post')->sole(); + } + + public function testSoleFailsIfNoRecords() + { + $this->expectException(NoRecordsFoundException::class); + + DB::table('posts')->where('title', 'Baz Post')->sole(); + } + public function testSelect() { $expected = ['id' => '1', 'title' => 'Foo Post'];