Skip to content

[8.x] Add Eloquent builder whereMorphedTo method to streamline finding models morphed to another model#38668

Merged
taylorotwell merged 2 commits into
laravel:8.xfrom
tobyzerner:where-morphed-to
Sep 7, 2021
Merged

[8.x] Add Eloquent builder whereMorphedTo method to streamline finding models morphed to another model#38668
taylorotwell merged 2 commits into
laravel:8.xfrom
tobyzerner:where-morphed-to

Conversation

@tobyzerner
Copy link
Copy Markdown
Contributor

@tobyzerner tobyzerner commented Sep 4, 2021

This PR adds whereMorphedTo and orWhereMorphedTo methods to the Eloquent Builder.

These methods are a shortcut for adding a where condition looking for models that are morphed to a specific related model, without the overhead of a whereHas subquery.

As an example, consider the following model:

class Feedback extends Model 
{
    public function subject() 
    {
        return $this->morphTo();
    }
}

Say we want to find feedback which is about a specific $model. One way to do this is to use whereHas:

$feedback = Feedback::whereHas('subject', [$model->getMorphClass()], function ($query) use ($model) {
    $query->where('id', $model);
})->get();

However, this is verbose and adds an unnecessary subquery. The information we want to constrain against is already in the feedback table. So, a more performant way would be to do this:

$feedback = Feedback::query()
    ->where('subject_type', $model->getMorphClass())
    ->where('subject_id', $model->getKey())
    ->get();

This is better, but it's still rather verbose. Also, the subject_type and subject_id columns are hard-coded – it would be better if we didn't have to worry about them and could automatically use the column names defined on the MorphTo relationship itself.

With this PR, the above can be replaced by this:

$feedback = Feedback::whereMorphedTo('subject', $model)->get();

It adds the same where clause, but is much simpler to read/write, and uses the column names defined on the MorphTo relationship.

@taylorotwell
Copy link
Copy Markdown
Member

I think it may be useful to be able to pass a string as the model name as well? ->whereMorphedTo('subject', Feedback::class);

@tobyzerner
Copy link
Copy Markdown
Contributor Author

tobyzerner commented Sep 6, 2021

Done. Not sure why the tests are failing in that particular instance, but it doesn't seem to have to do with the PR.

@GrahamCampbell GrahamCampbell reopened this Sep 6, 2021
@taylorotwell taylorotwell merged commit b3811be into laravel:8.x Sep 7, 2021
@tobyzerner tobyzerner deleted the where-morphed-to branch September 8, 2021 02:51
victorvilella pushed a commit to cdsistemas/framework that referenced this pull request Oct 12, 2021
…ing models morphed to another model (laravel#38668)

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

* Add ability to pass string as the model name

return $this->where(function ($query) use ($relation, $model) {
$query->where($relation->getMorphType(), $model->getMorphClass())
->where($relation->getForeignKeyName(), $model->getKey());
Copy link
Copy Markdown
Collaborator

@GrahamCampbell GrahamCampbell Mar 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this wrong if the relation uses something other than the model key as the owner key? $model->getKey() should be $relation->getRelatedKeyFrom($model)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants