Search code examples
phplaravelmany-to-many

Laravel Eloquent: ordering Many-to-Many query- user favorites first



My Laravel app returns a list of ships for users to manage. I want to return ships that are "favorited" by the active user before the rest of the ships. eg:

  • Best ship (*)
  • Ship I manage often (*)
  • Another ship
  • Beta ship
  • Cornelia

I have a many-to-many relationship between User and Ship, where ship->userFavorite returns the users who have "favorited" the ship.

I can imagine 2 solutions, but I'm not sure if they are possible and how to implement them if they are.

  1. An orderby query that sorts based on favorite being equal to active user

    $ships = Ship::orderby([ship->userfavorite being equal to Auth::User()], 'ASC')
    ->orderby('name', 'ASC')->get();
    
  2. My current solution: I use a wherehas query to return the favorited ships first ($favships), and use another query to return all the ships ($ships). For this solution I would like to remove the favoried ships from the second query. But how can I elegantly remove these ships from the results?

    $user = Auth::user();
    $favships = Ship::wherehas('userFavorite', function($q) use($user)
    {
        $q->where('id', $user->id);
    })->orderBy('name', 'ASC')->get();
    $ships = Ship::orderBy('name', 'ASC')->get();
    

Any help to increase my understanding of this problem would be greatly appreciated!


Solution

  • you can use

    $normalShips= $ships->diff($favships);
    

    But I think you can reduce from 2 queries to 1 query:

    //Ship.php
    public function currentUserFavorite() {
         $this->userFavorite()->where('id', Auth::user()->id);
    }
    
    
    // get all ships
    $ships = Ship::with('currentUserFavorite')->orderBy('name', 'ASC')->get();
    
    // finally
    $favships = $ships->where('currentUserFavorite.0.id', Auth::user()->id);
    $normalShips = $ships->diff($favships);
    
    // or do a loop 
    foreach ($ships as $ship) {
        if ($ship->currentUserFavorite->count() > 0) {
          $favships[] = $ship;
        } else {
          $normalShips[] = $ship;
        }
    }