Skip to content

Commit

Permalink
[8.x] Add firstOr() function to BelongsToMany relation (#40828)
Browse files Browse the repository at this point in the history
* Add firstOr() function to BelongsToMany relation

* Add firstOr() test on BelongsToMany relation
  • Loading branch information
Robert Kujawa authored Feb 11, 2022
1 parent d037fc5 commit 538732d
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Illuminate\Database\Eloquent\Relations;

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

/**
* Execute the query and get the first result or call a callback.
*
* @param \Closure|array $columns
* @param \Closure|null $callback
* @return \Illuminate\Database\Eloquent\Model|static|mixed
*/
public function firstOr($columns = ['*'], Closure $callback = null)
{
if ($columns instanceof Closure) {
$callback = $columns;

$columns = ['*'];
}

if (! is_null($model = $this->first($columns))) {
return $model;
}

return $callback();
}

/**
* Get the results of the relationship.
*
Expand Down
42 changes: 42 additions & 0 deletions tests/Integration/Database/EloquentBelongsToManyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ protected function defineDatabaseMigrationsAfterDatabaseRefreshed()
});

Schema::create('users_posts', function (Blueprint $table) {
$table->increments('id');
$table->string('user_uuid');
$table->string('post_uuid');
$table->tinyInteger('is_draft')->default(1);
Expand Down Expand Up @@ -932,6 +933,33 @@ public function testOrderByPivotMethod()
$relationTag2 = $post->tagsWithCustomExtraPivot()->orderByPivot('flag', 'desc')->first();
$this->assertEquals($relationTag2->getAttributes(), $tag3->getAttributes());
}

public function testFirstOrMethod()
{
$user1 = User::create(['name' => Str::random()]);
$user2 = User::create(['name' => Str::random()]);
$user3 = User::create(['name' => Str::random()]);
$post1 = Post::create(['title' => Str::random()]);
$post2 = Post::create(['title' => Str::random()]);
$post3 = Post::create(['title' => Str::random()]);

$user1->posts()->sync([$post1->uuid, $post2->uuid]);
$user2->posts()->sync([$post1->uuid, $post2->uuid]);

$this->assertEquals(
$post1->id,
$user2->posts()->firstOr(function () {
return Post::create(['title' => Str::random()]);
})->id
);

$this->assertEquals(
$post3->id,
$user3->posts()->firstOr(function () use ($post3) {
return $post3;
})->id
);
}
}

class User extends Model
Expand All @@ -949,6 +977,13 @@ protected static function boot()
});
}

public function posts()
{
return $this->belongsToMany(Post::class, 'users_posts', 'user_uuid', 'post_uuid', 'uuid', 'uuid')
->withPivot('is_draft')
->withTimestamps();
}

public function postsWithCustomPivot()
{
return $this->belongsToMany(Post::class, 'users_posts', 'user_uuid', 'post_uuid', 'uuid', 'uuid')
Expand All @@ -974,6 +1009,13 @@ protected static function boot()
});
}

public function users()
{
return $this->belongsToMany(User::class, 'users_posts', 'post_uuid', 'user_uuid', 'uuid', 'uuid')
->withPivot('is_draft')
->withTimestamps();
}

public function tags()
{
return $this->belongsToMany(Tag::class, 'posts_tags', 'post_id', 'tag_id')
Expand Down

0 comments on commit 538732d

Please sign in to comment.