Laravel 5 Model::with() behavior - php

I'm trying to get a simple list of products with a given category, using Laravel 5's (L5) Model::with() method. But it seems that L5 ignores the category where clause.
The relation in my Product model:
public function categories(){
return $this->belongsToMany('App\Category', 'categories_products');
}
In my Controller:
public function getByCategory($slug){
$return = Product::with(array('categories' => function($query) use ($slug){
$query->where('slug', 'like', $slug);
}))->paginate(60);
dd($return);
}
The result is a list of every product in my database, instead of just a list of those with the given category slug.
I'v tried to hardcode in some different where clauses, but all seems to be ignored. Am I missing something?

Eloquent doesn't use joins to query related data when using with(), but instead uses separate queries. In your example, it first fetches products and then fetches related categories.
You need to use has() or whereHas() to return only those products that have categories (slugs?).
public function getByCategory($slug){
$return = Product::has('categories')->with(array('categories' => function($query) use ($slug){
$query->where('slug', 'like', $slug);
}))->paginate(60);
dd($return);
}
Or:
public function getByCategory($slug){
$return = Product::whereHas('categories', function($query) use ($slug){
$query->where('slug', 'like', $slug);
})->paginate(60);
dd($return);
}
whereHas() adds a subquery that counts the number of relations. You should use DB::getQueryLog() to see the SQL that Eloquent produces. Makes it a lot easier to figure out what's going on!

Do you need to have an advanced subquery? If slug is defined as a column in product you can do this:
$return = Product::where('slug', 'like', $slug)->paginate(60);
dd($return);
Or if using the relations your query would look like this:
$return = Product::where('slug', 'like', $slug)->categories->paginate(60);
dd($return);

Related

Trying to related tables columns and sums with Laravel eloquent

Ok.
I have three tables
products
--product_id
--product_name
--product_type_id
--price15
--price23
--description
--bonus_points
--image
productTypes
--product_type_id
--product_type_name
productQuantities
--id
--product_id
--warehouse_id
--quantity
Products are placed in different warehouses so I have to keep tracks of its numbers
And has relationships are like this
class Product extends Model
{
public function productType() {
return $this->belongsTo('App\Models\ProductType','product_type_id','product_type_id');
}
public function productQuantities() {
return $this->hasMany('App\Models\ProductQuantity','product_id','product_id');
}
}
What I want to get is all columns from products and product type name from productType, sum of quantity from productQuantities, so I can perform search on those column values later on with where().
How can I get these columns with Eloquent?
I know I could get them with raw SQL commands but I need to do this way for compatibility reasons.
I tried this way before I ask the question.
But model relations just stopped working with no errors. Values just got emptied out from the other parts of the page.
$products = Product::selectRaw('products.*, productTypes.product_type_name, sum(product_quantities.quantity) as quantitySum')
->leftjoin('productTypes','products.product_type_id','=','productTypes.product_type_id')
->leftjoin('productQuantities','products.product_id','=','productQuantities.product_id')
->where('products.product_id','like','%'.$searchID.'%')
->where('product_name', 'like', '%'.$searchName.'%')
->where('product_type_name', 'like', '%'.$searchType.'%')
->where(function($q) use ($searchPrice) {
$q->where('price15','like','%'.$searchPrice.'%')
->orwhere('price23','like','%'.$searchPrice.'%');
})
->where('points', 'like', '%'.$searchPoints.'%')
->groupBy('products.product_id')
->orderByRaw($query)
->paginate($paginateBy);
Working version before this was simple.
Product::leftjoin('productTypes','products.product_type_id','=','productTypes.product_type_id')
->select('products.*','productTypes.product_type_name')
->where('products.product_id','like','%'.$searchID.'%')
->where('product_name', 'like', '%'.$searchName.'%')
->where('product_type_name', 'like', '%'.$searchType.'%')
->where(function($q) use ($searchPrice) {
$q->where('price15','like','%'.$searchPrice.'%')
->orwhere('price23','like','%'.$searchPrice.'%');
})
->where('points', 'like', '%'.$searchPoints.'%')
->orderByRaw($query)
->paginate($paginateBy);
And I thought any kind of join methods doesn't seem to be working well with Eloquent relationship? But older one has leftjoin method as well.
I have not tested this (and am assuming you want to group on product_type_name but you should be able to do something along the lines of:
$results = Product::with(['productType','productQuantities'])
->select(DB::raw('products.*,
productType.product_type_name,
sum(productQuantities.quantity) as "QuantitySum"'))
->groupBy('productType.product_type_name')
->get();
OR
$results = DB::table('products')
->join('productType', 'productType.product_type_id', '=', 'products.product_type_id')
->join('productQuantities', 'productQuantities.product_id', '=', 'products.product_id')
->select(DB::raw('products.*,
productType.product_type_name,
productType.product_type_name,
sum(productQuantities.quantity) as "QuantitySum"'))
->groupBy('productType.product_type_name')
->get();
Then you should be able to access the aggregated quantities using (in a loop if you wanted) $results->QuantitySum.
you can get it with eager loading and aggregating. For example, you need to query products has product type name like "new product" and quantity greater than 1000:
Product::with("productType")
->whereHas("productType", function ($query) {
$query->where("product_type_name", "like", "new product");
})
->withCount(["productQuantities as quantity_count" => function ($query) {
$query->selectRaw("sum(quantity)");
}])
->having("quantity_count", ">", 1000)
->get();
you can get through relationship
$product->productType->product_type_name
and attribute:
$product->quantity_count
$products = Product::withsum('productQuantities','quantity')
->leftjoin('product_types','products.product_type_id','=','product_types.product_type_id')
Gives me the result that I wanted. And didn't break the other parts.
But I'm still confused why with() and withSum() didn't work together.
Is it because products belongs to productTypes maybe

laravel 5.2 search in related entity

Suppose I have a Model called 'Commodity' which has category_id belongs to a category.
In Commodity.php I defined this relationship:
public function category(){
return $this->belongsTo('App\Category');
}
Now, I want to find the commodities which their category name include 'glass'
I tried this:
$items = Commodity::orderBy('id', 'desc')->category()->where('title', 'LIKE', '%glass%');
But it populates this error:
Call to undefined method Illuminate\Database\Query\Builder::category()
Please read official documentation that covers querying relations.
Sometimes you may wish to eager load a relationship, but also specify additional query constraints for the eager loading query. Here's an example:
$users = App\User::with(['posts' => function ($query) {
$query->where('title', 'like', '%first%');
}])->get();
So, regarding your question I'd suggest to try next:
$commodities = App\Commodity::with(['category' => function ($query) {
$query->where('title', 'like', '%glass%');
}])->orderBy('id', 'desc')->get();

Laravel - Using a nested relationship with the query builder

I am working on an API but its starting to get a bit slow now that the data is increasing. I am moving some of the queries so that they use the DB query builder.
I have my last one which has a nested query:
$artists = Artist::with('performances', 'performances.stage')->get();
I have got so far:
$artists = \DB::table('artists')
->leftJoin('performances', 'artists.id', '=', 'performances.artist_id')
->get();
But now need to do the second relationship which in the Performance model is:
public function stage()
{
return $this->hasOne('App\Models\Stage', 'id', 'stage_id');
}
Any help on how I do this?
yes you can use eloquent relationship with query builder like this
$artists = Artist::join('performances', 'artists.id', '=', 'performances.artist_id')
->all();
foreach($artists as $artist){
$data = $artist->stage()->first();
}
It is very well covered in the official documentation, please, refer to this section of Documentation
I think that you want to achieve something like this:
$posts = Post::whereHas('comments', function ($query) {
$query->where('content', 'like', 'foo%');
})->get();
And also, please, read carefully this section

Laravel ajax search with relations

I wanted to search the records after getting the relations. I tried with Laravel colletions. didnt work tough.
public function search($key){
$products = Product::with('unit', 'category', 'brand')->get();
$allproducts = collect($products);
$result = $allproducts->search($key);
Here I want the search to be done also based on category and brand.
If I cant you collection then how to do it the standard way.
I think using a query is the best approach since you dont need to load all products-categories-etc from the database and then try to find the matching ones.
Example query
Product::where('product_name', 'LIKE', "%$keyword%")
->orWhereHas('category', function ($q) use ($keyword) {
$q->where('category_name', 'LIKE', "%$keyword%");
//everything else you need to check
})->get();

How to get data from foreign key in laravel 5.1?

I am using laravel 5.1 for my new project smart search.
My problem is to get data from foreign key using like query for search of that table.
My database tables are:
category->id, name
search->id, category_id (foreign_key), question, answer, tags
My model code is:
category model
public function helpcenter() {
return $this->belongsTo('App\HelpCenter');
}
helpcenter model
public function category() {
return $this->hasOne('App\HelpCenterCategory', 'id', 'category_id');
}
My controller function for search query is
$queries = HelpCenter::has('category')
->where('questions', 'LIKE', '%'.$term.'%')
->orwhere('category_id.name','LIKE','%'.$term.'%')
->take(5)->get();
You will want to use whereHas() to subquery a relationship:
$queries = HelpCenter::whereHas('category', function($category) use ($term)
{
$category->where('name','LIKE','%'.$term.'%');
})
->orWhere('questions', 'LIKE', '%'.$term.'%')
->take(5)->get();
whereHas() is documented here: http://laravel.com/docs/5.1/eloquent-relationships#querying-relations

Categories