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

Corban's avatar

SortBy and accented words

Hello everyone, I have a problem that I suppose has a really easy and obvious answer that I can't figure right now.

Right now I'm using the simplest of simplest queries to populate a select list. My problem is that when I use ->sortBy('last_name') the majority of names appear in the right order, but two of them that start with "Á" appear at the end of the list. It's there something that I should add? There is no need of the 'Desc' part since the rest of "A" last names appear at the start.

Thanks for your time.

0 likes
10 replies
andonovn's avatar

You may try using the COLLATE keyword (at least that's for MySQL, not sure for the other DB engines).

Something like this should work: ->orderBy('last_name', 'ASC COLLATE latin1_german2_ci')

Ref: official MySQL docs

florianhusquinet's avatar
Level 4

@andonovn It looks like a problem from the sortBy method used on a collection and not the orderBy method used on a query.

@Corban

I don't think sortBy support UTF-8 characters by default, which is the issue here. I've found this solution on stackoverflow:

setlocale(LC_COLLATE, 'fr_FR.utf8'); // No need to set this if you're doing it elsewhere

$collection->sortBy("name", SORT_LOCALE_STRING); // Signals to arsort() to take locale into consideration

https://stackoverflow.com/questions/39374842/laravel-5-3-collection-sort-utf8-strings

Another solution might be to change your query if that's a possibility. MySQL handles sorting pretty well and it will take off a bit of the complexity from your controller/view.

1 like
Corban's avatar

@florianhusquinet yeah it worked! Well, actually I had to make a minor change since it looked like 'fr_FR' didn't work, but changing it to 'French' seemed to do the trick.

I'll take your advice and try to change the query (is just a simple Select id, name, last_name FROM employees OrderBy but since there's no sortByRaw method I suppose you mean a whole raw query without eloquent? I'll check that.

@andonovn thanks, it didn't work but now I know that DB collations can't be passed in the query, they go in the config/database file.

florianhusquinet's avatar

You can use the orderByRaw method to do order your query just like a regular MySQL query if @andonovn's method does not work and MySQL doesn't return the expected results by itself (it might)

Something like this:

$users = Users::orderByRaw('last_name COLLATE utf8_french_ci');
Corban's avatar

I tried the orderByRaw this afternoon before searching and lastly asking. It returns Method orderByRaw does not exist., also tried sortByRaw and the same...

I'll stick with your previous answer until finishing some things tomorrow and I'll begin searching a simpler method in my spare time.

andonovn's avatar

@Corban another option would be orderBy(\DB::raw('last_name COLLATE utf8_french_ci'));

again not tested tho :)

Edit: I am pretty sure that you can pass any raw MySQL keywords in your queries. If you are failing to do that, most probably you are using regular collection methods after the query was executed instead of the query builder's methods. Lots of them are having the same names and that's a common confusion in the Laravel community.

2 likes
florianhusquinet's avatar

I have to agree with @andonovn on this one, it looks like you are trying to execute orderByRaw on a collection after the query has been executed.

The sortBy method should be used on a collection (a collection being wrapper of an array of datas) while the orderBy and orderByRaw methods are meant to be used on the query builder.

Here is an example using both methods and what they should return:

// User is a model, this is a query using Eloquent.
$users = App\Models\User::orderBy('first_name')->get(); 
/*
    [
        [
            'first_name' => 'Benton',
            'last_name' => 'Hanks'
        ],
        [
            'first_name' => 'Johanna',
            'last_name' => 'Smith'
        ],
        [
            'first_name' => 'Laurence',
            'last_name' => 'Colt'
        ]
    ];
*/

// $users is now a collection, sortBy is not querying the database it is simply changing the order of the results fetched earlier.
$sorted = $users->sortBy('last_name');
/*
    [
        [
            'first_name' => 'Laurence',
            'last_name' => 'Colt'
        ],
        [
            'first_name' => 'Benton',
            'last_name' => 'Hanks'
        ],
        [
            'first_name' => 'Johanna',
            'last_name' => 'Smith'
        ]
    ];
*/

You can learn more about collections, query builder and their respectives methods here (and there is a lot...): https://laravel.com/docs/5.5/collections https://laravel.com/docs/5.5/queries

2 likes
Corban's avatar

Oh ok, now I get it. I was sorting after fetching with ->get() since I was using the ::all()method, I'm still getting used to Eloquent.

Thanks @andonovn and @florianhusquinet for the explanation.

1 like
florianhusquinet's avatar

No problem, it can be quite confusing at first, especially when the methods' name are so similar.

1 like
stefanX201's avatar

@FLORIANHUSQUINET -

Route::get('/sort', function() {
    setlocale(LC_COLLATE, 'fr_FR.utf8'); // No need to set this if you're doing it elsewhere

    $collection = collect([
        ["name"=>"maroon"],
        ["name"=>"zoo"],
        ["name"=>"ábel"],
        ["name"=>"élof"]
    ])->sortBy("name", SORT_LOCALE_STRING); // Signals to arsort() to take locale into 

    dd($collection->toArray());
});
array:4 [▼
  0 => array:1 [▼
    "name" => "maroon"
  ]
  1 => array:1 [▼
    "name" => "zoo"
  ]
  2 => array:1 [▼
    "name" => "ábel"
  ]
  3 => array:1 [▼
    "name" => "élof"
  ]
]

seems your example is not working

Please or to participate in this conversation.