Skip to content
This repository was archived by the owner on Jul 16, 2021. It is now read-only.
This repository was archived by the owner on Jul 16, 2021. It is now read-only.

Naive implementation of WhereHas with Polymorphic relations #1651

Closed
@timacdonald

Description

@timacdonald

I have wanted to be able to query polymorphic relations with the whereHas method, as I'm sure anyone using them has also wanted to.

I came across this article that shows a way to implement this in your app: https://zaengle.com/blog/using-wherehas-in-laravel-polymorphic-relations

That article (which is awesome) shows an implementation that requires you to add a new method for each new type of relation, so not something the framework can really handle for you.

I hacked on this for some time and came up with the following implementation that allows you to specify a whereHas and provide the class type you want to filter against. Because this is a bit more of a dynamic approach that could be applied to all apps, I thought I'd at least float the idea here, after all...this is laravel/ideas

This is working well for me in my applications, but I'm aware I've only used it, and tested it, against its happy path. I would love someone with better knowledge of the query builder, and database queries in general, to roast this thing and pull it apart before I try and PR it to the core.

How it could look on a model...

$events = Event::whereEventable(Post::class, function ($query) {
    $query->wherePublished();
})->etc(...);

You do have to be specific about the class you are checking against, but multiple checks can be chained...

$events = Event::whereEventable(Post::class, function ($query) {
    $query->wherePublished();
})->orWhere->whereEventable(Comment::class, function ($query) {
    $query->wherePublished();
})->etc(...);

With this 👆 it should be possible to allow you to pass in an array of classes, and handle the check against multiple classes instead of having to repeat the closure logic, but I'll implement that if this looks okay to people.

So although I have not yet implemented it, it should be possible to do this...

$classes = [Post::class, Comment::class];

$events = Event::whereEventable($classes, function ($query) {
    $query->wherePublished();
})->etc(...);

It also handles morph map values...

Relation::morphMap(['posties' => Post::class]);

$events = Event::whereEventable('posties', function ($query) {
    $query->wherePublished();
})->etc(...);

I threw it all in this gist, so jump in and check it out, and please point out how this is not ever going to work.

Gist: https://gist.github.com/timacdonald/128e7d150f7214b51a030193d3d2b937

I know the naming isn't great. If this was PR'd I assume it would have a more generic name like whereHasPolymorphic(...) rather than my generic filterPolymorphicRelation(...). It'll also be on the eloquent query builder, not on the model.

@staudenmeir no doubt you are busy, but if you have a few minutes to look at this it would be great! Just ping'ing you as I know you have a really strong knowledge of the query builder. (P.S. thanks for all the work you do on Laravel)

I guess it'd also be handy to know if others think this would even be useful. No point having it in core if only a handful of people are gonna use it.

I'll also work out a way to specify the full key and type columns. But don't wanna do that work if this is just a non-starter.

This approach still requires the developer to add a wrapping method whereEventable In this example, but the underlying helper on the query builder I think would useful.

This is a previous thread that is probably useful to reference as well: laravel/framework#18523

No doubt performance is going to be a concern

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions