Getting Articles category laravel - php

I want to get category name of articles. This is my CategoriesController:
public function show(Category $category)
{
$articles = $category->articles()->latest()->paginate(5);
return view('categories.index', compact('articles'));
}
When I try to do it like this: {{$articles->category()}}
I'm getting this error: call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\Database\Eloquent\Collection' does not have a method 'category'

You already have the category getting passed to your controller action, so just pass that instance to your view rather than trying to grab it from every article item and potentially adding more database queries to your controller action.
public function show(Category $category)
{
return view('categories.index', compact('articles', 'category'));
}

$articles would, in this case, be a collection of several articles. Therefore you can't simply do {{ $articles->category }}.
This should work, however:
#foreach ($articles as $article)
{{ $article->category }}
#endforeach

Related

Need help using all() and find() in the same function for Laravel

In my layouts, I am displaying all the categories (from my database) using a foreach statement. In the page, it is a page is it shown from the show() function. It seems a little contradicting because I have to use all() for the layout, and find() in the page. Is there any way to work around this?
public function show($id)
{
$categories = category::find($id);
$products = product::all()->sortBy('ID');
$categories = category::all()->sortBy('ID');
return view('categories', compact('products','categories'));
}
In the template
#foreach($categories as $category)
<li class="text-uppercase" style="white-space: nowrap;">{{ $category->name}}</li>
#endforeach
In the page itself ( localhost:8000/category/5 ) I just want to display the name of the category in the page, not display all like in the above code block.
{{ $categories->name}}
When I put both the all() and find() into the same function
This is the error message:-
Property [name] does not exist on this collection instance. (View: C:.............\resources\views\categories.blade.php)
Your problem is you've been overwritten your $categories variable. Once you populate it with single category (via find()) then you override it with all categories (via all()).
You should override your show() function
public function show($id)
{
$category = category::find($id);
$products = product::all()->sortBy('ID');
$categories = category::all()->sortBy('ID');
return view('categories', compact('products','categories', 'category'));
}
You should use $categories variable to get all categories and use $category for getting a single category.

Pulling all categories and grouping them by parent id

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

Laravel - getting relation in loop - best practices

Just an example:
let's say I have Post model, and the Comment model. Post, of course, have Comments, one-to-many relation.
I have to display list of posts with comments below it.
I'll get my posts in the controller:
$posts = Post::get(), I'll pass it to the blade view and then I'll loop through it
#foreach($posts as $post)
{{ $post->title }}
{{ $post->comments }}
#endforeach
where $post->comments is some relation
public function comments()
{
return $this->hasMany(Comment::class);
}
As we know, that query will be executed many times.
Now my question: how we should optimize it?
Return Cache::remember in the getter?
Get (somehow?) those comments, when getting the posts in one query? Something like join query? I know that I can write that kind of query, but I'm talking about Eloquent's query builder. And then how get the comments within the loop? Wouldn't {{ $post->comments }} call the relation again instead of getting stored data?
Different solution?
You can do $posts = Post::with('comments')->get() to eager load the comments with the post. Read more about it in the documentation: https://laravel.com/docs/5.7/eloquent-relationships#eager-loading
Also, to display the comments you would want to add another foreach loop. It would look something like this:
#foreach($posts as $post)
{{ $post->title }}
#foreach($post->comments as $comment)
{{ $comment->title }}
#endforeach
#endforeach
You’ve probably cached some model data in the controller before, but I am going to show you a Laravel model caching technique that’s a little more granular using Active Record models
Note that we could also use the Cache::rememberForever() method and rely on our caching mechanism’s garbage collection to remove stale keys. I’ve set a timer so that the cache will be hit most of the time, with a fresh cache every fifteen minutes.
The cacheKey() method needs to make the model unique, and invalidate the cache when the model is updated. Here’s my cacheKey implementation:
public function cacheKey()
{
return sprintf(
"%s/%s-%s",
$this->getTable(),
$this->getKey(),
$this->updated_at->timestamp
);
}
public function comments()
{
return $this->hasMany(Comment::class);
}
public function getCachedCommentsCountAttribute()
{
return Cache::remember($this->cacheKey() . ':comments_count', 15, function () {
return $this->comments->count();
});
}
yes u can do like that in controller
$minutes = 60;
$posts = Cache::remember('posts', $minutes, function () {
return Post::with('comments')->get()
});
in blade u can get like that
#foreach($posts as $post)
{{ $post->title }}
#foreach($post->comments as $comment)
{{ $comment->title }}
#endforeach
#endforeach
for more information read this article

Laravel Pivot table get value and pass to blade template

i'm trying to get all the Level_id and Term_id on my intermediate table using many to many relationship but i couldn't make it work and i want to pass it to my view using ordered list html.
i always end up with this..Trying to get property of non-object
Controller:
public function get_term_level()
{
$terms=Term::find(1);
foreach ($terms->level as $tm) {
$tm->pivot->Level_id;
}
return view('term_level.index',compact('terms'));
}
Term Model same as with my LevelModel
public function level(){
return $this->belongsToMany(Level::class, 'term_levels')->withPivot('Term_id', 'Level_id');
}
View
#foreach ($terms->pivot as $tm )
<ul>
<li>{{ $tm->Term_id }}</li>
{{ $tm->Level_id }}
</ul>#endforeach
Try this (inside your controller):
foreach ($terms->level()->get() as $tm) {
$tm->pivot->Level_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 }}

Categories