Pulling all categories and grouping them by parent id - php

I am working with Laravel data querying and I need a query that is going to group all the children of a parent when I take the categories.
the categories table has a name and a parent_id, the routes of the categories have the parent_id set as null, the query should return every category grouped by parent id and the parent should be the first node of every group.

If you only want to display the categories as parent child somewhere, you do not need to collect them like that, you can make a relationship within the model like
class Category {
public function children()
{
return $this->hasMany(self::class, 'parent_id');
}
public function parent()
{
return $this->hasMany(self::class, 'id', 'parent_id');
}
}
may be it will be one-to-many relationship instead of many-to-many depending on your requirement.
Now you can just get all the parents like
Category::whereNull('parent_id')->get();
or using a scope
Category::parent()->get(); and define the scope in the model
and loop through the parent category like
#foreach ( $categories as $category )
{{ $category->name }}
#foreach ( $category->children as $subCategory )
{{ $subCategory->name }}
#endforeach
#endofreach
and to retrieve parent with children you can use
Category::whereNull('parent_id')->with('children')->get();
or
Category::parent()->with('children')->get();
I have not tested the code, but roughly it will be like this.

contoller
$locations = OurLocation::groupBy('country_id')->with('children')->get();
model
public function children()
{
return $this->hasMany(OurLocation::class, 'country_id','country_id');
}
blade
#foreach($locations as $index=>$location)
#foreach($location->children as $children)
{{ $children->company_name }} <br>
#endforeach
#endforeach

When you get the returned collection from the query, you are able to use the ->groupBy() method where you can specify the field which the results should be grouped by.
Assuming your categories model is Category:
$categories = Category::all()->groupBy('parent_id')->toArray();

Related

create counter for blog categories in laravel

I´m traying to create one counter for my blog´s categories. This should appear to the right name side of my category . i´m using my model with variable appends, that after i will use in my blade for show my result in one span. But i don´t know very well how i can use count in my Model. I´m doing this in my model Blog.
my variable appends contain:
protected $appends = [
'custom_fields',
'has_media',
'restaurant',
'blog_category',
'viewer',
'postCounter',
];
i´m traying this:
return $this->blogs()->count();
i have a relation between blog and blog_category with:
public function blogCategory()
{
return $this->belongsTo(\App\Models\BlogCategory::class, 'blog_category_id', 'id');
}
i want to do in my view appear for example:
innovation (2)
in my view i´m doing this:
#foreach($categories as $category)
<li>{{ trans('web.blog_category_'.$category->name) }}<span>{{$category->postCounter}}</span></li>
#endforeach
but always returned me 0, and i have post with categories
updated
With laravel relationship withCount you can do this easily. If you want to count the number of results from a relationship without actually loading them you may use the withCount method, which will place a {relation}_count column on your resulting models.
add withCount method to your query
$categories = Category::withCount('blogCategory')->get();
You can access the count in your foreach loop
// $category->blogCategory_count
#foreach($categories as $category)
<li>
<a href="{{ url('blogs/'.$category->name) }}">
{{trans('web.blog_category_'.$category->name) }}
</a>
<span>{{$category->blogCategory_count}}</span>
</li>
#endforeach

Laravel relations doesn't return anything

i have problem in laravel eloquent relationships.
there is 2 model in my application: article and category.
article model:
public function category()
{
return $this->belongsToMany('App\Category');
}
category model:
public function article()
{
return $this->hasMany('App\Article');
}
the relation between this tow is hasMany (Category -> article) & belongsToMany (Article -> category).
category will fetch by requested slug using this method at categoryController:
$category = Category::where('slug', '=', $slug)->get();
problem will be shown in view when i want to fetch articles from category and nothhing will return back:
#foreach ($category->article->all() as $article)
{{ $article->name }}
#endforeach
and from #dd($category->article) we will get empty collection:
Collection {#323 ▼
#items: []
}
As #lagbox tried to highlight in a comment, for pivot tables, both relationships should be belongsToMany. Inverse of hasMany is belongsTo.
If one article belongs to many categories, and one category can have many articles, then, ideally, there it should be a many-to-many relationship. Category model should have a belongsToMany relationship with Article model and vice versa. Additionally, there should be a pivot table, article_category. And as many have suggested, you can get articles the belongs to a category by using #foreach($category->articles as $articles)
You can read more about many to many here:
https://laravel.com/docs/5.8/eloquent-relationships#many-to-many
You can use #forelse blade directive like
#forelse ($category->article as $article)
<li>{{ $article->name }}</li>
#empty
<p>No articles</p>
#endforelse
You can check that here
You dont need to write $category->article->all() . $category->article itself will return all articles.
So just use like,
#foreach ($category->article->all() as $article)
{{ $article->name }}
#endforeach
For eager loading articles, you can use
with keyword
$category = Category::with('article')->where('slug', '=', $slug)->get();

How to get two arrays of obiects by one column

Hi i have on table with categories with foreign key to herself where parent_id is the same that id in this table. I want to get two arrays of objects. First with categories where
parent_id=0
and second with subcategories. But I dont know how can I catch this subcategories. I have this:
$category= Category::where('parent_id', '=', 0)->get();
dd($category[0]['id']);
$subcategory= Category::where('parent_id', '=', (($category[0]['id']??)));
First $category shouild return me array of categories and second array with subcategories i need adjust id of each object of array $category to each subcategory array. Is it possible or there are other ways?
If you define your model relations correctly you can get categories and their subcategories in a much nicer way.
First define the relations:
class Category extends Model {
public function parent() {
return $this->belongsTo(Category::class);
}
public function subcategories() {
} return $this->hasMany(Category::class, 'parent_id');
}
You can now get all parent categories with their subcategories the following way:
$parents = Category::whereParentId(0)->with('subcategories')->get();
This will give you list of all parent categories, each of them will have subcategories property that will store all subcategories. You can traverse them in the following way:
foreach ($parents as $parent) {
printf("Parent category %s\n", $parent->name);
foreach ($parent->subcategories as $subcategory) {
printf("Subcategory %s\n", $subcategory->name);
}
}
Small suggestion: make your parent_id nullable and store NULL for parent categories instead of 0, as 0 is not a correct category ID.

Laravel 5 - Count the number of posts that are assigned to each category in a blog

I was wondering what the cleanest way was to count the number of posts that are connected to a category in my blog.
Here is how the table relationship is set up.
What I have is a hasMany relationship from the Category to the Post models like this:
In Categories Model
public function blog_posts()
{
return $this->hasMany('App\Http\Models\Blog_Post', 'category_id');
}
And in the Blog_Post Model
public function blog_categories()
{
return $this->belongsTo('App\Http\Models\BlogCategories', 'category_id');
}
In effect all I want to do is be able to return to my view the total number of posts that each category has as shown below. Where x is the number of posts within each category.
cat1 (x)
cat2 (x)
cat3 (x)
It's not hard to count I know however as I only want a count I do not want to also retrieve the records as they are not required and I also do not want to create more queries than is necessary.
I have not completed the view as yet but probably a start would be to pass through the categories in a loop to display each and add the count at the same time?
#foreach ($categories as $category)
{!! $category->name !!} - {!! Count of posts here !!}
#endforeach
Hopefully that is clear(ish)!
Eager load the relation in your controller:
public function index()
{
$categories = Category::with('blog_posts')->get();
return view('categories.index', compact('categories'));
}
You can then use the count() method on the blog_posts relation when looping over categories in your view:
#foreach ($categories as $category)
<li>{{ $category->name }} ({{ $category->blog_posts->count() }})</li>
#endforeach
EDIT: Since Laravel 5.3, you can use withCount() to load counts of relations, i.e.
$categories = Category::withCount('blog_posts')->get();
This will make the count available via a property:
foreach ($categories as $category) {
$blog_posts_count = $category->blog_posts_count;
}
The nicest way to do it with eager loading support I know is to create a separate relation with the post count. Check this out:
public function blog_posts_count() {
return $this->hasOne('App\Http\Models\Blog_Post', 'category_id')
->selectRaw('category_id, count(*) as aggregate')
->groupBy('category_id');
}
public function getBlogPostsCountAttribute() {
if(!array_key_exists('blog_posts_count', $this->relations))
$this->load('blog_posts_count');
$related = $this->getRelation('blog_posts_count');
return $related ? (int) $related->aggregate : 0;
}
Usage is simple:
{{ $category->blog_posts_count }}

Get posts foreach categories in Laravel

I am using Laravel 4
Here is my Controller:
public function getArticles()
{
$categories = Category::with(['posts' => function($query){
$query->orderBy('updated_at', 'DESC')->take(4)->get();
}])->get();
return View::make('articles', compact('categories'));
}
Here is my View:
#foreach($categories as $category)
<h1>{{$category->title}}</h1>
<ul>
#foreach($category->posts as $post)
<li>
{{ $post->title }}
</li>
#endforeach
</ul>
#endforeach
My Category Model:
class Category extends Basemodel {
public function posts(){
return $this->hasMany('Post');
}
}
And my Post Model:
class Post extends Basemodel {
public function category(){
return $this->belongsTo('Category');
}
}
So it displays correctly my 6 categories (titles), but it only displays 4 posts total, I would like to display the 4 latest posts for each category (24 posts total).
I tried many things, and searched online but couldn't find a way around it.
You can't do that using limit in the eager loading closure, because, as you noticed, it limits the other query, that fetches all the posts.
You can easily get single related model with eager loading for hasMany with a helper relation:
public function latestPost()
{
return $this->hasOne('Post')->latest();
}
but for n related models per each parent, you need a bit more complex solution - take a look at:
n per parent
1 per parent
Maybe you can get use $categories = Category::all() to get all categories first.
foreach $categories and get the latest four posts by $posts=$category->posts
merge the posts array into one array
pass categories and posts to the view.
Cheers.
I hope you can write the correct foreach. And when retrieving the posts, use $category->posts instead of $category->posts(), which results in an error.

Categories