Skip to content

Commit 538732d

Browse files
author
Robert Kujawa
authored
[8.x] Add firstOr() function to BelongsToMany relation (#40828)
* Add firstOr() function to BelongsToMany relation * Add firstOr() test on BelongsToMany relation
1 parent d037fc5 commit 538732d

File tree

2 files changed

+65
-0
lines changed

2 files changed

+65
-0
lines changed

src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Illuminate\Database\Eloquent\Relations;
44

5+
use Closure;
56
use Illuminate\Contracts\Support\Arrayable;
67
use Illuminate\Database\Eloquent\Builder;
78
use Illuminate\Database\Eloquent\Collection;
@@ -752,6 +753,28 @@ public function firstOrFail($columns = ['*'])
752753
throw (new ModelNotFoundException)->setModel(get_class($this->related));
753754
}
754755

756+
/**
757+
* Execute the query and get the first result or call a callback.
758+
*
759+
* @param \Closure|array $columns
760+
* @param \Closure|null $callback
761+
* @return \Illuminate\Database\Eloquent\Model|static|mixed
762+
*/
763+
public function firstOr($columns = ['*'], Closure $callback = null)
764+
{
765+
if ($columns instanceof Closure) {
766+
$callback = $columns;
767+
768+
$columns = ['*'];
769+
}
770+
771+
if (! is_null($model = $this->first($columns))) {
772+
return $model;
773+
}
774+
775+
return $callback();
776+
}
777+
755778
/**
756779
* Get the results of the relationship.
757780
*

tests/Integration/Database/EloquentBelongsToManyTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ protected function defineDatabaseMigrationsAfterDatabaseRefreshed()
3838
});
3939

4040
Schema::create('users_posts', function (Blueprint $table) {
41+
$table->increments('id');
4142
$table->string('user_uuid');
4243
$table->string('post_uuid');
4344
$table->tinyInteger('is_draft')->default(1);
@@ -932,6 +933,33 @@ public function testOrderByPivotMethod()
932933
$relationTag2 = $post->tagsWithCustomExtraPivot()->orderByPivot('flag', 'desc')->first();
933934
$this->assertEquals($relationTag2->getAttributes(), $tag3->getAttributes());
934935
}
936+
937+
public function testFirstOrMethod()
938+
{
939+
$user1 = User::create(['name' => Str::random()]);
940+
$user2 = User::create(['name' => Str::random()]);
941+
$user3 = User::create(['name' => Str::random()]);
942+
$post1 = Post::create(['title' => Str::random()]);
943+
$post2 = Post::create(['title' => Str::random()]);
944+
$post3 = Post::create(['title' => Str::random()]);
945+
946+
$user1->posts()->sync([$post1->uuid, $post2->uuid]);
947+
$user2->posts()->sync([$post1->uuid, $post2->uuid]);
948+
949+
$this->assertEquals(
950+
$post1->id,
951+
$user2->posts()->firstOr(function () {
952+
return Post::create(['title' => Str::random()]);
953+
})->id
954+
);
955+
956+
$this->assertEquals(
957+
$post3->id,
958+
$user3->posts()->firstOr(function () use ($post3) {
959+
return $post3;
960+
})->id
961+
);
962+
}
935963
}
936964

937965
class User extends Model
@@ -949,6 +977,13 @@ protected static function boot()
949977
});
950978
}
951979

980+
public function posts()
981+
{
982+
return $this->belongsToMany(Post::class, 'users_posts', 'user_uuid', 'post_uuid', 'uuid', 'uuid')
983+
->withPivot('is_draft')
984+
->withTimestamps();
985+
}
986+
952987
public function postsWithCustomPivot()
953988
{
954989
return $this->belongsToMany(Post::class, 'users_posts', 'user_uuid', 'post_uuid', 'uuid', 'uuid')
@@ -974,6 +1009,13 @@ protected static function boot()
9741009
});
9751010
}
9761011

1012+
public function users()
1013+
{
1014+
return $this->belongsToMany(User::class, 'users_posts', 'post_uuid', 'user_uuid', 'uuid', 'uuid')
1015+
->withPivot('is_draft')
1016+
->withTimestamps();
1017+
}
1018+
9771019
public function tags()
9781020
{
9791021
return $this->belongsToMany(Tag::class, 'posts_tags', 'post_id', 'tag_id')

0 commit comments

Comments
 (0)