Single category and multi categories - php

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

Related

Get nested belongstomany in laravel

Hello I have a question:
I have three things :
Top Category
Category
Product
I want to have this : Top Category -> Category -> Product
So I can get all nested information to one Top Category
My Models :
class Overcategory extends Model
{
use HasFactory;
protected $fillable = [
'name',
'img',
];
public function categories()
{
return $this->belongstoMany(Category::class);
}
}
class Category extends Model
{
use HasFactory;
protected $fillable = [
'category_title',
'category_description',
'category_preview_img',
'over_categories_id',
'order',
'price'
];
public function product()
{
return $this->belongstoMany(Product::class);
}
public function overcategories()
{
return $this->belongstoMany(Overcategory::class);
}
}
class Product extends Model
{
use HasFactory;
protected $fillable = [
'product_title',
'product_desc',
'product_preview_img',
'product_price',
];
public function category()
{
return $this->belongstoMany(Category::class);
}
}
And my code to get the Top Category with Category is this :
$relationsship = Overcategory::with('categories')->get();
How would I get the categories with their product too?
In order to get all Overcategory with their Category and their Product, you can use the dot notation when you eager load the relationships.
$relationsship = Overcategory::with('categories.product')->get();
// will get you all the Overcategories with a Categories relationshiop and inside each Category, the Products will be loaded.
This also works the exact same way when you are working on eloquent collections instead of a query builder, with the load method instead of with.
If you want to read more on this topic, here is the documentation https://laravel.com/docs/9.x/eloquent-relationships#querying-relationship-existence.
Quick note aside, if a relationship returns multiple items (which is the case with product) it should be plural (products).

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

how to display video per category in laravel eloquent

model video
protected $table = 'lokit_video';
protected $fillable =
[
'title',
'cover_img',
'trailer',
'url',
'order_',
'active',
'description',
'lokit_category_id',
'duration'
];
public function lokit_category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
model category
protected $table = 'lokit_category';
protected $fillable = ['name'];
in controller
public function index(){
$dataCategory = Category::all();
$dataVideo = Video::all();
$video = Video::where('lokit_category_id', $dataCategory)->get();
dd($video);
return View('bnpt.content.home',compact('dataCategory','dataVideo'));
}
when I try the code above what happens with the code is null, how to fix it?
If you want to get all the videos related to all the categories, you should develop the relationship.
In Category Model:
public function videos()
{
return $this->hasMany(Video::class);
}
In the controller method:
$dataCategory = Category::all();
return View('bnpt.content.home',compact('dataCategory'));
In the view file:
<ul>
#foreach($dataCategory as $category)
<li><span>{{$category->name}}</span>
<ul>
#foreach($category->videos as $video)
<li><span>{{$video->name}}</span></li>
#endforeach
</ul>
</li>
#endforeach
</ul>
[PROBLEM]In your code you have
$dataCategory = Category::all();
$video = Video::where('lokit_category_id', $dataCategory)->get();
$dataCategory is a collection of the model instances of all the entries in your lokit_category table.
[SOLUTION]
You can't compare a collection with a field that expects an id in your case in the where statement.
lokit_category_id should be compared with the id of a category.
If you have the lokit_category_id
$videos = Video::where('lokit_category_id', $lokit_category_id)->get();
dd($videos);
If you have the name of the lokit_category, get the id using that name and then make the query.
// Get the category for which you want to get all the videos.
$categoryName = 'CATGEORY NAME';
$category = Category::where('name', $categoryName)->first();
$videos = Video::where('lokit_category_id', $category->id)->get();
dd($videos);
[IF YOU WANT VIDEOS WITH RESPECT TO A CATEGORY]
In your Category Model
public function videos(){
return $this->hasMany(App\Video::class, 'lokit_catgeory_id', 'id');
}
Controller
Use eager loading as it will help in reducing the number of queries.
$categories = Category::with('videos')->get();
foreach($categories as $category){
// You can access the videos for the category using the videos relation.
$category->videos;
}

Pagination for nested items in the Laravel relationship

I am very beginner in Laravel. I use in my project Laravel 5.8.
I have this code:
class ForumCategory extends Model
{
use scopeActiveTrait;
protected $quarded = ['id'];
protected $fillable = ['company_id', 'enable', 'name', 'url_address', 'enable'];
public $timestamps = false;
public function themes()
{
return $this->hasMany('App\ForumPost', 'id_category', 'id')->where('parent_id', '=', null);
}
public function lastPost()
{
return $this->themes()->orderBy('id', 'desc')->first();
}
}
class ForumPost extends Model
{
use scopeActiveTrait;
protected $quarded = ['id'];
protected $fillable = ['company_id', 'id_category', 'parent_id', 'user_id', 'date', 'title', 'content', 'url_address', 'enable'];
public $timestamps = true;
protected $table = 'forum';
public function category()
{
return $this->belongsTo('App\ForumCategory', 'id_category');
}
public function author()
{
return $this->belongsTo('App\User', 'user_id');
}
public function postCount()
{
return $this->hasMany('App\ForumPost', 'parent_id', 'id')->where('parent_id', '!=', null)->count();
}
}
When I run this function:
ForumCategory::with('themes')->orderBy('name', 'asc')->paginate(35);
I have pagination only for pagination.
When I display the results of this function:
#foreach ($forums as $forum)
Welcome in {{ $forum->name }}<br/>
#foreach ($forum->themes as $post)
Post: {{ $post->title }}
#endforeach
<div class="paginationFormat"></div>
<div class="text-right">{{ $forums->links() }}</div>
#endforeach
I can display pagination for $ forums.
I would also like to display the pagination for $ post (data from relationships). How can this make it?
Maybe you could take a look at the Pagination documentation and examples from the Laravel docs: https://laravel.com/docs/5.8/pagination
The Laravel docs are a great place to start since everything is documented very well and there are a lot of examples.
If you want to add a page that paginates all posts, just return a view with Post::sortBy('name')->paginate() and use $posts->links().
If you have to do pagination an Eager loading constraint - it won't work, else you would have to use the constraint to execute the query as the parent Model/Object.
Refer to this link, go through it. https://laracasts.com/discuss/channels/laravel/paginate-constrained-eager-load
Use Themes as the Parent Object and paginate accordingly depending on the relationship defined in the models.
Themes::with(['forumCategory'=>function(query){
//condition here....
}])-paginate(10);
Or alternatively you have multiple paginations in one view but passed separately:
$themes = Themes::with('forumCategory')-paginate(10);
$forums = ForumCategory::with('themes')->orderBy('name', 'asc')->paginate(35);
Same issue in this link: Laravel Multiple Pagination in one page
And you might have to write an anonymous helper function to handle relative actions that involve both Models somewhere in your application.
Alternatively you could use lazyEager loading on the post model. So while you have this in your code, you could do lazy eager loading on the themes.
$forums = ForumCategory::with('themes')->orderBy('name', 'asc')->paginate(35);
$forums->load(['themes' => function($query) {
$query->take(5);
}]);
you could also utilize the loadCount() function.

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