iLC
iLC

Reputation: 339

Laravel Imageable Type and Filtering

I have a product which is imageable

Product.php

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

And a vehicle that this morphs to

public function products()
{
  return $this->morphMany('App\Product', 'imageable');
}

I can call it fine with $product->imageable->model for example, if I want to get the vehicle model.

But how would I do this in a query, specifically like this:

$products = \App\Product::where('imageable_type', 'App\Vehicle')

And

$products->where($products->imageable->make, 'Ford')

That line above is pseudocode but its the principle I'm trying to achieve, is this even possible? I essentially want to be able to filter through the vehicles by Make, but that detail resides in the imageable model for the product.

Edit, after changing my query to:

if($make = request('make')){
                $products->where('imageable_type', 'App\Vehicle')
                ->whereHas('imageable', function($query) {
                    $query->where('make', request('make'));
                });
            }

as suggested below I get the following error:

`SQLSTATE[42S22]: Column not found: 1054 Unknown column 'make' in 
'where clause' (SQL: select * from `products` where 
(`products`.`user_id` != 3 and `products`.`status` = 0) and `category` 
= Cars and `imageable_type` = App\Vehicle and exists (select * from 
`products` as `laravel_reserved_0` where `laravel_reserved_0`.`id` = 
`laravel_reserved_0`.`imageable_id` and `make` = Tesla))`

When passing make as a request parameter

Thanks

Upvotes: 0

Views: 1944

Answers (1)

Aboudeh87
Aboudeh87

Reputation: 716

try this:

\App\Product::where('imageable_type', App\Vehicle::class)
    ->whereHas('imageable', function($query) {
        $query->where('make', 'Ford');
    })->get();

update

in Product model add the name for morphTo relation:

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

update

I think it will not work with you because there is a bug when the relation is morpTo

maybe you should do it in another way depends in what is your need:

Ex: 1

// in this way you will get all Vehicle made by ford and eager load the products, then you make some process to get all products.
$vehicles = \App\Vehicle::with('products')->where('make', 'Ford')->get();

foreach($vehicles as $vehicle) {
    // I put the condition because maybe there are some vehicles without products
    $productName = $vehicle->products->count() ? $vehicle->products->first()->name : '';    
}

Or

Ex: 2

\App\Product::leftJoin('vehicles', function(JoinClause $join)
    {
        $join->on('products.imageable_id', '=', 'vehicles.id')
            ->on('products.imageable_type', '=', \DB::raw("'App\\Vehicle'"));
    })
    ->where('vehicles.make', 'Ford')
    ->where('products.imageable_type', App\Vehicle::class)
    ->get()

Upvotes: 2

Related Questions