Laravel : How to access many to many relationship data Ask - php

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

Related

Single category and multi categories

I have articles witch can have one single category that's Main category with category_id.
and additional multi categories with pivot table everything working it's stores but i can't get data on web i'm only getting articles with single category how can i get articles with single and with multi categories in one variable?
article model:
public function category()
{
return $this->belongsTo(AllCategory::class, 'category_id', 'id');
}
public function manyCategories()
{
return $this->belongsToMany(AllCategory::class, 'articles_categories', 'article_id', 'category_id')
->using(ArticleCategory::class);
}
AllCategory model:
public function articles()
{
return $this->hasMany(Article::class, 'category_id', 'id')->orderBy('published_at', 'Desc');
}
public function manyArticles()
{
return $this->belongsToMany(Article::class, 'articles_categories', 'category_id', 'article_id')
->using(ArticleCategory::class);
}
and pivot table:
class ArticleCategory extends Pivot
{
use HasFactory;
public $table = 'articles_categories';
protected $fillable = [
'article_id', 'category_id'
];
protected $guarded = ['*'];
}
and in controller i'm getting like this
$offsetPage = ($page - 1);
$perPage = 24;
$category = AllCategory::bySlug($slug);
if (! $category) {
abort(404);
}
$categoryArticles = $category->articles()
->with('manyCategories')
->skip($perPage * $offsetPage)
->take($perPage)
->get();
I'm getting single category articles with articles() and i'm trying to get manycategories to ->with but it's only getting me single category articles what i'm doing wrong?
You could create an accessor that would add the main category to the Collection of categories that the Article belongs to.
public function getCategoriesAttribute()
{
// adding the main category (if there is one) to the Collection
return (clone $this->manyCategories)->when(
this->category,
fn ($collection, $category) => $collection->prepend($category)
);
}
Controller:
$categoryArticles = $category->articles()
->with(['category', 'manyCategories'])
->skip($perPage * $offsetPage)
->take($perPage)
->get();
View:
#foreach ($articles as $article)
#foreach ($article->categories as $category)
...
#endforeach
#endforeach
Laravel 8.x Docs - Eloquent - Mutators & Casting - Defining an Accessor
Laravel 8.x Docs - Collections - Available Methods - when
Laravel 8.x Docs - Collections - Available Methods - prepend

How to query Eloquent relational tables based on json ids

I have a articles table with a field named article_categories.
I have a categories table with id field.
In my Article Model I have defined:
public function category(){
return $this->hasMany(Category::class,'id','article_categories');
}
the categories in the articles table are saved as json like ["1","3","24"]
in my ArticleController I want to retrieve all categories of a specific article.
In my edit function in the ArticleController I have this function:
public function edit(Article $article)
{
$category_ids = implode(',',json_decode($article->article_categories)) ; //this gives me 1,3,24
/////////
// HERE SHOULD COME THE QUERY WHICH I DON'T KNOW
// $article_categories = ??????????
////////
$categories = Category::all();
return view('article.edit', compact('articles','categories','article_categories'));
}
From what I've researched, there is no way to do this with Laravel but I don't know if this is true or not. I'm using Laravel 8.
Can anyone help me?
First of all you should know that you violated a many-to-many relation in a single column and that's not valid. What you should do is a pivot table article_category or category_article and in both Article and Category models you will define a many-to-many relation
like so
class Article extends Model
{
public function categories()
{
return $this->belongsToMany(Category::class);
}
}
class Category extends Model
{
public function articles()
{
return $this->belongsToMany(Article::class);
}
}
And in your controller you can do
public function edit(Article $article)
{
$categories = Category::all();
return view('article.edit', compact('article','categories'));
}
And in the view you will have direct access to $article->categories
In your current situation you can do this
public function edit(Article $article)
{
$category_ids = json_decode($article->article_categories)
$article_categories = Category::whereIn('id', $category_ids);
$categories = Category::all();
return view('article.edit', compact('article','categories','article_categories'));
}

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
}
}

Query for get category in view in Laravel

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.

Show data from multiple tables in view laravel

I asked question whose link is:
Link
Now my problem is that I want to show "CategoryName' of in food details.For that I add function in Categories.php model as:
public function food()
{
return $this->hasMany('App\Food','food_categories','Category_id','Food_id');
}
and in food.php
public function restaurant()
{
return $this->belongsToMany('App\Restaurant','food_restaurant','Food_id','Res_id');
}
public function categories()
{
return $this->belongsTo('App\Categories','food_categories');
}
Then in show.blade.php I add:
#foreach ($food->restaurant as $restaurant)
<h3><p>RestaurantName:</h3><h4>{{$restaurant->ResName}}</p></h4>
<h3><p>Contact #:</h3><h4>{{$restaurant->Contact}}</p></h4>
<h3><p>Location:</h3><h4>{{$restaurant->Address_Loc}}</p></h4>
#endforeach
#foreach ($food->categories as $categories)
<h3><p>CategoryName:</h3><h4>{{$categories->CategoryName}}</p></h4>
#endforeach
And I changed controller to :
public function show($Food_id)
{
$food = Food::with('restaurant.categories')->findOrFail($Food_id);
return view('show', compact('food'));
}
But it does not shows me categoryname.Plz help me where is the problem?
With Eager loading, "dot" notation loads nested relations.
In your controller you do
Food::with('restaurant.categories')
..this queries the restaurant() relation on the Food model, and that Restaurant's categories() relation.
I think you might need to call
Food::with('restaurant', 'categories')
as this will query both relations on the Food model.

Categories