Advanced Select statement (Laravel) - laravel

In the Products table i have the store_id column which connects the product with the store.
In my APIController which i use with Angular i have this return statement. I am returning a collection of products.
return Product::where('category_id', $category->id)
->select(array('id', 'name', 'newprice', 'image',
'store_id', 'link'))
->paginate(20);
My problem is that instead of returning the store_id(from the products table) i want to return the store name, which is NOT stored in the same table. Is there any way to do that?
Is my only option the use of JOIN?

I recommend you do it with Laravel(/Eloquent) relationships like this:
ApiController:
$productFieldArray = ['id', 'name', 'newprice', 'image', 'store_id', 'link'];
$product = Product::where('category_id', $category->id)
->select(productFieldArray)
->paginate(20);
// Get the value you want (I guess it's the name attribute?)
$store = $product->store->name;
Model relationships:
Product.php:
...
public function store() {
return $this->belongsTo('App\Store');
}
...
Store.php:
...
public function products() {
return $this->hasMany('App\Product');
}
...
Edit:
You have to use the with() function in your query to point out your want to receive the store data too. See: Laravel - accessing relationship Models with AngularJS or http://laravel.com/docs/4.2/eloquent#eager-loading.
So you query will be:
Product::with('store')
->where('category_id', $category->id)
->select(productFieldArray)
->paginate(20);

Related

How do I query data from a pivot table in Laravel 7 [duplicate]

Searching from pivot table using laravel.
Here is my table structure:
Product
id
name
Categories
id
name
product_category (Pivot table)
id
category_id
product_id
//products can have multiple categories
Product model:
public function categories(){
return $this->belongsToMany(Category::class, 'product_category');
}
What is the best way to search all products by category id?
Currently I am doing this way, and it seems not an efficient way:
//Controller
$categories = product_category::where('category_id',1)->get();
Now I have to loop through categories and then get Products and pass it to views? Any idea how to do this in an efficient way?
For this you could use the whereHas() method:
$categoryId = 1;
$products = Product::whereHas('categories', function ($query) use($categoryId) {
$query->where('id', $categoryId);
})->get();
The above will return all products that are in the Category where the id is equal to $categoryId.
You can eager load products for a given category. Try:
$category = Category::with('products')->where('category_id',1)->find(1);
When you do this, only 2 database queries will be executed: one for loading the category, and one for loading related products.
Then in your Blade view you can do:
#foreach($category->products as $product
{{ $product->name }}
#endforeach
You can use this inside your method in controller..this only works when $request->$query(search) have value .then here we use wereHas for get the relationship of model and with->() using for get pivot table values
->when($request->query('search'), function ($query)use($request) {
$q= $request->query('search');
return $query->whereHas('relation name', function (Builder $query) use ($q) {
$query->with('pivot table name.column name')
->where('pivot table name.column name', 'like', "%{$q}%")
});})

Laravel - Get array with relationship

I have an ajax call that returns an array:
$reports = Report::where('submission_id', $submissionID)
->where('status', 'pending')
->get(['description','rule']);
return [
'message' => 'Success.',
'reports' => $reports,
];
From this array, I only want to return the fields 'description' and 'rule'. However I also want to return the owner() relationship from the Report model. How could I do this? Do I have to load the relationship and do some kind of array push, or is there a more elegant solution?
You can use with() to eager load related model
$reports = Report::with('owner')
->where('submission_id', $submissionID)
->where('status', 'pending')
->get(['id','description','rule']);
Note you need to include id in get() from report model to map (owner) related model
you will have probably one to many relationship with Reports and owners table like below
Report Model
public function owner() {
return $this->belongsTo('App\Owner');
}
Owner Model
public function reports() {
return $this->hasMany('App\Report');
}
your controller code
$reports = Report::with('owner')->
where('submission_id', $submissionID)->where('status', 'pending')->get()
return [
'message' => 'Success.',
'reports' => $reports,
];
This is what I ended up going with:
$reports = Report::
with(['owner' => function($q)
{
$q->select('username', 'id');
}])
->where('submission_id', $submissionID)
->where('status', 'pending')
->select('description', 'rule','created_by')
->get();
The other answers were right, I needed to load in the ID of the user. But I had to use a function for it to work.

mb_strpos() expects parameter 1 to be string, object given when querying 2 tables in Laravel

Ok, so I don't know if this can be done, but I need to combine the results of 2 Where clauses from 2 tables into one variable.
So far I have this working to query one table:
$allCompanies = Products::where('category_id', $id->id)->groupBy('company_id')->get();
And this for the other:
$companies = Company::where('visible', 0)->get();
But is there any way to get them into the same query string? Something like so I can get where the ID matches the ID column in one table AND where visible is 0 in the other?
I tried this:
$allCompanies = Products::with('company', function($q){
$q->where('visible', 0);
})->where('category_id', $id->id)
->groupBy('company_id')->get();
but got this error:
mb_strpos() expects parameter 1 to be string, object given
Company Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
public function products()
{
return $this->hasMany('App\Products');
}
}
Products Model
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Products extends Model
{
protected $fillable = [
'name',
'description',
'image',
'size',
'price',
'stock',
'company_id',
'category_id'
];
public function category()
{
return $this->belongsTo('App\Categories', 'category_id');
}
public function company()
{
return $this->belongsTo('App\Company', 'company_id');
}
}
When using callback in with, you should pass callback as value of associative-array.
Your query should be:
$allCompanies = Products::with(['company' => function($q) {
$q->where('visible', 0);
}])
->where('category_id', $id->id)
->groupBy('company_id')
->get();
Ref: https://laravel.com/docs/8.x/eloquent-relationships#nested-eager-loading-morphto-relationships
The most Laravel way of achieving this is through Relationships and whereHas. If you have a relationship defined you could do the following:
$products = Products::where('category_id', $id->id)
->whereHas('company', function($q) {
$q->where('visible', 0);
});
Which will query for all the products with a certain category_id that also have a relationship with a company that has a column visible with value 0
Depends on what you want:
If you want all the products from visible companies:
$products = Products::whereHas('company', function($q) {
$q->where('visible',0);
})->get();
If you want all the companies with their products (which I would advise):
$Companies = Company::with('products')->where('visible',0)->get();

best approach to search from pivot table using laravel

Searching from pivot table using laravel.
Here is my table structure:
Product
id
name
Categories
id
name
product_category (Pivot table)
id
category_id
product_id
//products can have multiple categories
Product model:
public function categories(){
return $this->belongsToMany(Category::class, 'product_category');
}
What is the best way to search all products by category id?
Currently I am doing this way, and it seems not an efficient way:
//Controller
$categories = product_category::where('category_id',1)->get();
Now I have to loop through categories and then get Products and pass it to views? Any idea how to do this in an efficient way?
For this you could use the whereHas() method:
$categoryId = 1;
$products = Product::whereHas('categories', function ($query) use($categoryId) {
$query->where('id', $categoryId);
})->get();
The above will return all products that are in the Category where the id is equal to $categoryId.
You can eager load products for a given category. Try:
$category = Category::with('products')->where('category_id',1)->find(1);
When you do this, only 2 database queries will be executed: one for loading the category, and one for loading related products.
Then in your Blade view you can do:
#foreach($category->products as $product
{{ $product->name }}
#endforeach
You can use this inside your method in controller..this only works when $request->$query(search) have value .then here we use wereHas for get the relationship of model and with->() using for get pivot table values
->when($request->query('search'), function ($query)use($request) {
$q= $request->query('search');
return $query->whereHas('relation name', function (Builder $query) use ($q) {
$query->with('pivot table name.column name')
->where('pivot table name.column name', 'like', "%{$q}%")
});})

Laravel Eloquent nested query

I was working with Laravel and got stuck in a situation. I have following models:
Category
Product
CategoryProduct
CategoryProduct holds the information about which product belongs to which category (a product may belong to multiple categories).
Now, when I want to load all products belonging to a particular category, I need to run query on Product and CategoryProduct which is where I'm stuck.
I gave it the following try but was unsuccessful:
$products = Product::where('status', '=', 'active')
->where('category_id', '=', $category_id)
->take($count)
->skip($skip)
->get();
Obviously, it will say that category_id is not a column.
Here is my DB & Model structure:
categories table
id,
name,
etc.
products table
id,
name,
sku,
etc.
category_products table
id,
product_id, ( Foreign key to Product.id )
category_id, ( Foreign key to Category.id )
etc.
Product model
class Product extends Eloquent {
protected $table = 'products';
protected $hidden = array();
public static $rules = array('name' => 'required|min:3');
}
Category model
class Category extends Eloquent {
protected $table = 'categories';
public static $rules = array('name' => 'required|min:3');
}
CategoryProduct model
<?php
class CategoryProduct extends Eloquent {
protected $table = 'category_products';
public function product()
{
return $this->belongsTo('Product');
}
public function category()
{
return $this->belongsTo('Category');
}
}
Update
A new question on this
I'm trying to display products. If category is not passed (value is -1), then I will show all products, otherwise I will show products from the passed category.
Now, when I show all products, those products may already exist in a category. I want to display ticked checkbox for products that are already in a category. I'm doing something like this:
if($category_id==-1)
$products = Product::where('status', '=', 'active')->take($count)->skip($skip)->get();
else{
$products = Product::whereHas('categories', function($q) use ($category_id)
{
$q->where('category_id', $category_id);
})->where('status', 'active')
->take($count)
->skip($skip)
->get();
}
The table category_products have product_id, category_id as columns.
Now, the query:
$products = Product::where('status', '=', 'active')->take($count)->skip($skip)->get();
will pick products only from products table. If I check each product for its existence in category_products, then there will be too many database queries for large number of products.
Any idea, how to achieve this. I hope I was able to clear my situation. Thanks
The CategoryProduct model should not be necessary unless you have additional fields besides product_id and category_id which point to other relationships.
What is necessary are the methods for setting up the relationship on the Category and Product models.
In Category, add the relationship function...
public function products()
{
return $this->belongsToMany('Product', 'category_products');
}
In your Product model, do the same for categories.
public function categories()
{
return $this->belongsToMany('Category', 'category_products');
}
Then you can query for your active products that belong to that category using your relationship method and whereHas()
$products = Product::whereHas('categories', function($q) use ($category_id)
{
$q->where('id', $category_id);
})->where('status', 'active')
->take($count)
->skip($skip)
->get();
You don't need a model for a pivot table in Many-to-Many relationships. Look at this section of the Eloquent documentation for further explanation.
You still need to create a migration to set up the pivot table (or do it manually if you don't use migrations), but not a model. Instead, create a function for Category to designate the relationship:
public function products()
{
return $this->belongsToMany('App\Product', 'category_products');
// - You might need to adjust the namespace of App\Product
// - category_products refers to the pivot table name
}
Likewise, Product needs a similar public function.
Then you're able to do it the other way around, by finding the category and then listing all its related products:
$products = Category::find($category_id)
->products()
->where('status', 'active')
->take($count)
->skip($skip)
->get();
This question could also be relevant to yours.

Resources