Laravel Relationships - Select rows with same column value in blade - laravel

Let's say I have a post with many comments and I properly defined $post->comments relation in my post model. Comments have a column named confirmed with the value of 0 or 1. How can I select confirmed (rows which have confirmed value of 1) rows in my blade template?

This can help you
In your Post model
public function comments()
{
return $this->hasMany(Comment:class);
}
public function confirmedComments()
{
return $this->comments()->whereConfirmed(1);
}
And from your controller
$comments = $post->confirmedComments;
If in blade, you want select confirmed comments, it's so easy to do it with
#if($comment->confirmed)
//confirmed comment
#else
//
#endif
Hope it'll be helpful !

There are many ways to do this.
If you already have the comments eager loaded, then you can use the where() method on the comments collection:
$confirmedComments = $post->comments->where('confirmed', 1);
This will go through all the comments in the collection and only return those that are confirmed.
If you don't have the existing collection, you can add the where clause to the relationship query. This way, you're only getting confirmed comments from the database, and you're not wasting resources retrieving and building models for comments you're not using
$confirmedComments = $post->comments()->where('confirmed', 1)->get();
And, another option, would be to create a new relationship for just confirmed comments, and that way you can eager load the new relationship:
public function comments()
{
return $this->hasMany(Comments::class);
}
public function confirmedComments()
{
return $this->comments()->where('confirmed', 1);
}
$confirmedComments = $post->confirmedComments;

Related

How to retrieve multiple relations with multiple tables in laravel eloquent

I'm using Laravel 5.8 to build a babysitting site. I have 4 tables with different relationships as below:
please see this image
The relationships are:
Babysitter->hasMany(session)
Sessions->hasOne(Review)
Sessions->hasOne(Kids)
Sessions->hasOne(Babysitter)
Sessions->hasOne(Parent)
I want to achieve 2 things:
First one
I want to show this result when listing all babysitters. I'm showing this information for each babysitter:
plsease see this image
See here what I couldn't achieve
plsease see this image
This is my code
Sitters::where('Status', 'active')->where('Verified', 1)->get();
Second one
Also, I've tried to show kids name with parent review as shown here:
plsease see this image
This is what i'm using
Sessions::select('Reviews.*', 'Sessions.Parent_id')->join('Reviews', 'Reviews.Session_id', '=', 'Sessions.id')->with('owner')->where('Trainer_id', session('user')->Id)->where('Status', '=', 'complete')->with('owner')->orderBy('Sessions.id', 'DESC')->get();
Here is Session.php Model
public function owner(){
return $this->belongsTo('App\Models\Parents', 'Parent_id');
}
As discussed change the relations:
Babysitter->hasMany(sesstion)
Sessions->hasOne(Review)
Sessions->belongsTo(Kids)
Sessions->belongsTo(Babysitter)
Sessions->belongsTo(Parent)
First one
in Babysitter.php declare the following attributes
class Babysitter extends Model
{
public function reviews()
{
$this->hasManyThrough(Review::class, Session::class);
}
public function getAverageReviewAttribute()
{
return $this->reviews()->avg('Rating');
}
}
Then you just need to call it on the model instance.
$babysitter = Babysitter::first();
return $babysitter->average_review;
Second one
Just use the relation
$babysitter = BabySitter::with(['sessions' => public function ($session) {
$session->with(['review','parent','kids']);
})->where('trainer_id', '=', session('user')->Id) //did not understand this condition
->first();
This assumes you have parent, kids and review relation declared on Session::class. (change the names if needed)
After a few days of searching & testing, this is what worked for me:
Inside (Sitters) Model, put this relation
public function sessions()
{
return $this->hasMany(Sessions::class, 'sitter_id')
->withCount('reviews')
->withCount(['reviews as review_avg' => function($query){
$query->select(DB::raw('AVG(Rating)'));
}]);
}
Also, inside (Sessions) Model, put this relation
public function reviews()
{
return $this->hasOne(Reviews::class, 'Session_id');
}
Now you query like this
return $sitters = Sitters::with('sessions')->get();
I hope this can help someone :)

One To Many associate

I have a model Shop and a model Comment.
on the Comment model:
public function shop()
{
return $this->belongsTo('App\Shop', 'commentable_id');
}
The Shop model is:
public function comments() {
return $this->hasMany('App\Comment', 'commentable_id');
}
So the relationship is One To Many
I want to copy all the comments of a Shop and attach them to another Shop:
$shop = Shop::find(1);
$comments = $shop->comments()->pluck('id')->toArray(); // it works, i have all the ids of the comments
$othershop = Shop::find(2);
$othershop->comments()->associate($comments); // doesn't work
$othershop->comments()->attach($comments); // doesn't work
Anyone knows how to proceed with a One to Many situation?
You can utilize createMany method of relationship:
$othershop->comments()->createMany($shop->comments->toArray());
You can also utilize chunking if one shop can have many comments (split it into more queries to make it more memory efficient):
$shop->comments()->chunk(500, function ($comments) use ($othershop) {
$othershop->comments()->createMany($comments->toArray());
});
edit: changed my answer based on comments.
To copy comments, you first need to replicate them. Then you can associate them with their owning model:
$shop = Shop::find(1);
$otherShop = Shop::find(2);
$comments = $shop->comments()->get();
foreach ($comments as $comment) {
$tmp = $comment->replicate();
$tmp->shop()->associate($otherShop);
$tmp->save();
}

How to use where condition in laravel eloquent

I am using laravel eloquent. I have fetched data from two table using eloquent.
I have post table and chat table. For post table I have model Post.php and for chat table I have model Chat.php. Here is the the eloquent relation I have created to fetch chat for individual post for a user.
in Post.php
public function TeamMessage()
{
return $this->hasMany('App\Chat','post_id');
}
And in Chat.php
public function ChatRelation()
{
return $this->belongsTo('App\Post');
}
it is working perfect. But this relation fetch all messages for a specific post. I want to fetch all unread message from chat table. I have a column named unread in chat table.
Now my question is how I can fetch only unread message for a specific post.
While the other answers all work, they either depend on scopes (which are very useful in many circumstances) or on you having already instantiated an instance of $post, which doesn't let you eager load multiple posts with their messages.
The dynamic solution is this, which will let you fetch either 1 or more posts and eager load their messages with subquery:
$posts = Post::with(['TeamMessage' => function ($query) {
$query->where('unread', true); // This part applies to the TeamMessage query
}])->get();
See in documentation
Edit:
If you, however, want to filter the posts, to only show those that have unread messages, you need to use whereHas instead of with:
$posts = Post::whereHas(['TeamMessage' => function ($query) {
$query->where('unread', true); // This part applies to the TeamMessage query
}])->get();
More in the documentation.
You can also chain whereHas(...) with with(...).
For querying relationships, you have to call them as functions instead of properties, like this:
$unreadPosts = $post->TeamMessage()->where('unread', true)->get();
For more information on this you can take a look at the docs.
You need to create a local scope on your model, information on local scopes can be found here: https://laravel.com/docs/5.6/eloquent#local-scopes
public function scopeUnread($query)
{
return $query->where('unread', 1);
}
Then in your controller/view
$unread = $yourmodel->unread()
First I would change your relation names to the name of the entity in lower case:
in Post.php
public function chats()
{
return $this->hasMany('App\Chat','post_id');
}
And in Chat.php
public function post()
{
return $this->belongsTo('App\Post');
}
public function scopeUnread($query)
{
return $query->where('unread', 1);
}
Then you can use
$post->chats()->unread()->get();

Count from hasManyThrough relationship with eager loading (need only Count)

I only need the count, don't want to retrive the results or perform query each time for each row. This is why I want eager loading.
I have 3 tables like the following:
Admins
id
Posts
id
admin_id
Comments
id
user_id //nullable (null if comment from admin)
admin_id //nullable (null if comment from user)
news_id
Now I want to retrieve all the posts from a single admin and all the comments count from those posts, without retrieving all the comments for posts, ONLY COUNT of comments,
With eager loading to avoid n+1 query issue;
Here I think we should make a relation to be used with eager loading like the following:
//admin model
public function commentsCountRelation()
{
return $this->hasManyThrough(Comment::class, News::class, 'admin_id', 'news_id')
->selectRaw('news_id, count(*) as count')
->groupBy('news_id');
}
--Look Here I used hasManyThrough relation because, news_id is not in Admins table.
Then I should make an attribute, to access the count easyly, like:
public function getCommentsCountAttribute()
{
return $this->commentsCountRelation->first()->count ?? 0;
}
Then access it like:
$admin = Admin::with('commentsCountRelation')->findOrFail($id);
$admin->commentsCount;
But it always returns null, why is that?
The following works for hasMany & belongsTo, I've used it on my other models like:
//relation
public function ordersCountRelation()
{
return $this->hasOne(Order::class)->selectRaw('user_id, count(*) as count')
->groupBy('user_id');
}
//attribute
public function getOrdersCountAttribute()
{
return $this->ordersCountRelation->count ?? 0;
}
//Then accessed like:
$user = User::with('ordersCountRelation')->find($id);
$user->ordersCount; //return only count
Any help will be highly appreciated
there is no need for using hasManyThrough.
just use some relations and withCount method:
$admin->posts->withCount('comments')->get();
then you can access it with: $comments_count

Database relation with Laravel Eloquent ORM

I'm new to Laravel and I'm stuck. This is what I am struggling with:
$questions = Question::find($id)->quiz(); // this code retrieves data from
// the table using the primary key
// in the table. The is a parameter
// that is passed via get.
This is what I have right now:
$questions = Question::where('quiz_id', '=', $id)->quiz();
This is the error I get:
Call to undefined method Illuminate\Database\Query\Builder::quiz()
What I want to do:
I want to run a query to get data from my database table using the foreign key in the table not the primary key, I also want to be able to use relations with this as seen from what I tried to do above.
Edit: Added the Question Model
<?php
class Question extends Eloquent{
protected $table = 'quiz_questions';
public function quiz()
{
return $this->belongsTo('Quiz');
}
}
Calling the quiz() function from Question::find($id)->quiz() will return a Query Builder instance allowing you to query the parent of the Question, its not going to return any data at that point until you call ->get() or another method that actually executes the query.
If you're wanting to return all the questions belonging to a certain quiz then you can do it like this.
$questions = Question::where('quiz_id', $id)->get();
This will return an Eloquent\Collection of the results for all questions with a quiz_id that is equal to $id.
If you've setup the relations between the Quiz and Questions then you can also do this using the Laravel relations.
$quiz = Quiz::findOrFail($id);
foreach($quiz->questions as $question)
{
// Do stuff with $question
}
Laravel will automagically pull Questions from the database that belongTo the Quiz you've already got from the database, this is known as eager loading http://laravel.com/docs/4.2/eloquent#eager-loading
Wader is correct, just calling where() will not execute your query. You either call get() and get an iterable result or use first() if you only want one result.
$quiz = Question::where('quiz_id', '=', $id)->first()->quiz();

Resources