Laravel How to display related products? - laravel

I have ShopController . Now I am displaying products in random order from database.
Here is the code
$productsLike = Product::with('categories')->where('slug', '!=', $slug)->inRandomOrder()->take(4)->get();
What i should do to display products related to the same category as current product?

I would make a local scope on your Product model to make things reusable.
public function scopeRelatedProducts($query, $count = 10, $inRandomOrder = true)
{
$query = $query->where('category_id', $this->category_id)
->where('slug' '!=' $this->slug);
if ($inRandomOrder) {
$query->inRandomOrder();
}
return $query->take($count);
}
Then you could do something like:
$related = Product::relatedProducts(4, true)->with('categories')->get();
This assumes the column your Product table stores the relationship to a Category follows the Laravel naming convention (e.g. RelatedModelName_id).
You could also replace the slug_id with the Product id
You can then use the resulting $related variable in your view, so assuming your using the above in a Product show controller method, you might do:
class ProductController
{
public function show (Product $product)
{
$related = $product->relatedProducts(4, true)->with('categories')->get();
return view('products.show', compact('product', 'related');
}
}
#foreach ($related as $item)
<h5>{{ $item->name }}</h5>
<p>{{ $item->description }}</p>
#endforeach

You can check with category id.
$productsLike = Product::with('categories')
->where('category_id_column', $category_id)
->where('slug', '!=', $slug)
->inRandomOrder()->take(4)->get();

Related

Laravel Eloquent "With" and sub "With" relationship query -> pass Column Value as Where clause

I have 3 Models "Category" (tableName = 'categories'), "Brand" ('brands'), "Item" ('items')
Can I pass parent column value (e.g. categories) to use it in the Where clause?
Simple example:
Category::with(['brands' => function ($q) {
$q->with(['items' => function ($query) use ($localWhereHas) {
$query->whereColumn('category_id', 'categories.id');
}]);
}]);
Relations are:
Category Model:
public function brands(): BelongsToMany
{
return $this->belongsToMany(Brand::class, 'category_brands')->withPivot('is_visible', 'addon_price');
}
Brand Model:
public function items(): HasMany
{
return $this->hasMany(Item::class, 'brand_id');
}
Item Model:
public function category(): BelongsTo
{
return $this->belongsTo(Category::class, "category_id");
}
The main idea is that I need the structure to be nested like this Category->Brands->Items
The backup plan is to fetch All needed Categories and Foreach them to get as many as categories I have all Brands->Items, using categoryId ($category->category_id) .... but I don't like it
No, you can't pass it directly because it is not the same context.
If you want to have a display like this :
Category
-brand
-item
Then you should maybe just group your items by brand :
$categories = Category::with('items.brand')->get();
#foreach($categories as $category)
{{ $category->name}}
#foreach($category->items->groupBy('brand_id') as $brand_id => $items)
{{ $items->first()->brand->name }}
#foreach($items as $item)
{{ $item->name }}
#endforeach
#endforeach
#endforeach

Show many products from a category from many-to-many relationship in laravel

So I’m making a catalogue using Laravel 7.* and I have a problem.
I have many products and many categories. I have created a many-to-many relationship so a product can be in many categories.
Now, what I am trying to do is to show in a page each category with related products, but obviously I am doing something wrong.
Below you may see some code:
Product.php:
public function categories()
{
return $this->belongsToMany(Category::class);
}
Category.php:
public function product()
{
return $this->belongsToMany(Product::class);
}
Show.blade.php
#php
$products = \App\Product::with('categories')->find(1);
#endphp
#foreach ($products as $id)
{{ $id->name }}<br>
#endforeach
Any help please?
Fixed it.
I fetched categories in controller and send to view. Then for each category displayed each product.
Get all the categories and show products related to them.
#php
$categories= \App\Category::all();
#endphp
#foreach($categories as $category)
#foreach($category->product as $product)
{{$product->name}}
#endforeach
#endforeach
You need also Id of category that you want to show products related to it.
According To This answer
Try this:
$category_id = 1; // Desired Category Id
$products = \App\Product::whereHas('categories', function($query) use ($category_id) {
$query->where('category_id', $category_id);
})->paginate();
I also added pagination.

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
]);
}

How to safely access other users and other model's records inside Blade template

I have 3 models in my app Users, Sales and Plans, when I render sales for each customer (due to storing) I only get id's for other users and models related to that sale (like account manager, owner, plan), now I'm trying to use those ID's inside blade to get names or other rows based on ID and model. Here is the show function:
public function show($id) {
$user = User::find($id);
$sales = Sale::where('customer_id', '=', $id)->get();
return view('profiles.customer', ['user' => $user, 'sales' => $sales]);
}
And in blade I get all those sales like:
#foreach ($sales as $sale)
<li>
<i class="fa fa-home bg-blue"></i>
<div class="timeline-item">
<span class="time"><i class="fa fa-clock-o"></i> {{$sale->created_at->format('g:ia, M jS Y')}}</span>
<h3 class="timeline-header">{{$user->name}} became a customer</h3>
<div class="timeline-body">
<p>Date: {{$sale->sold_date}}</p>
<p>Price: {{$sale->sale_price}}</p>
</div>
</div>
</li>
#endforeach
So inside each record I have like "account_manager_id", "agent_id", "owner_id", "plan_id".
Currently I have this solved by adding public static function (this is for users, have same function for Plan model as well) in Sale model class:
public static function getUser($id) {
return User::where('id', $id)->first();
}
And I'm using it like this in Blade:
Account manager: {{$sale->getUser($sale->account_mgr_id)->name}}
Is this the safest and best way to do it? Or there is something I'm overlooking here?
You need to add relationships in your Sales Model.
class Sales extends Eloquent {
.....
.....
public function accountManager() {
return $this->hasMany('App\User', 'account_manager_id');
}
public function agents() {
return $this->hasMany('App\User', 'agent_id');
}
public function owner() {
return $this->hasOne('App\User', 'owner_id');
}
}
Now $sales->agents will give you a user with agent_id as id in User table.
Update your hasOne, hasMany relationships as your need. Laravel Documentation.
From your blade template, your access your AccountManager as
#foreach($sales->accountManager as $manager)
Name: {{ $manager->name}}
#endforeach
I think you could use Eloquent relationships. Taking your example, you should define relationship in your User model:
<?php
class User extends Eloquent {
public function sales() {
return $this->hasMany(Sale::class, 'customer_id');
}
}
Then, whenever you need to get sales of that user (entries, that relate via customer_id column), just simply do
<?php
$user = User::find($id);
$sales = $user->sales;
This is very fun when when you have to print out list of users that have sales, for example
<?php
public function showUsersWithSales() {
$users = User::with('sales')->get();
return view('users-with-sales', compact('users'));
}
users-with-sales.blade.php example:
#foreach ($users as $user)
User: {{ $user->name }}<br>
Sales:<br>
#foreach ($user->sales as $sale)
{{ $sale->amount }} {{ $sale->currency }} # {{ $sale->created_at }}<br>
#endforeach
<hr>
#endforeach
It would print all users with their sale amount and currency, followed by date when it was created.
This sample takes into account, that your User model has name attribute and your Sale model has amount, currency, created_at and customer_id fields in your database.
To reverse the action, say you have a sale and want to know who made it, just simply define a relationship!
<?php
class Sale extends Eloquent {
public function customer() {
return $this->belongsTo(User::class, 'customer_id');
}
}
Hope that helps!
Eloquent Relationship is your friend, https://laravel.com/docs/5.2/eloquent-relationships and you can solve your problem easily.
Suggestion is to remove all those function access and control from view and put it somewhere else. This will be good habit for you so you can avoid the infamous fat view.

How to best get results from 3 different tables based on ID matches in Laravel.

Trying to get products AND variants for a particular supplier.
I can get the products easy enough, but can't figure out how to best get to the variants with matching product_id and send it to the view.
Variants.product_id matches with Product.ID
This works (getting products for the supplier)
public function suppliers($id) {
$supplier = Supplier::orderby('company_name', 'ASC')->find($id);
$products = Supplier::find($id)->products;
$data = [];
$data['supplier'] = $supplier;
$data['products'] = $products;
return view('admin.purchasing.supplier-details', $data);
}
I've tried this to get the variants also without luck.
Controller:
public function suppliers($id) {
$supplier = Supplier::orderby('company_name', 'ASC')->find($id);
$products = Supplier::find($id)->products;
$variants = array();
foreach ($products as $product) {
$product_id = $product->id;
$variants[] = Variant::find($product_id);
}
$data = [];
$data['supplier'] = $supplier;
$data['products'] = $products;
$data['variants'] = $variants;
return view('admin.purchasing.supplier-details', $data);
}
View:
#foreach($products as $product)
<tr>
<td>{{ $product['title'] }}</td>
#foreach($variants as $variant)
#if($variant->product_id == $product['id'])
<td>${{ $variant->price }}</td>
#else
<td>not set</td>
#endif
#endforeach
</tr>
#endforeach
Any tips much appreciated.
First of all , you should have relation set on your models to make this work
like this For exemple :
Supplier.php
public function products()
{
return $this->hasMany('App\Product');
}
Product.php
public function variants()
{
return $this->hasMany('App\Variant');
}
public function Supplier()
{
return $this->belongsToMany('App\Supplier'); //in case you have only one supplier for each product change this to belongsto
}
Variant.php
public function products()
{
return $this->belongsToMany('App\Product'); //not sure if this should be manytomany or one to many , it deppends on what you did
}
anyway now you can do this
Controller
public function suppliers($id) {
$Data = Supplier::where('id',$id)->orderby('company_name', 'ASC')->with('products.variants')->first(); //you will get the supplier with all products associated to him with variants foreach product
return view('admin.purchasing.supplier-details')->with('Data',$Data); // now you just loop the $supplierwithproducts->products to get results (dd the variable to check output)
}
View
{{ $Data->name }} // supplier name since Supplier model was the starting point
#foreach($Data->products as $product) //loop all products related to that supplier
{{ $product->name }} //shows product name (depends on you database columns
#foreach($product->variants as $variant) // loops all variants in the current product
{{ $variant->name }} // shows variants
#endforeach
#endforeach
If you copy and paste this code it might not work ,but this will give you an idea how you should handle relations in laravel (levrage eloquent relations)
Check this for more informations
Laravel Docs
Laracasts Defining Relationships With Eloquent
Laracasts Updating Records and Eager Loading

Resources