Reputation: 8085
I'm working on an API endpoint with Laravel Spark.
This endpoint returns the given Team along with its users.
// in App\Team
public function users()
{
return $this->belongsToMany(
'App\User', 'team_users', 'team_id', 'user_id'
)->withPivot('role');
}
However, I wish to order those users by a method that is on the user model.
On my App\User model I have a method:
public function currentQueueLength()
{
returns an integer based upon the users current appointments,
}
Is there any way I can return the users relationship but order the users by the result of that method?
Upvotes: 0
Views: 698
Reputation: 12358
If you add current_queue_length
as an attribute to the User
model, you can then order by this attribute.
You can add the attribute by adding it to the $appends
array and creating an accessor:
class User extends Model {
protected $appends = ['currentQueueLength'];
public function getCurrentQueueLengthAttribute()
{
return $this->currentQueueLength();
}
}
Credit to this question: Add a custom attribute to a Laravel / Eloquent model on load?
Then in Team
you can add the method like so:
class Team extends Model {
public function users()
{
return $this->belongsToMany(
'App\User', 'team_users', 'team_id', 'user_id'
)->withPivot('role');
}
public function usersByCurrentQueueLength()
{
return $this->users->orderBy('current_queue_length');
}
}
As mentioned in my comment, the issue with this approach is that it sounds like currentQueueLength()
is a costly operation (based on your comment) so ideally, it would be something you could do conditionally, however, I'm unsure how to do that! You may want to reconsider your approach to implementing currentQueueLength()
which may open up more options to the way you structure this query.
Upvotes: 1
Reputation: 11083
You can acheave this by sorting the users like this :
Team::with('users')
->all();
$team->users->sort(
function ($user1, $user2) {
return $user1->currentQueueLength() - $user2->currentQueueLength();
}
);
More information about sort : To sort in ascending order, return -1 when the first item is less than the second item. So you can use :
return $user1->currentQueueLength() < $user2->currentQueueLength() ? -1 : 1;
And to sort in descending order, return +1 when the first item is less than the second item.
return $user1->currentQueueLength() < $user2->currentQueueLength() ? 1 : -1;
And if it's a field in the users model you can do it like this :
$teams = Team::with(['users' => function ($q) {
$q->orderBy('Field', 'asc'); // or desc
}])->all();
For the case of property :
// asc
$team->users->sortBy('userProperty');
// desc
$team->users->sortByDesc('userProperty');
Hope that helps :)
Upvotes: 0