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
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();
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.
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
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
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