I want items to be under the category they are related to - laravel

I want to achieve this result, but I can't understand the logic of the sql implementation
here is my welcome.blade.php:
#extends('layouts/layout')
#section('content')
<div class="container-fluid">
#foreach ($categories as $category)
<h4>{{$category->category_name}}</h4>
<div class="row">
<div class="col-sm-4">
<h6>{{$category->item_name}}</h6>
</div>
</div>
#endforeach
</div>
#endsection
and my controller:
$categories = DB::table('items')
->join('categories', 'items.category_id', 'categories.id')
->select('items.item_name', 'items.item_price', 'categories.category_name', 'categories.description')
->groupBy('categories.category_name')
->get();
return view('welcome', 'categories'=> $categories]);

You can use the QueryBuilder here if you want, but I would suggest using Eloquent unless you have a particular reason to not use it.
Let's assume that you have a Category and Item model and that you've defined a relational function within the Category model back to the Item model.
class Category extends Model
{
public function items()
{
// this assumes you're using standard naming conventions
return $this->hasMany(Item::class);
}
}
Then in your Controller, you might do something like the following to obtain categories and their related items.
$categories = Category::with('items')->get();
return view('welcome', compact('categories'));
The above can be adapted when required to limit the query to a specific Category when you require it. We use the with method to eager load the related records so that we can avoid the n+1 query problem.
Finally, in your view you can iterate (loop) over the categories and loop over the related items (there could be more than one).
#forelse($categories as $category)
<h4>{{ $category->category_name }}</h4>
#forelse ($category->items as $item)
<p>{{ $item->item_name }}</p>
#empty
<p>No items</p>
#endforelse
#empty
<p>No results</p>
#endforelse
The above is purely illustrative and ideally, you would break the above into reusable components.

Since you're using Laravel, you could use Eloquent relationships:
class Category extends Model{
public function items{
return $this->hasMany(Item::class);
}
}
Then in your controller:
$categories = Category::with('items')->get();
return view('welcome', ['categories'=> $categories]);
Then in your view:
#foreach ($categories as $category)
<h4>{{$category->category_name}}</h4>
#foreach($category->items as item)
<div class="row">
<div class="col-sm-4">
<h6>{{$item->name}}</h6>
</div>
</div>
#endforeach
#endforeach

$categories = DB::table("categories")->select("id", "category_name", "description")->get();
$items = DB::table("items")->select("category_id", "item_name", "price")->get();
view('welcome',compact("categories", "items"));
/////////////////////// BLADE ///////////////////////
<div class="container-fluid">
#foreach ($categories as $category)
#foreach($items as $item)
#if($category->id === $item->category_id)
<h4>{{$category->category_name}}</h4>
<div class="row">
<div class="col-sm-4">
<h6>{{$category->item_name}}</h6>
</div>
</div>
#endif
#endforeach
#endforeach
</div>
Try this.

Related

Laravel Categories, Subcategories and model binding

I have two tables: products and categories. Every product have specific category.
The products table has category_id.
The categories table has name and parent_id.
This is my example product: iPhone 12.
In the admin section I have category Apple and subcategory iPhone and then I put the product (iPhone 12) inside the subcategory iPhone.
In the frontend section I can successfully display the category tree unordered list and when I click on the subcategory iPhone, the product iPhone 12 displays fine but when I click on the category Apple, the product doesn't show. How can I display the data from the parent, so when I click on Apple category or iPhone subcategory to display the product in both cases?
Here's my code:
Model category
public function products()
{
return $this->hasMany('App\Models\Product');
}
public function children() {
return $this->hasMany('App\Models\Category', 'parent_id');
}
Category model
public function products()
{
return $this->hasMany('App\Models\Product');
}
ProductController
public function productCategory(Category $category) {
$categories = Category::with('children')->whereNull('parent_id')->where('status',1)->get();
$products = $category->products;
return view('products', compact('products', 'categories'));
}
Route
Route::get('/category/{category:slug}', 'App\Http\Controllers\ProductController#productCategory')->name('product.category');
Products view:
<div class="content products">
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="categories">
<ul>
#foreach($categories as $category)
<li>
{{ $category->name }}
#if($category->children)
<ul>
#foreach($category->children as $child)
<li>
{{ $child->name }}
</li>
#endforeach
</ul>
#endif
</li>
#endforeach
</ul>
</div>
</div>
<div class="col-md-9">
<div class="row">
#foreach($products as $product)
<div class="col-sm-4">
<div class="image">
<img class="img-fluid" src="{{ Storage::url($product->image) }}" />
</div>
<div class="title">
<h3>{{ $product->title }}</h3>
</div>
</div>
#endforeach
</div>
</div>
</div>
</div>
</div>
I think you could use hasManyThrough function provided by laravel
In the category model add these functions
//retrunt only the subcategories of the category
public function subcategories()
{
return $this->hasMany(Category::class,'parent_id');
}
//return the products directly by the parent category
public function categotyProducts()
{
return $this->hasManyThrough(
Product::class,
category::class,
'parent_id',
'category_id',
);
}
for more information see the docs
Hope that works for you!
In your Product model define category relationship as below.
public function category()
{
return $this->belongsTo('App\Models\Category','category_id');
}
In your controller function define slug variable and use below query to get Products
$slug = ($category->slug)??'';
Query for products:
$products = Product::where(function($query) use ($slug){
$query->whereHas('category',function($q) use ($slug){
$q->where('name', 'like', '%' . $slug . '%');
})
->orWhereHas('category.children',function($q) use ($slug){
$q->where('name', 'like', '%' . $slug . '%');
});
})->get();

I am trying to click on a category and products will show accordingly, but its not working

Controller:
public function shopfront(){
$products=Product::all();
$categories=Category::all();
return view('shop.index',compact('products','categories'));
}
index.blade.php:
<div class="sidebar-widget">
<h4 class="pro-sidebar-title">Categories</h4>
<div class="sidebar-widget-list mt-30">
<ul>
#foreach ($categories as $category)
#foreach ($products as $product)
#if ($category->id==$product->category->id)
<li>
<div class="sidebar-widget-list-left">
<input type="checkbox"> <a href="">{{ $category->name }}
{{-- <span>4</span> --}}
</a>
<span class="checkmark"></span>
</div>
</li>
#endif
#endforeach
#endforeach
</ul>
</div>
</div>
I do not know how to achieve this, will highly appreciate some help or i sample that i can work with
Image
i don't know how you want to achieve it but let me give you an idea if you want it in this way:
when click on a category then it should show all products of that category:
in your blade file
#foreach($categories as $category)
<li class="nav-item">
<a class="nav-link" href="{{route('category.products',$category->name)}}"> {{$category->name}}</a>
</li>
#endforeach
you should create a route named category.products as below in web.php
Route::get('category/{name}','YourController#yourmethod')->name('category.products');
controller
public function CategoryProducts($name){
$category = Category::where('name',$name)->first();
$products = $category->products;
return view('front-end.categoryWise-products',compact('products'));
}
you can customize it according to your requirements.

list of products in an foreach with an foreach

For school I got a project to make an webshop so I try to make an admin dashboard where if u wanna see the users informatie, u also will see the orders the user placed.
Right now i try this
#foreach($user->order as $order)
<div class='col-sm-12 col-md-6 col-lg-6'>
<div class="card">
<div class="card-header">
<b>Order ID:</b> {{ $order->id }}
</div>
<div class="card-body">
<ul class="list-group list-group-flush">
<li class="list-group-item list-group-item-secondary text-center text-danger"><b>Info:</b></li>
<li class="list-group-item"><b>Datum:</b> {{ $order->date }}</li>
<li class="list-group-item"><b>Prijs:</b> € 200</li>
<li class="list-group-item list-group-item-secondary text-center text-danger"><b>Producten:</b></li>
#foreach($user->order->orderrow as $orderrow)
<li class="list-group-item">{{ $orderrow->product->productname }}</li>
#endforeach
</ul>
</div>
</div>
</div>
#endforeach
but how can i make it that when i want to see the orderrow from an other table then the order table. is able to be worked in an foreach on the users.show.blade.php
Product model
public function orderrows()
{
return $this->hasMany(Orderrow::class)->orderBy('date', 'desc');
}
Orderrow model
public function product()
{
return $this->belongsTo(Product::class);
}
Order model
public function user()
{
return $this->belongsTo(User::class);
}
public function orderrow()
{
return $this->hasMany(Orderrow::class);
}
User model
public function order()
{
return $this->hasMany(Order::class);
}
Try using this code for inner foreach loop.
#foreach($order->orderrow as $orderrow)
<li class="list-group-item">{{ $orderrow->product->productname }}</li>
#endforeach

Get related products for a product by category

I'm trying to show products related to a category. But it is showing all products which are also related to other categories.
Blade:
<div class="row">
#foreach($categories as $category)
#foreach ($category->products as $product)
<div class="col-sm-12 col-md-6 col-lg-4 p-b-50">
<!-- Block2 -->
<div class="block2">
<div class="block2-img wrap-pic-w of-hidden pos-relative block2-labelnew">
<img src="{{ URL::to('/') }}/images/backend_images/product_images/{{ $product->product_image }}"
class="img-thumbnail" style="width: 270px; height: 360px;" />
<div class="block2-overlay trans-0-4">
</div>
</div>
<div class="block2-txt p-t-20">
<a href="product-detail.html" class="block2-name dis-block s-text3 p-b-5">
{{ $product->product_name }}
</a>
<span class="block2-price m-text6 p-r-5">
$75.00
</span>
</div>
</div>
</div>
#endforeach
#endforeach
</div>
Controller:
public function products(Request $request, Product $product)
{
$categories = Category::with('products')->distinct()->get();
return view('product.listing', compact('product', 'categories'));
}
Route:
Route::get('/product/{id}','Admin\ProductController#products')->name('product.products');
Edit your controller:
public function products(Request $request, Product $product)
{
$categories = $product->categories;
return view('product.listing', compact('product', 'categories'));
}
Also you should have the categories relationship method on Product Model.
public function products(Request $request, Category $category)
{
$products = Product::where('category_id',$category->id)->get();
$categories = Category:all();
return view('product.listing', compact('products','categories'));
}
Your route is
Route::get('/product/{id}','Admin\ProductController#products')->name('product.products');
//{id} it means you're getting category id from route right? so you can directly access it in controller.
Controller
//$id is from route.
public function products($id)
{
$products = Product::with('category')->where('category_id',$id)->get();
return view('product.listing', compact('products'));
}
In your blade file
#foreach($products as $product)
//here your all product which belongs to that categories.
and now if you want to access categories then may do as.
categories :- {{ $product->category->name }} //make sure it belongsTo in product
#endforech
public function products(Request $request)
{
$categories = Category::where('id',$request->id)->with('products')->get();
return view('product.listing', compact('categories'));
}
#foreach($categories as $category)
#foreach ($category as $product)
Assuming a product has one category and you have a category_id column in your products table change products method in your ProductController like below.
public function products(Request $request, Product $product)
{
$relatedProducts = Product::where('category_id', $product->category_id)
->where('id', '!=', $product->id) // ignore current product
->get();
return view('product.listing', compact('product', 'relatedProducts'));
}
Replace id in your route withproduct`. Read More about route model binding.
Route::get('/product/{product}','Admin\ProductController#products')->name('product.products');
Then in your view your you can iterate through relatedProducts
controller:
public function products(Request $request, Category $category)
{
$category->load('products');
return view('product.listing', compact('category'));
}
route:
Route::get('/product/{category}','Admin\ProductController#products')->name('product.products');
blade file:
#foreach ($category->products as $product)
<div class="col-sm-12 col-md-6 col-lg-4 p-b-50">
<!-- Block2 -->
<div class="block2">
<div class="block2-img wrap-pic-w of-hidden pos-relative block2-labelnew">
<img src="{{ URL::to('/') }}/images/backend_images/product_images/{{ $product->product_image }}" class="img-thumbnail" style="width: 270px; height: 360px;" />
</div>
</div>
</div>
#endforeach

How to output table data from controller to view?

I'm in the beginning stages of trying to make sense of Laravel and am having trouble displaying the 'illuminate collection object' passed to a blade from a controller.
My print_r is outputting "Illuminate\Support\Collection Object ( [items:protected] => Array ( ) ) 1" which I thought meant that it was seeing one item in the array (just one record in the table currently), but I'm hitting the #else statement so I'm guessing it's actually empty. I'm getting no errors, but I have not been able to display anything from $products despite $title outputting just fine.
public function shop(){
$products = DB::table('products')->get();
$data = array(
'title'=>'Shop',
'products' => $products
);
return view('pages.shop')->with($data);
}
#section('content')
<h1>{{$title}}</h1>
{{ print_r($products) }}
#if($products->count())
<ul class="list-group">
#foreach($products as $product)
<li class="list-group-item">{{$product->title}}</li>
#endforeach
</ul>
#else
<p>No products</p>
#endif
#endsection
Why is my array empty?
On your Controller:
$title = 'Shop';
$products = DB::table('products')->get();
return view('pages.shop', compact('title', 'products');
On your Blade:
I would also suggest to put your unordered list tag <ul> outside of the loop then use #forelse for a cleaner code, like so:
#section('content')
<h1>{{$title}}</h1>
<ul class="list-group">
#forelse($products as $product)
<li class="list-group-item">{{$product->title}}</li>
#empty
<li class="list-group-item">No products</li>
#endforelse
</ul>
#endsection
Try this..........
public function shop()
{
$products = DB::table('products')->get();
$title = "Shop";
return view('pages.shop', compact('products', 'title'));
}
#section('content')
<h1>{{ isset($title) ? $title : '-' }}</h1>
#if($products->count())
<ul class="list-group">
#foreach($products as $product)
<li class="list-group-item">{{ isset($product->title) ? $product->title : '-' }}</li>
#endforeach
</ul>
#else
<p>No products</p>
#endif
#endsection
You can display the data by first passing it as an array to the view
return view('pages.shop')->with('data', $data);
then in the blade
#section('content')
<h1>{{$data['title']}}</h1>
#if(count($data['products']))
<ul class="list-group">
#foreach($data['products'] as $product)
<li class="list-group-item">{{$product->title}}</li>
#endforeach
</ul>
#else
<p>No products</p>
#endif
#endsection
Pass both $products and $title to the view, I prefer to use compact feels cleaner.
$title = 'shop';
$products = DB::table('products')->get();
return view('pages.shop', compact('title', 'products');
Then in your view you can reference them directly. As you are doing now.
#section('content')
<h1>{{$title}}</h1>
#if($products->count())
<ul class="list-group">
#foreach($products as $product)
<li class="list-group-item">{{$product->title}}</li>
#endforeach
</ul>
#else
<p>No products</p>
#endif
#endsection
In your controller
$title = 'shop';
$products = DB::table('products')->get();
return view('pages.shop', compact('title', 'products');
OR
$products = DB::table('products')->get();
$data = array(
'title'=>'Shop',
'products' => $products
);
return view('pages.shop')->with('data',$data);
In your Blade
#section('content')
<h1>{{$title}}</h1>
#if(count($products))
<ul class="list-group">
#foreach($products as $product)
<li class="list-group-item">{{$product->title}}</li>
#endforeach
</ul>
#else
<p>No products</p>
#endif
#endsection

Resources