Skip to content

Commit

Permalink
[8.x] Add Eloquent builder whereMorphedTo method to streamline find…
Browse files Browse the repository at this point in the history
…ing models morphed to another model (#38668)

* Add Eloquent builder `whereMorphedTo` method to streamline finding models morphed to another model

* Add ability to pass string as the model name
  • Loading branch information
tobyzerner authored Sep 7, 2021
1 parent 07644bc commit b3811be
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,47 @@ public function orWhereMorphRelation($relation, $types, $column, $operator = nul
});
}

/**
* Add a morph-to relationship condition to the query.
*
* @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation
* @param \Illuminate\Database\Eloquent\Model|string $model
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function whereMorphedTo($relation, $model, $boolean = 'and')
{
if (is_string($relation)) {
$relation = $this->getRelationWithoutConstraints($relation);
}

if (is_string($model)) {
$morphMap = Relation::morphMap();

if (! empty($morphMap) && in_array($model, $morphMap)) {
$model = array_search($model, $morphMap, true);
}

return $this->where($relation->getMorphType(), $model, null, $boolean);
}

return $this->where(function ($query) use ($relation, $model) {
$query->where($relation->getMorphType(), $model->getMorphClass())
->where($relation->getForeignKeyName(), $model->getKey());
}, null, null, $boolean);
}

/**
* Add a morph-to relationship condition to the query with an "or where" clause.
*
* @param \Illuminate\Database\Eloquent\Relations\MorphTo|string $relation
* @param \Illuminate\Database\Eloquent\Model|string $model
* @return \Illuminate\Database\Eloquent\Builder|static
*/
public function orWhereMorphedTo($relation, $model)
{
return $this->whereMorphedTo($relation, $model, 'or');
}

/**
* Add subselect queries to include an aggregate value for a relationship.
*
Expand Down
62 changes: 62 additions & 0 deletions tests/Database/DatabaseEloquentBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Database\Eloquent\RelationNotFoundException;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Query\Builder as BaseBuilder;
use Illuminate\Database\Query\Grammars\Grammar;
Expand Down Expand Up @@ -1305,6 +1306,62 @@ public function testOrWhereDoesntHave()
$this->assertEquals(['baz', 'quux'], $builder->getBindings());
}

public function testWhereMorphedTo()
{
$model = new EloquentBuilderTestModelParentStub;
$this->mockConnectionForModel($model, '');

$relatedModel = new EloquentBuilderTestModelCloseRelatedStub;
$relatedModel->id = 1;

$builder = $model->whereMorphedTo('morph', $relatedModel);

$this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where ("morph_type" = ? and "morph_id" = ?)', $builder->toSql());
$this->assertEquals([$relatedModel->getMorphClass(), $relatedModel->getKey()], $builder->getBindings());
}

public function testOrWhereMorphedTo()
{
$model = new EloquentBuilderTestModelParentStub;
$this->mockConnectionForModel($model, '');

$relatedModel = new EloquentBuilderTestModelCloseRelatedStub;
$relatedModel->id = 1;

$builder = $model->where('bar', 'baz')->orWhereMorphedTo('morph', $relatedModel);

$this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "bar" = ? or ("morph_type" = ? and "morph_id" = ?)', $builder->toSql());
$this->assertEquals(['baz', $relatedModel->getMorphClass(), $relatedModel->getKey()], $builder->getBindings());
}

public function testWhereMorphedToClass()
{
$model = new EloquentBuilderTestModelParentStub;
$this->mockConnectionForModel($model, '');

$builder = $model->whereMorphedTo('morph', EloquentBuilderTestModelCloseRelatedStub::class);

$this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "morph_type" = ?', $builder->toSql());
$this->assertEquals([EloquentBuilderTestModelCloseRelatedStub::class], $builder->getBindings());
}

public function testWhereMorphedToAlias()
{
$model = new EloquentBuilderTestModelParentStub;
$this->mockConnectionForModel($model, '');

Relation::morphMap([
'alias' => EloquentBuilderTestModelCloseRelatedStub::class,
]);

$builder = $model->whereMorphedTo('morph', EloquentBuilderTestModelCloseRelatedStub::class);

$this->assertSame('select * from "eloquent_builder_test_model_parent_stubs" where "morph_type" = ?', $builder->toSql());
$this->assertEquals(['alias'], $builder->getBindings());

Relation::morphMap([], false);
}

public function testWhereKeyMethodWithInt()
{
$model = $this->getMockModel();
Expand Down Expand Up @@ -1793,6 +1850,11 @@ public function roles()
'related_id'
);
}

public function morph()
{
return $this->morphTo();
}
}

class EloquentBuilderTestModelCloseRelatedStub extends Model
Expand Down

0 comments on commit b3811be

Please sign in to comment.