Query for get category in view in Laravel - php

I try to get the category from my article.
A category can have several sub categories, but I only want the first level. In my DataBase, each sub categories has a parent_id, stored in the same table.
I have a method scopeFirstLevelItems but I don't think it will help me here?
public function scopeFirstLevelItems($query)
{
return $query->where('depth', '1')
->orWhere('depth', null)
->orderBy('lft', 'ASC');
}
It's possible to get the category parent from the sub categories ?
For get the category in my controller, I try this
protected function index(Article $article)
{
$articles = Article::published()->paginate(8);
$category = Category::with('articles')->firstLevelItems()->where('id', $article->id)->get();
return view('pages.blog', [
'articles' => $articles,
'category' => $category
]);
}
And in my view
{{ $category->name }}
But it doesn't work.
And I have three relations in my Category model
public function parent()
{
return $this->belongsTo('App\Models\Category', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Models\Category', 'parent_id');
}
public function articles()
{
return $this->hasMany('App\Models\Article');
}
Can you help me ? Thank you

You can get parent category's name from child category by
$category->parent()->name
Also I think you copy pasted the child function to parent function.
Change the Model, which currently point to App\Models\Category in both parent and child.

Related

Laravel has and orHas not working with where

I need get categories with products, only where products exists on category, I have code:
$categories = Category::with(['children.products', 'products'])->has('children.products')->orHas('products')->whereNull('parent_id')->whereId($category->id)->paginate(15);
But whereId = $category->id not working.. Why? I get category with other categories.. but I need get only certain category, where id = categoryId
Model category:
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function parent()
{
return $this->belongsTo(self::class, 'parent_id')->withoutGlobalScope('active');
}
public function products()
{
return $this->hasMany(Product::class);
}
You should combine has and orHas within enclosed function, something similar to below:
$query->where(function($query) {
$query->has('children.products');
$query->orHas('products');
});
Additionally, to above, I would recommend using "join" because "has" is a lot slower.

laravel eloquent multiple tables where criteria

I have spent two days trying to solve this issue but no luck.
I have 3 tables, categories, items and related items, every item is under one category and category can have many items, this part working fine, now the issue is in related item, I have in the table realteditems 3 fields, id(just autoincrement), ritemf_id,riteml_id those refers to item_id in items table.
What I want to do is to display item with its details and related items to this item, means if item1 have many realted items,such item2,item3,item4 .. so need to display like this
item_title: item1
related item:
item2
item3
item4
controller
$items = Item::orderBy('category_id', 'asc')->with('category')->get()->groupBy('category_id');
$categories = Category::orderBy('category_id', 'asc')->get();
return view('home',['items' => $items,'ritems' => $ritems,'categories' => $categories]);
items modal
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
public function relateditems()
{
return $this->belongsTo('App\Relateditem', 'ritemf_id');
}
relateditems modal:
class Relateditem extends Model
{
protected $table="relateditems";
protected $fillable=['ritemf_id','riteml_id'];
protected $primaryKey='id';
public $timestamps=false;
public function items()
{
return $this->belongsTo('App\Item', 'item_id');
}
}
showing items with its category in blade(working fine)
#if (!empty($categoryItems->first()->category))
{{ $categoryItems->first()->category->category_name }} #else {{$category_id}} #endif
#foreach($categoryItems as $item)
{{$item->item_title}}
${{$item->item_price}}
#endforeach
#endforeach
relateditems()definition looks incorrect to me in Item model, Item may have more than one related items then this should be hasMany/beongsToMany association.
Assume its hasMany then update your item model as
public function relateditems() {
return $this->hasMany('App\Relateditem', 'ritemf_id');
}
And eager load your related items for each item
$items = Item::orderBy('category_id', 'asc')
->with(['category', 'relateditems'])
->get()
->groupBy('category_id');
I assume the groupBy method is used from collection class to group retrieved data not on database side
You need to fix both relations in Item Model and RelatedItem model. relateditems should be hasMany because an item can have many related item.
You also need to define belongsTo relation in RelatedItem to Item using riteml_id key
Item modal
public function category()
{
return $this->belongsTo('App\Category', 'category_id');
}
public function relateditems()
{
return $this->hasMany('App\Relateditem', 'ritemf_id');
}
Relateditem modal:
class Relateditem extends Model
{
protected $table="relateditems";
protected $fillable=['ritemf_id','riteml_id'];
protected $primaryKey='id';
public $timestamps=false;
public function item() //i have change it to item instead items, because belongsTo always return single record
{
return $this->belongsTo('App\Item', 'riteml_id');
}
}
Fetch Data
$items = Item::orderBy('category_id', 'asc')->with('category','relateditems', 'relateditems.item')->get()->groupBy('category_id');
foreach($items as $categoryId => $groupItems){
echo $groupItems->first()->category;
foreach($groupItems as $item) {
echo $item->item_tile;
...
foreach($item->relateditems as $relatedItem){
if ($relatedItem->item){
echo $relatedItem->item->item_tile; //this will show you related item title
}
}
}
}
For Single Item
$item = Item::with('category','relateditems', 'relateditems.item')->find(1);
foreach($item->relateditems as $relatedItem){
if ($relatedItem->item){
echo $relatedItem->item->item_tile; //this will show you related item title
}
}

Laravel scope on collection

I'm in Pain because of this problem.
Problem
I have categories table which contains id, slug and parent_id.
lessons table which contains category_id (the child of a Category)
I want by Eloquent scope get all lessons posted by Category parent id
example:
parent category of id=1 have children categories of ids 3, 4 and 5.
Then retrieve Lessons under the parent category of id=1, so this must return the lessons of all of the childrens.
Categories table
public function parent()
{
return $this->belongsTo(self::class, 'parent_id');
}
public function lessons()
{
return $this->hasManyThrough(
\App\Lesson::class, \App\Category::class,
'parent_id', 'category_id', 'id'
);
}
//Pointless try
// public function scopeGetParent($query, $slug)
// {
// $query->where('slug', $slug)->first()->lessons;
// }
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
Lessons.php
return Lesson::recentLessons()
->byParentCategory($args['category'])
->simplePaginate($page)
->shuffle();
how can I construct scopeByParentCategory() function??
sorry for the fuzzy question! Spent 3 hours trying :(
update: I got this idea right after posting the question but still wanna know what do you think about it and if this the best way to handle it.
public function scopeByParentCategory($query, $slug)
{
$ids = [];
foreach (Category::where('slug', $slug)->first()->children as $value)
{
$ids[] = $value->id;
}
return $query->whereIn('category_id', $ids);
}
First put this code inside of your Category model:
public function scopeOfSlug($query, $slug)
{
$query->where('slug', $slug);
}
Then in your controller
return Category::ofSlug($args['category'])
->lessons
->simplePaginate($page)
->shuffle();

Hide unpublished items from counter in Laravel query

I'm showing all sub categories under main category. On each sub-category there is a counter of how many items are assigned there.
Main Category
- Sub Category (1)
- Sub Category (3)
- etc
Current problem is that one item can be published and unpublished. When the item is not published yet I don't want to show it on counter. Column in items table is published and accept 1 for published and 0 for unpublished.
This is what I have to show them on page
HomeController.php
$allCategories = Category::where('parent_id', 0)->has('children.item')
->with(['children'=> function($query){
$query->withCount('item');
}])
->get()
->each(function($parentCategory){
$parentCategory->item_count = $parentCategory->children->sum(function ($child) { return isset($child->item_count)?$child->item_count:0;});
});
My Item.php model
public function category()
{
return $this->belongsTo('App\Category');
}
My Category.php model
public function item()
{
return $this->hasMany('App\Item','category_id');
}
public function parent()
{
return $this->belongsTo('App\Category', 'id', 'parent_id');
}
public function children()
{
return $this->hasMany('App\Category', 'parent_id', 'id');
}
I've tried to directly add it to the query but doesn't make any difference
$query->withCount('item')->where('published', 1);
You have to add the where condition in the relationship function item of Category.php model.
Here is the code:
public function item()
{
return $this->hasMany('App\Item','category_id')->where('published', 1);
}

Laravel : How to access many to many relationship data Ask

I have category and subcategory table with many to many relationship
class Category extends Model {
protected $table='categories';
protected $fillable=['name'];
public function subcategories() {
return $this->belongsToMany('App\Modules\Subcategory\Models\Subcategory', 'categories_subcategories', 'category_id', 'subcategory_id');
}
}
Subcategory
class Subcategory extends Model {
protected $table='subcategories';
protected $fillable=['name'];
public function categories()
{
return $this->belongsToMany('App\Modules\Category\Models\Category', 'categories_subcategories', 'subcategory_id', 'category_id');
}
}
in controller
public function catSubList()
{
$subcategories = Subcategory::with('categories')->get();
return view('Subcategory::category_subcategory',compact('subcategories'));
}
But in view when i tried to access the data with following view
#foreach($subcategories as $row)
<td>{{$i}}</td>
<td>{{$row->name}}</td>
<td>{{$row->categories->name}}</td>
#endforeach
I got the error like :
ErrorException in Collection.php line 1527: Property [name] does not exist on this collection instance.
How do i access $row->categories->name ? anyone with the suggestion please?
You have to make another foreach() loop Because your subcategories belongsToMany categories. row->categories returns a collection, not an object. Thus the error.
<td>{{$row->name}}</td>
<td>{{$row->categories->name}}</td>
#foreach($row->categories as $category)
<td>{{$category->name}}</td>
#endforeach
Update
Getting a category with all subcategories. Simply invert your query
$category = Category::with('subcategories')
->where('name', '=', 'cars')
->first();
//will return you the category 'cars' with all sub categories of 'cars'.
Without eager loading
$category = Category::find(1);
$subacategories = $category->subcategories;
return view('Subcategory::category_subcategory', compact('category', subcategories));

Categories