Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

chrisgrim's avatar

How to add a where() statement to a morphTo()

Hi, I have setup a polymorphic relationship. In my Feature.php I have

/**
     * Get the model to be featured
     */
    public function featureable()
    {
        return $this->morphTo();
    }

One of the models I can morph to is a post. What if I only want to grab the Post models that have a status of 'p'. I tried doing

return $this->morphTo()->where('status', 'p');

but it didn't return it correctly.

0 likes
11 replies
chrisgrim's avatar

@michaloravec I might have been a bit too fast. I tried

return Section::first()->featured()->whereHasMorph(
            'featureable',
            [Listing::class],
            function (Builder $query) {
                $query->where('status', 'like', 'p');
            }
        )->get();

In my section.php I have

public function featured()
    {
        return $this->belongsToMany(Feature::class)->withPivot('order')->orderBy('order', 'ASC');
    }

and in my feature.php I have

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

but I get an error message

Argument 1 passed to App\Http\Controllers\Curated\CommunityController::App\Http\Controllers\Curated\{closure}() must be an instance of App\Http\Controllers\Curated\Builder, instance of Illuminate\Database\Eloquent\Builder given, called in /Users/chrisgrim/code/ei/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Concerns/QueriesRelationships.php on line 222
MichalOravec's avatar

Remove Builder from that function

return Section::first()->featured()->whereHasMorph('featureable', 
	[Listing::class],
	function ($query) {
        $query->where('status', 'like', 'p');
})->get();

Or import proper class.

Everything is in the documentation...

chrisgrim's avatar

Ahh ok I need to read up on builders more

chrisgrim's avatar

@michaloravec Sorry to keep bothering you but I feel like I am learning and understanding it more. I did some more testing and see that only

Section::first()->featured()->whereHasMorph(
            'featureable',
            [Listing::class, Event::class],
            function ($query) {
                $query->where('status', 'like', 'p');
            }
        )->get();

works because it is a single section. However if I do

return $community->sections()->featured()->whereHasMorph(
            'featureable',
            [Listing::class, Event::class],
            function ($query) {
                $query->where('status', 'like', 'p');
            }
        )->get();

it doesn't work because I am grabbing multiple sections. I would need to do something like

$community->sections()->with('featured')

Which makes me think I need to at the whereHasMorph into my feature model and call it like

$community->sections()->with('featured.liveFeatured')

and then in my feature.php have

public function liveFeatured()
    {
        return $this->whereHasMorph(
            'featureable',
            [Listing::class, Event::class],
            function ($query) {
                $query->where('status', 'like', 'p');
            }
        );
    }

but I am getting a Call to undefined method Illuminate\Database\Eloquent\Builder::addEagerConstraints()

MichalOravec's avatar

liveFeatured is not a relationship, only relationships could be eager loaded.

chrisgrim's avatar

Sorry @michaloravec I just figured it out

public function liveFeatured()
    {
        return $this->morphTo()->whereHasMorph(
            'featureable',
            [Listing::class, Event::class],
            function ($query) {
                $query->where('status', 'like', 'p');
            }
        );
    }

Thanks again for all your help!

chrisgrim's avatar

@michaloravec Again I spoke to soon. If I do

public function liveFeatured()
{
return $this->morphTo()->whereHasMorph(
            'featureable',
            [Listing::class, Event::class],
            function ($query) {
                $query->where('status', 'like', 'p');
            }
        );

and then

$sections = $community->sections()->with('featured.liveFeatured')->get();

it returns

{
"id": 1,
"user_id": 1,
"container_type": "App\Models\Curated\Community",
"container_id": 1,
"name": "Section1",
"order": 0,
"created_at": "2021-08-12T22:23:32.000000Z",
"updated_at": "2021-08-12T22:23:53.000000Z",
"featured": [
{
"id": 1,
"user_id": 1,
"type": "l",
"featureable_type": "App\Models\Curated\Listing",
"featureable_id": 1,
"created_at": "2021-08-12T22:26:00.000000Z",
"updated_at": "2021-08-12T22:26:00.000000Z",
"pivot": {
"section_id": 1,
"feature_id": 1,
"order": 0
},
"featureable": {
"id": 1,
"slug": "this-is-a-listing-1",
"name": "This is a listing",
"blurb": "swzszsxxs",
"community_id": 1,
"user_id": 1,
"largeImagePath": null,
"thumbImagePath": null,
"status": "d",
"order": 0,
"created_at": "2021-08-12T22:26:00.000000Z",
"updated_at": "2021-08-12T22:26:00.000000Z"
},
"live_featured": null
},

as you can see the featureable has a status of 'd' but it is still being returned.

Jaytee's avatar

Would this not work, like any other relation query??

$sections = $community->sections()->with(['featured.liveFeatured' => function ($q) {
    $q->where('status', 'like', 'p'); // Is this your intention? Or
    $q->where('status', 'p');
}])->get();
chrisgrim's avatar

Hi @jaytee I actually just got it figured out. I was adding it to the wrong model. Instead of adding it to my featured model I had to add it to my sections model

//Section.php

public function publicFeatured()
    {
        return $this->belongsToMany(Feature::class)->withPivot('order')->orderBy('order', 'ASC')->whereHasMorph(
            'featureable',
            [Listing::class, Event::class],
            function ($query) {
                $query->where('status', 'like', 'p');
            }
        );
    }

Please or to participate in this conversation.