Search code examples
phpnestedoptgroup

PHP : Get Select with NESTED Optgroup and options dynamically by Strings


Starting from array of string like :

"mobili;tavolini_lato_divano",
"mobili;tavoli_da_pranzo",
"illuminazione;plafoniere",
"illuminazione;lampade_decorative",
"sculture;sculture_in_resina",
"sculture;sculture_in_resina;serie_limitata_tatoo",
"sculture;sculture_in_resina;sculture_resina_grandi",

Need to create a select that have nested optgroup and option , based on split by " ; " ,where if 2 elements , first ( parent ) become optgroup and second ( son ) an option.

If 3 elements ( with same 1st element ) , 2nd element will become an optiongroup (inside first optgroup - Nested - ) with inside an option ( 3d element ).

And so on if 4 elements, and more elements.

Actually I made this example but this work only if there are 2 count.

Full example with input and output in :

https://wtools.io/php-sandbox/b63q

Select Execute and HTML as output to see result.
Thanks


Solution

  • First create an ordered (and nested) array of your element array (line 76-89 in my code), and then you must use the recursive function (line 91-104 in my code) to create a string of options and optgroup.

    Finally, print the output of the recursive function (line 107 in my code).

    <?php
    
    /*
    Row 1 : mobiletti_puzzle_3d;mobili
    Output : "optgroup" -> mobiletti_puzzle_3d
                "option" -> mobili
    
    Row 2 : sculture;sculture_in_resina
    Output : "optgroup" -> sculture
                "option" -> sculture_in_resina
    
    Row 3 : sculture;sculture_in_resina;sculture_resina_grandi
    Output : "optgroup" -> sculture
                "optgroup" -> sculture_in_resina
                    "option" -> sculture_resina_grandi
    
    If they have the same parent must be added as Option of Row 2 
    
    Row 4 : sculture;sculture_in_metallo
    Output : "optgroup" -> sculture
                "option" -> sculture_in_metallo
    
    
    Final Output ALL EXAMPLE :
    "optgroup" -> mobiletti_puzzle_3d
        "option" -> mobili
    "optgroup" -> sculture
        "option" -> sculture_in_resina
        "option" -> sculture_in_metallo
        "optgroup" -> sculture_in_resina
            "option" -> sculture_resina_grandi
    
    Split by " ; " the count-1 , always will be an optgroup and this will generate a Nested Optgroup 
    
    */
    $Categories = [
        "mobiletti_puzzle_3d;mobili",
        "mobili;sedie_da_pranzo",
        "mobili;sgabelli",
        "mobili;tavolini_da_salotto",
        "mobili;tavolini_lato_divano",
        "mobili;tavoli_da_pranzo",
        "sculture;sculture_decorate_in_vetro",
        "sculture;sculture_in_bronzo",
        "sculture;sculture_in_metallo",
        "sculture;sculture_in_resina;sculture_resina_grandi",
        "sculture;sculture_in_resina;sculture_resina_medie",
        "sculture;sculture_in_resina;sculture_resina_piccole",
        "sculture;sculture_in_resina;serie_limitata_tatoo",
        "illuminazione;plafoniere",
        "illuminazione;lampade_decorative",
        "illuminazione;lampade_da_terra",
        "illuminazione;lampade_da_tavolo",
        "illuminazione;lampade_da_comodino",
        "illuminazione;lampadari",
        "divani_e_poltrone;mobili",
        "decorazione_murale;stampe_su_telaio_estetico",
        "decorazione_murale;specchi_design_moderno",
        "decorazione_murale;quadri_scultura_in_metallo",
        "decorazione_murale;puzzle_3d_in_legno",
        "decorazione_murale;orologi_parete",
        "decorazione_murale;dipinti_su_telaio_estetico",
        "decorazione_murale;dipinti_su_plexiglas",
        "consolle;mobili",
        "colonne;mobili",
        "collage_3d;decorazione_murale",
        "appliques;illuminazione",
        "altri_oggetti;vasi",
        "altri_oggetti;posacenere",
        "altri_oggetti;portagioie",
        "altri_oggetti;portacandele",
        "altri_oggetti;oggetti_decorativi",
        "altri_oggetti;centrotavola"
    ];
    
    $select = [];
    foreach ($Categories as $row) {
        $pointer = &$select;
        $row = explode(';', $row);
        $ogCount = count($row) - 1;
        for ($i = 0; $i < $ogCount; $i++) {
            $row[$i] = $row[$i];
            if (empty($pointer[$row[$i]]))
                $pointer[$row[$i]] = [];
            $pointer = &$pointer[$row[$i]];
            if (($i + 1) >= $ogCount)
                $pointer[] = $row[$i + 1];
        }
    }
    
    function recursiveSelect($_options, $_space = '')
    {
        if (!is_array($_options))
            return  '<option value="' . $_options . '">' . $_options . '</option>' . "\n";
        else {
            $tmp = '';
            foreach ($_options as $key => $option)
                if (!is_array($option)) {
                    $tmp .= recursiveSelect($option);
                } else
                    $tmp .= '<optgroup label="' . $_space . $key . '">' . recursiveSelect($option, $_space . str_repeat('&nbsp;', 4)) . '</optgroup>' . "\n";
            return $tmp;
        }
    }
    ?>
    <select>
        <?php echo (recursiveSelect($select)); ?>
    </select>
    

    This code can handle all depths of nested elements in your array.

    To better display the select optgroups, I added the space ($_space) parameter to the recursive function (with 4 spaces in line 101).