Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

t0berius's avatar

sortCollection (special case on "year" switch)

The following code is used to generate a collection used to generate a chart:

    $pastDays = 7;

    $signUpsLastWeek = User::whereDate('created_at', '>=', now()->subDays($pastDays))->select('created_at')->get();

    //group them now by date
    $signUpsLastWeek = $signUpsLastWeek->groupBy(function($item) {
        return $item->created_at->format('m.d');
    });

    //group them now by date now, using collection operations
    $signUpsLastWeek = $signUpsLastWeek->mapWithKeys(function ($userGroup, $key) {
        return [$key => $userGroup->count()];
    });

    //insert empty records inside collection for dates where no users signed up
    for ($days_backwards = 0; $days_backwards <= $pastDays; $days_backwards++) {
        if(!$signUpsLastWeek->has(today()->subDays($days_backwards)->format('m.d')))
            $signUpsLastWeek->put(today()->subDays($days_backwards)->format('m.d'), 0);
    }

    //reverse order, so the latest records will be at the end of the collection (for graph rendering)
    $signUpsLastWeek = $signUpsLastWeek->sortKeys(SORT_NUMERIC);

    $signUpsLastWeek = $signUpsLastWeek->mapWithKeys(function ($item, $key) {
        //make sure the key is formatted from MM.DD to DD.MM
        return [explode(".", $key)[1] . "." . explode(".", $key)[0] => $item];
    });

Running this code now returns a collection like:

Illuminate\Support\Collection {#1805 ▼
#items: array:8 [▼
    "01.01" => 0
    "02.01" => 0
    "03.01" => 0
    "04.01" => 0
    "05.01" => 0
    "06.01" => 0
    "07.01" => 0
    "31.12" => 0
]
}

Any idea how to fix?

The main advantage of using a collection is we only generate one SQL query, otherwise this would trigger one query for every day, using this approach was fine for us, but now because of the "switch" inside the months the chart seems strange, because 31.12 is listed at the end.

0 likes
3 replies
automica's avatar

@t0berius it doesnt seem strange for 31.12 to be at the end as it is after 07.01. If you want it before i would suggest using date as key in YY.MM.DD format

t0berius's avatar

@automica

Any idea how I can switch to d.m.y in the end?

The problem seems to be

    //reverse order, so the latest records will be at the end of the collection (for graph rendering)
    $signUpsLastWeek = $signUpsLastWeek->sortKeys(SORT_NUMERIC);

I already switched all formats from m.d to m.d.y.

New code:

    //group them now by date
    $signUpsLastWeek = $signUpsLastWeek->groupBy(function($item) {
        return $item->created_at->format('m.d.y');
    });

    //group them now by date now, using collection operations
    $signUpsLastWeek = $signUpsLastWeek->mapWithKeys(function ($userGroup, $key) {
        return [$key => $userGroup->count()];
    });

    //insert empty records inside collection for dates where no users signed up
    for ($days_backwards = 0; $days_backwards <= $pastDays; $days_backwards++) {
        if(!$signUpsLastWeek->has(today()->subDays($days_backwards)->format('m.d.y')))
            $signUpsLastWeek->put(today()->subDays($days_backwards)->format('m.d.y'), 0);
    }

    //reverse order, so the latest records will be at the end of the collection (for graph rendering)
    $signUpsLastWeek = $signUpsLastWeek->sortKeys(SORT_NUMERIC);
automica's avatar

if you set your keys as YYYYMMDD eg 20210107 then you should be able to order numeric.

Please or to participate in this conversation.