Laravel, Simple and Correct way for relationship - laravel

I want to list related categories of related brand with this logic.
Products Table
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('slug');
$table->integer('brand_id')->unsigned();
$table->foreign('brand_id')->references('id')->on('brands')->onDelete('cascade');
$table->integer('category_id')->unsigned();
$table->foreign('category_id')->references('id')->on('categories')->onDelete('cascade');
$table->timestamps();
});
}
web.php
Route::get('{Brand}/{Category}/{Product}', 'ProductsController#show');
Route::get('{Brand}/{Category}', 'ProductsController#index');
1st route, for example; Samsung/phones should list all of Samsung's phones with following code part. Is there another way to make these codes simple? And this query returns null. I checked that query is getting correct columns but returns null.
use App\Product;
use App\Brand;
use App\Category;
class ProductsController extends Controller
{
public function index(Request $request)
{
$category = $request->Category;
$cat_id = Category::select('id')
->where('slug',$category)
->get();
$brand = $request->Brand;
$br_id = Brand::select('id')
->where('slug', $brand)
->get();
$products = Product::select('id','name','slug')
->where('category_id', $cat_id)
->where('brand_id', $br_id)
->get();
return view('products.index', compact('products'));
}
}
Product.php
class Product extends Model
{
public function brands()
{
return $this->belongsTo('App\Brand');
}
public function categories()
{
return $this->belongsTo('App\Category');
}
}
Category.php
class Category extends Model
{
public function brands()
{
return $this->belongsToMany('App\Brand');
}
public function products()
{
return $this->hasMany('App\Product');
}
}

First of all read the docs about laravel relationships:
https://laravel.com/docs/5.7/eloquent-relationships
The reason your current code is not working is because in your route you ask for parameters:
Route::get('{Brand}/{Category}', 'ProductsController#index');
But in your index() method on your ProductsController you have not included these parameters.
public function index(Request $request, Brand $brand, Category $category)
The second problem in your code is that you are not using your relationships at all. Your current controller just makes a new eloquent query.
Example of getting all the products for the given category using the method you have defined on your Category Model:
public function index(Request $request, Brand $brand, Category $category)
{
$products = $category->products;
return view('products.index', compact('products'));
}
Example of extending this with the given brand:
public function index(Request $request, Brand $brand, Category $category)
{
$products = $category->products()->where('brand_id', $brand->id)->get();
return view('products.index', compact('products'));
}
UPDATE
As noted in the comments, the URL parameters are slugs and not ids, so auto route-model-binding will not work. An updated solution with slugs:
public function index(Request $request, $brand, $category)
{
$categoryModel = Category::where('slug', $category)->firstOrFail();
$brandModel = Brand::where('slug', $brand)->firstOrFail();
$products = $categoryModel->products()->where('brand_id', $brandModel->id)->get();
return view('products.index', compact('products'));
}
Further improving your code would be to add a scope or helper method so you can do something like Brand::FindBySlug($slug);

I think you are using get method at last that will give you array not only one value. Could you please try with below code. This might help
use App\Product;
use App\Brand;
use App\Category;
class ProductsController extends Controller
{
public function index(Request $request)
{
$category = $request->Category;
$cat_id = Category::where('slug',$category)->value('id);
$brand = $request->Brand;
$br_id = Brand::where('slug', $brand)->value('id);
$products = Product::select('id','name','slug')
->where('category_id', $cat_id)
->where('brand_id', $br_id)
->get();
return view('products.index', compact('products'));
}
}

You should try this:
public function index($brand, $category,Request $request)
{
$products = Product::select('id','name','slug')
->where('category_id', $category)
->where('brand_id', $brand)
->get();
return view('products.index', compact('products'));
}

Related

Eloquent collections with a relation of another relation

I have Post eloquent related with PostCategory and my collection is good.
class Post extends Model
{
public function post_categories()
{
return $this->belongsTo(PostCategory::class, 'category_id');
}
public function detail($slug_category, $slug)
{
$detail = Post::with('post_categories')
->whereHas('post_categories', function ($query) use ($slug_category){
$query->where('category_slug', $slug_category);
})->where('slug', $slug)
->first();
return($detail);
}
}
I have this another class 'Players' where i need to have a collection with all user's posts with PostCategory category relation.
class Players extends Model
{
public function posts()
{
return $this->hasMany(Post::class);
}
public function detail($slug_category, $slug_name)
{
$detail = Player::with('posts')
->whereHas('players_info', function ($query) use ($slug_name){
$query->where('slug', $slug_name);
})
->whereHas('player_categories', function ($query) use ($slug_category){
$query->where('category_slug', $slug_category);
})->first();
return($detail);
}
}
I read something about "belongsToMany" and "withPivot", but I'm still confused for correct way.
What can I do to resolve this?
thanks!
I solved just with this.
return $this->hasMany(Post::class)->with('post_categories');

How to load a Category Page with Products using pagination and filtering? Laravel

// CategoryController
class CategoryController extends Controller
{
public function show($slug)
{
$category = Category::with('products')
->where('slug', $slug)
->where('menu', 1)
->first();
return view('pages.category.show', compact('category'));
}
}
// Product_to_categories pivot table...
Schema::create('products_to_categories', function (Blueprint $table) {
$table->bigIncrements('id');
$table->bigInteger('category_id')->unsigned()->index();
$table->foreign('category_id')->references('id')->on('categories');
$table->bigInteger('product_id')->unsigned()->index();
$table->foreign('product_id')->references('id')->on('products');
$table->timestamps();
});
I cannot paginate the products on the page, how would you suggest paginating with Eager Loading or passing the variables separately...
I have a pivot table Category_Product also...
I also want to filter based on brand and price?
EDIT:
// product.pphp
class Product extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class, 'products_to_categories', 'product_id', 'category_id');
}
}
```
Reverse it, meaning query for products instead:
class CategoryController extends Controller
{
public function show($slug)
{
$products = Product::with(['categories'])->whereHas('categories', function ($query) use ($slug) {
$query->where(['slug' => $slug]);
})->paginate();
return view('pages.category.show', compact('products'));
}
}
You can do that in two steps like this:
class CategoryController extends Controller
{
public function show($slug)
{
$category = Category::where('slug', $slug)->first();
$products = Product::where('category_id', $category->id)->paginate(20);
return view('pages.category.show', compact('category', 'products'));
}
}
This with Eager Loading
class CategoryController extends Controller
{
public function show($slug)
{
$category = Category::with('products')->whereHas('products' => function($query) {
if(request()->has('price')
{
$query->where('price',request()->input('price');
}
if(request()->has('brand')
{
$query->where('brand',request()->input('brand');
}
})->where('slug', $slug)->paginate(20);
return view('pages.category.show', compact('category'));
}
}
Thanks #Tpojka that answer provides the same results as this below...
class CategoryController extends Controller
{
public function show($slug)
{
$category = Category::where('slug', $slug)->first();;
$products = $category->products()->paginate(15);
return view('pages.category.show', compact('category', 'products'));
}
}

how to use laravel Scope in a relationship?

I'm using laravel
I have two models
Product
class Product extends Model
{
public function productcategories(){
return $this->hasOne('App\Product\Productcategorie','CategoryID','ProductCategoryId');
}
}
and Productcategorie
class Productcategorie extends Model
{
protected $primaryKey = 'CategoryID';
public function product(){
return $this->belongsToMany('App\Product\Product','ProductCategoryId','CategoryID');
}
public function scopeCp($query,$id){
return $query->where('categoryparent_id', '=', $id);
}
}
The Product model has a scope Cpscope
and i have ProductController with function
function productCatgoryPaFilter(Request $request){
$categories= Categoryparent::with('categories')->get();
$id=$request->id;
return $product = Product::with('productcategories')->with('productoption.option')->orderBy('created_at','DESC')->get();
}
i want to get all products with categoryparent_id equal to passed parametre in scope
how can i do it?
If you want to filter data in relational model, use whereHas(). Though i have not tested, give it a try
Product::whereHas('productcategories', function ($query) use($id) {
$query->cp($id);
})
->orderBy('created_at','DESC')->get()

How to show Laravel model with belongsToMany connection if has specified connection?

I have this product model:
public function categories() {
return $this->belongsToMany('App\Category', 'product_categories');
}
And in my controller:
public function search(Request $request) {
return Product::with([
'categories' => function($categories) use ($request) {
// ...
}
]);
}
If I try to use $request in the categories function it's search only in categories, but shows all products.
How do I show only that products whitch has defined categories in $request->category_id?
you may use the whereHas keyword in laravel:
public function search(Request $request) {
return Product::with('categories')
->whereHas('categories', function ($query) use ($request){
$query->where('category_id', $request->category_id);
})->get();
}
Here is the docs
You can search it in following way:
public function search(Request $request) {
return Product::with('categories')
->whereHas('categories', function ($q) use (request) {
$q->where('id', $request->category_id);
});
}

Laravel Eloquent how to get all products in a category with slug

My Productcategory.php has
public function products()
{
return $this->hasMany('App\Models\Product');
}
And Product.php has
public function productcategory()
{
return $this->belongsTo('App\Models\Productcategory', 'category_id');
}
Now my route is
Route::get('gallery/{slug}', 'GalleryController#index');
When URL is something like gallery/print-pattern-client-work, how can I get all products with the same category? I have the following but category_id is an integer and not a slug. So I am not so sure how to do it.
public function index()
{
$categoryslug = Request::segment(2);
$products = Productcategory::with('products')->where('category_id',$categoryslug)->get();
...
}
This assumes you have a column named "slug" in your product_categories table. And that your described relations work well.
You could make an accessor in Product.php
public function scopeFindByCategorySlug($query, $categorySlug)
{
return $query->whereHas('productcategory', function ($query) use ($categorySlug) {
$query->where('slug', $categorySlug);
});
}
Then in your controller you call this:
public function index(Request $request, $slug)
{
$products = Product::findByCategorySlug($slug)->get();
}
Edit:
As mentioned in comments there is no actual need for an accessor. This is basically all you need (in controller):
public function index(Request $request, $slug)
{
$products = Product::whereHas('productcategory', function ($query) use ($categorySlug) {
$query->where('slug', $categorySlug);
})->get();
}
Don't
$categoryslug = Request::segment(2);
Use $slug
public function index($slug)
{
$products = Productcategory::with('products')->where('category_id',$slug)->get();
...
}
As you're using Laravel, you should use Laravel's Many to Many Relationships like this:
Your table structure would be like:
- products
- id
- name
- ...
- categories
- id
- name
- slug
- ...
- category_product
- id
- category_id
- product_id
- ...
Your models should be like this:
class Product extends Model {
public function categories() {
$this->belongsToMany(Category::class, 'category_product');
}
}
class Category extends Model {
public function products() {
$this->belongsToMany(Product::class, 'category_product');
}
}
and you can fetch all the products for a particular $category_slug like this:
$category = Category::where('slug', $category_slug)->first();
if($category) {
$products = $category->products;
}

Resources