0

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?

3
  • What does User::currentQueueLength() do exactly? Commented Jul 25, 2017 at 10:14
  • 1
    @haakym Runs a horrible loop to calculate the total time of a users services. The user is a barber and can have many appointments with services assigned. There are various model relationships but the method returns an integer of minutes. Normally called e.g. $user->currentQueueLength() Commented Jul 25, 2017 at 10:18
  • Gotcha. My first thought is that you could use the $appends attribute and an accessor method to preload the currentQueueLength() as an attribute on the User model, then order by this attribute on your Team:: users() call. The issue with this approach is that it sounds like currentQueueLength() is a costly operation (based on your last comment, is it?) so ideally, it would be something you could do conditionally. Perhaps refactoring your currentQueueLength() may be the first step? Commented Jul 25, 2017 at 10:30

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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 :)

1 Comment

I think @lovelock wants to implement the ordering within the Team::users() call? currentQueueLength is also not currently a property on User, however it could become one with $appends + accessor as I mentioned in my comment on the question, but it may be a costly operation and unwanted besides this instance so perhaps not ideal?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.