0

I want to create this question with the intention that we can collect in one place, one or several examples of an infinite array tree, and generate a nested structure of HTML <ul> <li>, with examples of codes using good practices for junior programmers, who want to learn to work with this type of arrays.

Scope:

  • Sort the arrangement and generate the HTML with different types of examples
  • Use different examples of codes with the same result, to understand the work with this type of arrangements, which can become very complex.

I have prepared for this example a multi-level arrangement:

The code that orders this arrangement I have obtained from this answer: php array tree sorting

A simple view is a code that is not so easy to digest, I would like more experienced programmers to give us more examples of code to obtain the same result, with different practices and examples.

$data = array(
    array("id"=> 1,  "parent_id" => "", "name"=> "Home" ),
    array("id"=> 2,  "parent_id" => "", "name"=> "News"),
    array("id"=> 3,  "parent_id" => 2, "name"=> "World"),
    array("id"=> 4,  "parent_id" => 2, "name"=> "Internationals"),
    array("id"=> 5,  "parent_id" => 4, "name"=> "America"),
    array("id"=> 6,  "parent_id" => 5, "name"=> "United Stated"),
    array("id"=> 7,  "parent_id" => 6, "name"=> "Florida"),
    array("id"=> 8,  "parent_id" => 7, "name"=> "Miami"),
    array("id"=> 9,  "parent_id" => "", "name"=> "Sports"),
    array("id"=> 10,  "parent_id" => "", "name"=> "Global")
);

$sort = array();
$all = array();
$dangling = array();

// Initialize arrays
foreach ($data as $value) {
    $value['children'] = array();
    $id = $value['id'];

    // If this is a top-level node, add it to the sort immediately
    if ($value['parent_id'] == '') {
        $all[$id] = $value;
        $sort[] =& $all[$id];

    // If this isn't a top-level node, we have to process it later
    } else {
        $dangling[$id] = $value; 
    }
}

// Process all 'dangling' nodes
while (count($dangling) > 0) {
    foreach($dangling as $value) {
        $id = $value['id'];
        $pid = $value['parent_id'];

        // If the parent has already been added to the sort, it's
        // safe to add this node too
        if (isset($all[$pid])) {
            $all[$id] = $value;
            $all[$pid]['children'][] =& $all[$id]; 
            unset($dangling[$value['id']]);
        }
    }
}

echo "<pre>"; print_r($sort);

This would be the result of the array ordered:

Array
(
    [0] => Array
        (
            [id] => 1
            [parent_id] => 
            [name] => Home
            [children] => Array
                (
                )

        )

    [1] => Array
        (
            [id] => 2
            [parent_id] => 
            [name] => News
            [children] => Array
                (
                    [0] => Array
                        (
                            [id] => 3
                            [parent_id] => 2
                            [name] => World
                            [children] => Array
                                (
                                )

                        )

                    [1] => Array
                        (
                            [id] => 4
                            [parent_id] => 2
                            [name] => Internationals
                            [children] => Array
                                (
                                    [0] => Array
                                        (
                                            [id] => 5
                                            [parent_id] => 4
                                            [name] => America
                                            [children] => Array
                                                (
                                                    [0] => Array
                                                        (
                                                            [id] => 6
                                                            [parent_id] => 5
                                                            [name] => United Stated
                                                            [children] => Array
                                                                (
                                                                    [0] => Array
                                                                        (
                                                                            [id] => 7
                                                                            [parent_id] => 6
                                                                            [name] => Florida
                                                                            [children] => Array
                                                                                (
                                                                                    [0] => Array
                                                                                        (
                                                                                            [id] => 8
                                                                                            [parent_id] => 7
                                                                                            [name] => Miami
                                                                                            [children] => Array
                                                                                                (
                                                                                                )

                                                                                        )

                                                                                )

                                                                        )

                                                                )

                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

    [2] => Array
        (
            [id] => 9
            [parent_id] => 
            [name] => Sports
            [children] => Array
                (
                )

        )

    [3] => Array
        (
            [id] => 10
            [parent_id] => 
            [name] => Global
            [children] => Array
                (
                )

        )

)

I want to generate from this array an HTML structure like the following one, using good practices and with different examples.

<ul>
    <li><a href="#">Home</a></li>
    <li><a href="#">News</a>
        <ul>
            <li><a href="#">World</a></li>
            <li><a href="#">Internationals</a>
                <ul>
                    <li><a href="#">America</a>
                        <ul>
                            <li><a href="#">United Stated</a>
                                <ul>
                                    <li><a href="#">Florida</a>
                                        <ul>
                                            <li><a href="#">Miami</a></li>
                                        </ul>
                                    </li>
                                </ul>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
        </ul>
    </li>
    <li><a href="#">Sports</a></li>
    <li><a href="#">Global</a></li>
</ul>
0

1 Answer 1

1

If anyone could tell what is the good practice for this is, there wouldn't be a need to write this in different ways. :)

Written naively this would be a recursion function with linearly increasing indent level:

function getListHtml( $input, $indentLevel = 0 ) {

    if ( empty( $input ) ) {
        return '';
    }

    $output = '';
    $indent = str_repeat( "\t", $indentLevel * 2 );

    $output .= $indent . "<ul>\n";

    foreach ( $input as $item ) {
        $name   = htmlspecialchars( $item['name'] );
        $output .= $indent . "\t<li><a href='#'>{$name}</a>";

        $children = getListHtml( $item['children'], $indentLevel + 1 );
        $output   .= $children ? "\n{$children}{$indent}\t" : '';

        $output .= "</li>\n";
    }

    $output .= $indent . "</ul>\n";

    return $output;
}

$result = getListHtml( $sort );

Good practice in more specific cases would likely follow templating needs of the project more than particulars of PHP code.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you very much @Rarst, it works perfect, with good practices, I mean this can be done in many ways, using different types of logic, and what I wanted was that, to have one more way of giving the same result, with different Logics or codes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.