Bastiyan
Bastiyan

Reputation: 646

Laravel Sort Parent Collection by their relationship values

I recently wanted to sort parent elements of a collection by using their relationship values so I came across something like this and It works. Do you think this is a suitable method or am I making this overcomplicated?

Basically, I want to sort the Events by their date

Events have one to many with Slots

Any review on this would be appreciated

Cheers

 $events = Event::with(['slots' => function ($q) {
        $q->orderBy('date');
        $q->orderBy('start_time');
    }])->active()->get();
    


    $slotArray = [];
    foreach($events as $event){
        foreach ($event->slots as $slot) {
               $slotArray[$slot->id] = [ 'id' => $event->id, 'start_date' => $slot->date, 'start_time' => $slot->start_time];
        }
    }
    
    //Sort the Array of IDS
    usort($slotArray, array($this,"sortByStartDate"));

    //Find the New Set of IDS sorted by the Start Date
    $sortedEventIDs = [];
    foreach($slotArray as $value) {
        array_push($sortedEventIDs, $value['id']);
    }

    $sortedEvents = $events->sortBy(function($model) use ($sortedEventIDs){
        return array_search($model->getKey(), $sortedEventIDs);
    });

Sort Function

function sortByStartDate($a, $b){
        return $a['start_date'] > $b['start_date'];
}    

Upvotes: 0

Views: 353

Answers (2)

mrhn
mrhn

Reputation: 18916

There is an SQL approach, that would look something like this. Create an subselect, fetch the date you want to use and order by it.

Event::with(['slots' => function ($q) {
        $q->orderBy('date');
        $q->orderBy('start_time');
    }])
    ->addSelect([
        'date' => Comment::selectRaw('MAX(start_date)')
            ->whereColumn('events.id', 'comments.event_id'),
    ])->orderBy('date');

Simply use Laravel relation and do the same, not as performance optimized but very straight forward aproeach.

$events = Event::with(['slots' => function ($q) {
    $q->orderBy('date');
    $q->orderBy('start_time');
}])->active()->get();

$events->sortBy(function ($event) {
    return $event->slots()->max('start_date');
});

Upvotes: 2

Ali Ali
Ali Ali

Reputation: 1864

You can use orderBy() function:

$events = Event::orderBy('start_time', 'DESC')->active()->get();

and for the IDs, you can use sortKeys():

$sorted = $events->sortKeys();

$sorted->all();

Upvotes: 0

Related Questions