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:
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.
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();
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!
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;
}
}