Laravel two queries, how do one query? - php

I have model post. I use this package: https://github.com/cyrildewit/eloquent-viewable
I have accesor in model post:
protected $appends = ['views'];
public function getViewsAttribute()
{
return $this->views()->count();
}
In blade when I foreach my posts:
#foreach($posts as $post)
Views: {{ $post->views }} {{ trans_choice('trans.views', $post->views)
#endforeach
I get two queries with views. And if posts 100, then queries will be 200.. For each post I get two same queries. How I can resolve this? If I delete {{ trans_choice('trans.views', $post->views) Then I get one query.

Given that views is a Laravel relationship, you can use the withCount function to "eager load" the value.
$posts = Post::withCount('views')->get();

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

i cant display posts' category with manyToMany relationship

i cant display posts' category with manyToMany relationship. i build relationship but can't display it.
// here is my post model
public function getCategory(){
return $this->belongsToMany(Category::class,
'post_categories','id','post_id');
}
// here is my controller
public function Allindex(){
$posts=Post::all();
return view('allposts',compact('posts'));
}
//here is my allposts blade
<div class="media-body">
<h4 class="media-heading">{{$post->pivot['name']}}</h4>
{{$post->created_at}}
</div>
You are passing the wrong param in a model relationship.
public function getCategory(){
return $this->belongsToMany(Category::class,'post_categories','post_id','category_id');
}
Now you can access it as below.
#foreach($post->getCategory as $category)
{{ $category->name }}
#endforeach
Or
{{ $post->getCategory->pluck('name')->implode(',') }}
Laravel is not automatically loading your relationship, the keyword you are looking for is eager loading.
You can eager load relationships with the with method like so:
$posts = Post::with('getCategory')->get();

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

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

How to manipulate an object in laravel

I have a laravel query as the one below:
$campaign = Campaign::with(array('tracks.flights' => function($q) use ($dates)
{
$q->whereRaw("flights.start_date BETWEEN '". $dates['start']."' AND '".$dates['end']."'")->orderBy('start_date')
->with('asset')
->with('comments');
}
))
->with('tracks.group')
->with('tracks.media')
->orderBy('created_at', 'desc')
->find($id);
I am very new to laravel and right now the response from this query returns all the data required including the comments with the comments attributes from the DB.
What i want to achieve is manipulate the comments object so it includes the user name from the users table as the comments table has the user_id only as an attribute.
How can I achieve this? I am very new to laravel.
Your Comment model must have a relationship with the User model, such as:
public function user()
{
return $this->belongsTo('App\User');
}
Now when you are iterating comments you are able to do $comment->user->name or in your case it will be something like this:
#if(!$campaign->tracks->flights->isEmpty())
#foreach($campaign->tracks->flights as $flight)
#if(!$flight->comments->isEmpty())
#foreach($flight->comments as $comment)
{!! $comment->user->name !!}
#endforeach
#endif
#endforeach
#endif
Once you can do this, next step is to understand eager load with eloquent.

Categories