Laravel Order Collection Through Double Relationships - laravel

I am sending a Vehicle to my blade template which has a relationship of products that displays all the products fitting a vehicle.
Vehicle.php
public function products() {
return $this->belongsToMany(Product::class, 'vehicle_product');
}
I am strugging to figure out how to order those products based on a 3rd relationship's (product_group()) priority attribute.
Product.php
public function product_group() {
return $this->belongsTo(ProductGroup::class);
}
Blade Template
#foreach ($vehicle->products->orderBy('product_group.priority') as $product)
...

Use sortBy instead of orderBy but you must have products and product_group on 'vehicle' before applying it.
$vehicle = Post::query()
->with([
'products' => fn($q) => $q->with('product_group')
])
->where('id', 1)
->first();
$vehicle->products
->sortBy(fn($product) => $product->product_group->priority)
->values()
->all();

Related

output category with child categories and posts and pagination

I want to get category with all children subcategories and posts where id = category_id.
Posts should be paginated.
In category model I have 2 relations.
public function children() {
return $this->hasMany(self::class, 'parent_id');
}
public function posts() {
return $this->hasMany(Post::class, 'category_id');
}
In controller I have this function
public function getCategoryWithPaginatedPosts($slug, $perPage = null)
{
$columns = ['id', 'parent_id', 'title', 'slug', 'description', 'image'];
$postsColumns = ['category_id','title','text'];
$result = Category::whereSlug($slug)
->select($columns)
->with('children')
->with(['items' => function ($q) use ($postColumns) {
$q->wherePublished(true)
->select($postColumns)
->orderBy('id', 'ASC')
->paginate();
}])
->first();
}
Pagination doesn't work.
I just see that number of items is equal to $perPage parameter (and I have more items), but I don't see paginator inside dd($result->items)
It works like that, though I believe it is not the best way to do that.
So I can do it in few steps.
In first step I retrieve all data from DB and convert models to array, because I don't need models on webpage and I suppose it works faster like that. I would use ->toBase() if it could take mutators and relations from the model.
Second step I convert array into stdClass, because it is more comfortable in blade to work with object rather than with array.
Third step is to paginate items with mypaginate function (manual paginator in AppService Provider).
public function getCategoryWithPaginatedPosts($slug, $perPage = null)
{
$columns = ['id', 'parent_id', 'title', 'slug', 'description', 'image'];
$postsColumns = ['category_id','title','text'];
$result = Category::whereSlug($slug)
->select($columns)
->with('children')
->with(['items' => function ($q) use ($postColumns) {
$q->wherePublished(true)
->select($postColumns)
->orderBy('id', 'ASC');
}])
->first()
->toArray();
$result = Arr::arrayToObject($result);
$result->items = collect($result->items)->mypaginate($perPage);
return $result;
}
you should not use ->first() after ->paginate(), change something like this,
$result = Category::whereSlug($slug)
->select($columns)
->with('children')
->with(['items' => function ($q) use ($postColumns) {
$q->wherePublished(true)
->select($postColumns)
->orderBy('id', 'ASC')
}])
->paginate(20);

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.

Laravel filtering one to many relations

I have Product and Category models tied one to many.How to filter Products by category? In template i have
{{ $category->name }}
How to write function to filter Products with Category?
public function productsByCategory($category_id){
$products = Product:: ????
return view("layouts._productsByCategory", compact("products"));
Answer is
$products = Product::where('category_id', $category_id)->get();
You can use:
$products = Product::where('category_id', $category_id)->get();
or
$products = Product::whereHas('category', function($q) use ($category_id) {
$q->where('id', $category_id);
});
assuming you set category relationship in Product model.
You might find it easier to go via the category:
public function productsByCategory($category_id){
return view("layouts._productsByCategory", [
'products' => Category::with('products')->find($category_id)->products
]);
}

Laravel 5.5 - How to fetch related products in many to many relation

I am developing a e-commerce website.
I have 3 tables
1.prodcts table
2.conditions table
3.condition_product table
A product can have many conditions.
particular condition belongs to many products.
Now I have a product which belongs to 3 conditions.
I want to get all related products which belongs to these 3 conditions.
How can i achieve this?
product.php
public function conditions(){
return $this->belongsToMany(Condition::class)->withTimestamps();
}
condition.php
public function products(){
return $this->belongsToMany(Product::class)->withTimestamps();
}
This is my code:
public function productDetails(Product $product)
{
$a = $product->id;
$relatedProducts = Product::whereHas('conditions.products', function($q) use($a) {
$q->where('id', $a);
})
->get();
return view('pages/product', compact('product','relatedProducts'));
}
But I am getting error.
Use the whereHas() method with nested relationships:
Product::whereHas('conditions.products', function($q) use($productId) {
$q->where('id', $productId);
})
->get();
This will give you products that have conditions of a specified product.
Alternatively, you could do this:
$conditionIds = Product::find($productId)->conditions->pluck('id');
$products = Product::whereHas('conditions', function($q) use($conditionIds) {
$q->whereIn('id', $conditionIds);
})
->get();
A good practice is to always specify witch table the 'id' field is referencing too, because if not, it could both reference the 'conditions' table or the 'products' table 'id' field :
$relatedProducts = Product::whereHas('conditions.products', function($q) use($a) {
$q->where('products.id', $a);
})
->get();
You could see this answer about SQL ambiguous column name.

Advanced Select statement (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);

Resources