Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.x] Add whereBelongsTo() Eloquent builder method #38927

Merged
merged 14 commits into from
Sep 28, 2021
37 changes: 37 additions & 0 deletions src/Illuminate/Database/Eloquent/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Concerns\BuildsQueries;
use Illuminate\Database\Concerns\ExplainsQueries;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\Builder as QueryBuilder;
Expand Down Expand Up @@ -305,6 +306,42 @@ public function orWhere($column, $operator = null, $value = null)
return $this->where($column, $operator, $value, 'or');
}

/**
* Add a "BelongsTo" relationship where clause to the query.
*
* @param \Illuminate\Database\Eloquent\Model $related
* @param string $relationship
* @param string $boolean
* @return $this
*
* @throws \Exception
*/
public function whereBelongsTo($related, $relationshipName = null, $boolean = 'and')
danharrin marked this conversation as resolved.
Show resolved Hide resolved
{
if ($relationshipName === null) {
$relationshipName = Str::camel(class_basename(get_class($related)));
danharrin marked this conversation as resolved.
Show resolved Hide resolved
}

try {
$relationship = $this->model->{$relationshipName}();
} catch (BadMethodCallException $exception) {
throw RelationNotFoundException::make($this->model, $relationshipName);
}

if (! $relationship instanceof BelongsTo) {
throw RelationNotFoundException::make($this->model, $relationshipName, BelongsTo::class);
}

$this->where(
danharrin marked this conversation as resolved.
Show resolved Hide resolved
$relationship->getForeignKeyName(),
danharrin marked this conversation as resolved.
Show resolved Hide resolved
'=',
$related->getAttributeValue($relationship->getOwnerKeyName()),
$boolean,
);

return $this;
}

/**
* Add an "order by" clause for a timestamp to the query.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,18 @@ class RelationNotFoundException extends RuntimeException
*
* @param object $model
* @param string $relation
* @param string $type
* @return static
*/
public static function make($model, $relation)
public static function make($model, $relation, $type = null)
{
$class = get_class($model);

$instance = new static("Call to undefined relationship [{$relation}] on model [{$class}].");
$instance = new static(
$type === null ?
"Call to undefined relationship [{$relation}] on model [{$class}]." :
"Call to undefined relationship [{$relation}] on model [{$class}] of type [{$type}].",
);

$instance->model = $class;
$instance->relation = $relation;
Expand Down
47 changes: 47 additions & 0 deletions tests/Database/DatabaseEloquentBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -906,6 +906,35 @@ public function testPostgresOperatorsWhere()
$this->assertEquals($result, $builder);
}

public function testWhereBelongsTo()
{
$related = new EloquentBuilderTestWhereBelongsToStub([
'id' => 1,
'parent_id' => 2,
]);

$parent = new EloquentBuilderTestWhereBelongsToStub([
'id' => 2,
'parent_id' => 1,
]);

$builder = $this->getBuilder();
$builder->shouldReceive('from')->with('eloquent_builder_test_where_belongs_to_stubs');
$builder->setModel($related);
$builder->getQuery()->shouldReceive('where')->once()->with('parent_id', '=', 2, 'and');

$result = $builder->whereBelongsTo($parent);
$this->assertEquals($result, $builder);

$builder = $this->getBuilder();
$builder->shouldReceive('from')->with('eloquent_builder_test_where_belongs_to_stubs');
$builder->setModel($related);
$builder->getQuery()->shouldReceive('where')->once()->with('parent_id', '=', 2, 'and');

$result = $builder->whereBelongsTo($parent, 'parent');
$this->assertEquals($result, $builder);
}

public function testDeleteOverride()
{
$builder = $this->getBuilder();
Expand Down Expand Up @@ -1948,3 +1977,21 @@ class EloquentBuilderTestStubStringPrimaryKey extends Model

protected $keyType = 'string';
}

class EloquentBuilderTestWhereBelongsToStub extends Model
{
protected $fillable = [
'id',
'parent_id',
];

public function eloquentBuilderTestWhereBelongsToStub()
{
return $this->belongsTo(self::class, 'parent_id', 'id', 'parent');
}

public function parent()
{
return $this->belongsTo(self::class, 'parent_id', 'id', 'parent');
}
}