1

I have a multidimensional array, and both the parent array and the child arrays are associative.
While there are various ways out there to sort multidimensional arrays with numeric top level and associative child levels by child value (like here or here), I'm lost doing so in my case where the top level is associative, too.

Here is my code:

$dbstructure = array (      

    'documents' => array ( 
        'prettyname' => array ('en' => 'Documents', 'pl' => 'Dokumenty', 'de' => 'Dokumente'), 
        'columns' => array ('file', 'name', 'descr', 'tags' ),  
    ),

    'photos' => array ( 
        'prettyname' => array ('en' => 'Photos', 'pl' => 'Zdjęcia', 'de' => 'Fotos'), 
        'columns' => array ('name', 'file', 'descr', 'publish', 'tags', 'file_date' ),
    ),

    'users' => array ( 
        'prettyname' => array ('en' => 'Users', 'pl' => 'Użytkownicy', 'de' => 'Benutzer'), 
        'columns' => array ('name', 'password', 'email', 'role', 'status', 'lang' ),
    )
);

The array is part of a config file that describes a db structure, and I want to sort the first level by ...['prettyname'][$lang], $lang being either 'en', 'pl' or 'de'. In other words, users shall get the table names in the right alphabetical order in their language.

Brit gets this order: 'documents' - 'photos'- 'users'
Pole gets: 'documents' - 'users'- 'photos' (Dokumenty - Użytkownicy - Zdjęcia)
German gets: 'users' - 'documents'- 'photos' (Benutzer - Dokumente - Fotos)

Any help is greatly appreciated. Thanks!

Jan Mirus
  • 263
  • 2
  • 9

1 Answers1

1

uasort can still get done what you want assuming you have a PHP version that supports "use" for including additional values into the scope of anonymous functions (PHP 5.3 and up).

<?php

$dbstructure = array (

    'documents' => array (
        'prettyname' => array ('en' => 'Documents', 'pl' => 'Dokumenty', 'de' => 'Dokumente'),
        'columns' => array ('file', 'name', 'descr', 'tags' ),
    ),

    'photos' => array (
        'prettyname' => array ('en' => 'Photos', 'pl' => 'Zdjęcia', 'de' => 'Fotos'),
        'columns' => array ('name', 'file', 'descr', 'publish', 'tags', 'file_date' ),
    ),

    'users' => array (
        'prettyname' => array ('en' => 'Users', 'pl' => 'Użytkownicy', 'de' => 'Benutzer'),
        'columns' => array ('name', 'password', 'email', 'role', 'status', 'lang' ),
    )
);


function sortDbStructureByLocale($dbStructure, $locale) {
    // here we're passing a custom function to uasort and including locale in it's scope
    // with "use" as per https://stackoverflow.com/a/22610655/2149955
    uasort($dbStructure, function($a, $b) use ($locale) {
        // if both prettynames are defined for this locale, sort based on them
        if(isset($a['prettyname'][$locale]) && isset($b['prettyname'][$locale])) {
            return strcmp($a['prettyname'][$locale], $b['prettyname'][$locale]);
        }
        // sort mising names earlier
        if(!isset($a['prettyname'][$locale])) {
            return -1;
        }
        if(!isset($b['prettyname'][$locale])) {
            return 1;
        }
        return 0;
    });
    return $dbStructure;
}

echo "unsorted: " . json_encode($dbstructure) . "\n\n";

echo "English sorting: " . json_encode(sortDbStructureByLocale($dbstructure, 'en')) . "\n\n";
echo "Polish sorting: " . json_encode(sortDbStructureByLocale($dbstructure, 'pl')) . "\n\n";
echo "German sorting: " . json_encode(sortDbStructureByLocale($dbstructure, 'de')) . "\n\n";
Patrick Fay
  • 552
  • 3
  • 15
  • Thanks @Patrick for the super quick reply and sorry for my late one. Your example works, however when I try it with other data for `$dbstructure`, it gets the order wrong and I can't figure out why :(. Thought maybe special chars are the problem, but they are not. – Jan Mirus Aug 07 '19 at 11:39
  • E.g. these 3 db tables: `$dbstructure = array ( 'components' => array( 'name' => array ('en' => 'Components', 'pl' => 'Składniki', 'de' => 'Komponenten'), ), 'locations' => array ( 'prettyname' => array ('en' => 'Locations', 'pl' => 'Siedziby', 'de' => 'Standorte'), ), 'parts' => array ( 'prettyname' => array ('en' => 'Parts', 'pl' => 'Części', 'de' => 'Teile'), ) );` the Polish sorting is Składniki > Części > Siedziby – Jan Mirus Aug 07 '19 at 11:53
  • 1
    In your second example "prettyname" is instead called "name" specifically for the "components". Since "prettyname" is missing, that is sorted first. Presumably the structure should be changed such that it is has "prettyname" or the sorting function should use "name" as a backup if "prettyname" is missing. If you change it to "prettyname" it returns the expected sorting. – Patrick Fay Aug 12 '19 at 06:17
  • 1
    You made my day!!! Stupid mistake [rollingeyes] thank you thank you!! Works like a charm now. – Jan Mirus Aug 13 '19 at 08:35