I'm trying to do that , get list of topics order by who has new post so I create a relation in topic model like that
public function latest_post()
{
return $this->hasOne(Post::class)->latest();
}
then I used the query like that
Topic::where('locale',$this->locale)->with('latest_post')->paginate(15)->sortByDesc('latest_post.created_at');
but it's giving me an error
Collection::render does not exist
so I change the sort to orderBy like that
Topic::where('locale',$this->locale)->with('latest_post')->orderBy('latest_post','DESC')->paginate(15);
but this also gives me another error
Unknown column 'latest_post' in 'order clause'
how can solve this issue?
Hmmm. Try this
$topic = Post::orderBy('created_at','desc')->first()->join('topics', 'topics.id', '=', 'posts.topic_id')->first();
Or in your post model:
public function Topic()
{
return $this->belongsTo(Topic::class, 'topic_id');
}
To get the last active topic:
$topic = Post::orderBy('created_at','desc')->first()->Topic;
Related
Hello I have Post model with relation:
public function category()
{
return $this->belongsTo(category::class);
}
I need show posts on every tab of category. For this I need use groupBy. When I do this:
$posts = Post::with('category')->groupBy('category.title')->get();
I get error:
Column not found: 1054 Unknown column 'category.title'.
Why? How I can return my posts with key of category title?
For multilangual I use this package: https://github.com/spatie/laravel-translatable
Try Collection's group-by method:
$posts = Post::with('category')->get()->groupBy('category.title')->all();
You may pass a callback to return the value you wish to key the group by (as you mentioned you are using laravel-translatable package):
$posts = Post::with('category')->get()->groupBy(function ($post, $key) {
return $post->category->getTranslation('title', 'fr');
})->all();
You can use something like this:
$posts = Post::all()->groupBy('category_id')->get();
and then in blade files you can foreach tabs and find a name by category_id
I have got three tables in laravel like so:
Users, posts, and comments
I'm trying to come up with a query that fetches me all the user's posts, plus the date of last comment with each post.
Approach i've taken that's not working perfectly is:
$posts = User::find($userId)->posts()->with('latestComment')->get();
In my Post model I have:
public function latestComment()
{
return $this->hasOne(Comment::class)->latest();
}
In my findings, i haven't been to see a way to get the date from the lastComment load.
Any pointers welcome,
Thanks
Just discovered one needs to add the foreign key to the select method like so:
return $this->hasOne(Comment::class)->latest()->select('field','foreign_key');
You should use eager loading constraint. Code from the other answers will first load all comments, which you don't want.
$posts = Post::where('user_id', $userId)
->with(['comments' => function($q) {
$q->taletst()->take(1);
}])
->get();
You can use the existing relationship and get the latest comment.
public function comments() {
return $this->hasMany(Comment::class);
}
public function latestComment() {
return $this->comments()->last();
}
I have 3 models
User
Channel
Reply
model relations
user have belongsToMany('App\Channel');
channel have hasMany('App\Reply', 'channel_id', 'id')->oldest();
let's say i have 2 channels
- channel-1
- channel-2
channel-2 has latest replies than channel-1
now, i want to order the user's channel by its channel's current reply.
just like some chat application.
how can i order the user's channel just like this?
channel-2
channel-1
i already tried some codes. but nothing happen
// User Model
public function channels()
{
return $this->belongsToMany('App\Channel', 'channel_user')
->withPivot('is_approved')
->with(['replies'])
->orderBy('replies.created_at'); // error
}
// also
public function channels()
{
return $this->belongsToMany('App\Channel', 'channel_user')
->withPivot('is_approved')
->with(['replies' => function($qry) {
$qry->latest();
}]);
}
// but i did not get the expected result
EDIT
also, i tried this. yes i did get the expected result but it would not load all channel if there's no reply.
public function channels()
{
return $this->belongsToMany('App\Channel')
->withPivot('is_approved')
->join('replies', 'replies.channel_id', '=', 'channels.id')
->groupBy('replies.channel_id')
->orderBy('replies.created_at', 'ASC');
}
EDIT:
According to my knowledge, eager load with method run 2nd query. That's why you can't achieve what you want with eager loading with method.
I think use join method in combination with relationship method is the solution. The following solution is fully tested and work well.
// In User Model
public function channels()
{
return $this->belongsToMany('App\Channel', 'channel_user')
->withPivot('is_approved');
}
public function sortedChannels($orderBy)
{
return $this->channels()
->join('replies', 'replies.channel_id', '=', 'channel.id')
->orderBy('replies.created_at', $orderBy)
->get();
}
Then you can call $user->sortedChannels('desc') to get the list of channels order by replies created_at attribute.
For condition like channels (which may or may not have replies), just use leftJoin method.
public function sortedChannels($orderBy)
{
return $this->channels()
->leftJoin('replies', 'channel.id', '=', 'replies.channel_id')
->orderBy('replies.created_at', $orderBy)
->get();
}
Edit:
If you want to add groupBy method to the query, you have to pay special attention to your orderBy clause. Because in Sql nature, Group By clause run first before Order By clause. See detail this problem at this stackoverflow question.
So if you add groupBy method, you have to use orderByRaw method and should be implemented like the following.
return $this->channels()
->leftJoin('replies', 'channels.id', '=', 'replies.channel_id')
->groupBy(['channels.id'])
->orderByRaw('max(replies.created_at) desc')
->get();
Inside your channel class you need to create this hasOne relation (you channel hasMany replies, but it hasOne latest reply):
public function latestReply()
{
return $this->hasOne(\App\Reply)->latest();
}
You can now get all channels ordered by latest reply like this:
Channel::with('latestReply')->get()->sortByDesc('latestReply.created_at');
To get all channels from the user ordered by latest reply you would need that method:
public function getChannelsOrderdByLatestReply()
{
return $this->channels()->with('latestReply')->get()->sortByDesc('latestReply.created_at');
}
where channels() is given by:
public function channels()
{
return $this->belongsToMany('App\Channel');
}
Firstly, you don't have to specify the name of the pivot table if you follow Laravel's naming convention so your code looks a bit cleaner:
public function channels()
{
return $this->belongsToMany('App\Channel') ...
Secondly, you'd have to call join explicitly to achieve the result in one query:
public function channels()
{
return $this->belongsToMany(Channel::class) // a bit more clean
->withPivot('is_approved')
->leftJoin('replies', 'replies.channel_id', '=', 'channels.id') // channels.id
->groupBy('replies.channel_id')
->orderBy('replies.created_at', 'desc');
}
If you have a hasOne() relationship, you can sort all the records by doing:
$results = Channel::with('reply')
->join('replies', 'channels.replay_id', '=', 'replies.id')
->orderBy('replies.created_at', 'desc')
->paginate(10);
This sorts all the channels records by the newest replies (assuming you have only one reply per channel.) This is not your case, but someone may be looking for something like this (as I was.)
I have a table named replies contains all replies of a topic in a Forum laravel application.
**replies Table**
---------------
reply_id
content
topic_id
reply_by
embed_reply
created_at
updated_at
replies can have another reply Herself.for that there is embed_reply column that hold reply_id of included reply.
Now I want details of included reply would have existed on the parent Reply on fetching.
for that i add this Method to reply Model :
public function included_reply ()
{
return $this->with('replies', function ($query) {
$query->where('reply_id',$this->embed_reply);
});
}
And for fetching replies of a specific Topic, I wrote this :
$topic = Topic::whereTopicId($id)
->with([
'replies' => function ($query) {
$query->orderBy('created_at', 'desc');
}
, 'replies.included_reply'
])
->first();
all of this return bellow Error:
BadMethodCallException in Builder.php line 2071:
Call to undefined method Illuminate\Database\Query\Builder::replies()
and I do not know how to do that.
what is solution?
I got my answer in:
laracasts.com/discuss
This is relationship that I must be added:
public function embed()
{
return $this->belongsTo(Reply::class, 'embed_reply');
}
and this for fetching that :
$reply = Reply::find($reply_id);
$embed = $reply->embed;
I have an application with a basic forum system where users can "like" a topic multiple times. My models extend Eloquent and I'm trying to get the sum of votes a user has for a specific topic... Basically, I'm trying to accomplish something like:
$votes = Auth::user()
->votes->has('topic_id', '=', $topic->id)
->sum('votes');
However, when executing this, I get the following error...
Call to a member function sum() on a non-object
I've also tried
public function show($forumSlug, $topicSlug)
{
$topic = Topic::whereSlug($topicSlug)->first();
$votes = Topic::whereHas('votes', function ($q) use ($topic)
{
$q->where('topic_id', '=', $topic->id)->sum('votes');
});
dd($votes);
}
However, with that I receive an error stating:
Unknown column 'ideas.id' in 'where clause' (SQL: select sum(votes)
as aggregate from votes where votes.idea_id = ideas.id and
idea_id = 1)`
You may try something like this (Not sure about your relationship but give it a try):
$topic = User::with(array('topics' => function ($query) use ($topic_id) {
// $query = Topic, so it's: Topic::with('votes')
$query->with('votes')->where('topics.id', $topic_id);
}))->find(Auth::user()->id)->topics->first();
// Count of total votes
dd($topic->votes->count());
P/S: If it doesn't work then please post your model's relationship methods.
I managed to get it working, though I'm not sure I like this approach. I'd love to hear if anyone knows of a better way of doing this...
Basically, I used my relationships to filter() the votes and then used sum() on the filtered collection.
public function show($forumSlug, $topicSlug)
{
$userId = is_null(Auth::user()) ? false : Auth::user()->id;
$topic = Topic::whereSlug($topicSlug)->first();
$votes = $topic->votes->filter(function ($votes) use ($userId)
{
return $votes->user_id == $userId;
})->sum('votes');
return View::make('forums.topics.show', compact('topic', 'votes'));
}