I have a few models such as User, Post, Comment, etc.
In the User, I have:
public function posts()
{
return $this->hasMany('Post');
}
I can get the first post via $customer->posts()->first(), but what if I want to get the latest Post? There is no last() as I can see.
This is further compounded by a hasManyThrough relationship (unfortunately we inherited a wacky schema):
public function comments()
{
return $this->hasManyThrough('Comment', 'Post');
}
If I try to do an $this->comments()->orderBy('comments.id', 'desc')->first(); it returns a User object??
No, this
// User model
$this->comments()->orderBy('comments.id', 'desc')->first();
won't return User model.
And to get what you asked for, simply do this:
$customer->posts()->latest()->first();
Related
To keep things simple, I'll give an example in code to what I'm trying to Achieve.
Let's assume that we have a model called User with the following code:
class User
{
public function posts()
{
return $this->hasOne(Post::class);
}
}
And the Post model look something like this.
class Post
{
public function comments()
{
return $this->hasMany(Comment::class);
}
}
And now what I want to be able to do is for example:
$user = Auth::user();
$comments = $user->post->comments; //here, I only want the "comment_id" and "comment_content" fields to be included, not all the Comment Model fields !
you can simply use hasManyThrough in user model to connect comments table.
read about hasManyThrough here: docs
and after having a relation between user and comments (hasManyThrough)
you can use load (Lazy eager loading) method
there is an piece of code you can use here
$user->load(["comments" => function($q){
$q->select("comment_id","comment_content");
}]);
read more about Lazy eager loading: docs
I have a model called CallbackRequest the model has a relationship with Loan model and that is the only relationship for CallbackRequest model.
CallbackModel:
public function loan() {
return $this->belongsTo(Loan::class);
}
Now Loan model itself has a relationship with a third model called Applicant.
Loan Model:
public function applicant() {
return $this->belongsTo(Applicant::class);
}
My point:
When I load CallbackRequest I eagerload loan model with it, all fine! But now I am wondering if there is a way to eagerload applicant model when I do:
Right now I access it like:
$modelResults = PublicCallback::with('loan')->get();
I get all callbacks with loan eagerloaded, but my point is I want when I eagerload loans in this case I want applicant to be loaded also !
Is there any way how to do this, is it possible ?
You can do this with:
$modelResults = PublicCallback::with(['loan', 'loan.applicant'])->get();
Ref: https://laravel.com/docs/5.5/eloquent-relationships#eager-loading
Just for posterity, there's also another way of loading nested relationships that can be done against a returned model, provided you have set up the relationships correctly:
Posts model:
public function comments() {
return $this->hasMany('App\Comment', 'quote_id', 'id');
}
Comments model:
public function user() {
return $this->belongsTo('App\User');
}
Then you can actually infer the user via relationship to a comment by drawing the post but loading an array of relations, eg:
$post = \App\Post::find($post_id);
return $post->load(['comments','comments.user']);
I am trying to Order the Posts table by the number of votes a Post has got.
The votes are stored in an other table
(Votes: post_id, user_id, vote_type)
Post-Model:
class Post extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
public function votes()
{
return DB::table('votes')->where('post_id','=',$this->id)->sum('vote_type');
}
}
The votes functions returns the number of votes a post has recieved(The Votes a stored in a seperate table)
Now I am trying to order all the Posts by the number of votes they have got.
Post::get()->sortBy('votes');
This returns follwing Error:
Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
I would be thankful about any help to fix this!
give it a try
Post::get()->sortBy(function($query){
return $query->votes();
});
Alternative
You can use withCount() as it will place a {relation}_count column on your resulting models.
Post::withCount(['votes'])
->orderBy('votes_count')
->get()
For Pagination
Refer docs for more details on paginations
Post::withCount(['votes'])
->orderBy('votes_count')
->paginate();
Add the following function in your Post Model
protected static function boot()
{
parent::boot();
static::addGlobalScope('voteCount', function ($builder) {
$builder->withCount('votes');
});
}
Now, each of your post model will always have a voteCount value and You can sort on that.
In your controller, use:
Post::get()->sortBy('voteCount');
Keep in mind that this will always return a votesCount with the PostModel, but I'm assuming it will be required as it usually does in this kind of applications.
If you want to sort votes as a attribute you have to to make it to be attribute by adding getVotesAttribute() method in your Post Model.
class Post extends Model
{
public function user()
{
return $this->hasOne(User::class);
}
public function getVotesAttribute()
{
return DB::table('votes')->where('post_id','=',$this->id)->sum('vote_type');
}
}
I have the reply relationship with like & unlike model. User can like for their best reply and unlike for bad reply.
The like & unlike relationship is almost same,just store in different table.
Now i want to get the replies that having most like & reply that having most unlike, compare them and show only the replies which have most number of vote. How can i achieve it?
In my Discussion Model
public function replies(){
return $this->hasMany('App\Forum\Reply');
}
In Reply Model
public function discussion(){
return $this->belongsTo('App\Forum\Discussion');
}
public function user(){
return $this->belongsTo('App\User');
}
public function likes(){
return $this->hasMany('App\Forum\Like');
}
In the like model
public function user(){
return $this->belongsTo('App\User');
}
public function reply(){
return $this->belongsTo('App\Forum\Reply');
}
I think you can use Eloquents withCount here.
So you'd have something like:
$mostLikedReply = Reply::withCount('likes')->orderBy('likes_count', 'desc')->first();
$mostUnlikedReply = Reply::withCount('unlikes')->orderBy('unlikes_count', 'desc')->first();
Note that withCount will place a {relation}_count column on your resulting models. That's why the orderBy is ordering on what the withCount applies, then by grabbing the first result, it should be the highest liked/unliked reply, from here you can compare what you need.
Read more about counting relations here
How about
$mostLikedReply = $discussion->replies->sortByDesc(function($reply) {
return $reply->likes->count();
}->first();
This will give you the model for the most liked reply.
And the same for most unliked reply and then compare the two? I guess at that point you can maybe merge the whole stuff if you need to.
I have three tables like this:
**Users**
id
**Posts**
id
user_id
**Favorites**
id
user_id
post_id
Currently, I made it so when I query my posts for display, it pulls all the related user data who created the post with that row which is great! But what I'm trying to do now is also add to see if the user Authorized (Logged in) has favorited the post (row) so I can display to that they already favorited it. I don't want to re-query for every post (i think its called the N+1 problem?). I'm using Laravel4
Post model
class Post extends Eloquent{
public function user(){
return $this->belongsTo('User');
}
User model
public function posts(){
return $this->hasMany('Post');
}
PostsController
public function index()
{
$posts = Post::with('user')->paginate(25);
return View::make('index', compact('posts'));
}
Step 1. Add favorites relationship in Post model.
public function favorites() {
return $this->hasMany('Favorite');
}
When querying the Model.
$auth_user_id = Auth::user()->id;
$posts = Post::with(array('user', 'favorites' => function($query) use ($auth_user_id){
$query->where('user_id', '=', $auth_user_id);
}))->get();
For more information refer to the eager load constraints,
http://laravel.com/docs/eloquent#eager-loading
Adding a many-to-many relationship using the favorites table as pivot would be one approach.
Add favorites relationship in User model:
public function favorites() {
return $this->belongsToMany('Post', 'favorites');
}
You should then be able to get all favorites by simply accessing
Auth::user()->favorites
To find whether the current post is a favorite, use
$isFavorite = Auth::user()->favorites->has($post->id);