roshkattu
roshkattu

Reputation: 251

Iterate through folder array ( file system like ) and return HTML nested list

I am having the following array

Array
(
    [0] => Homework2 (1).java
    [test2] => Array
    (
    )
    [1] => space-art-hd-473771.jpg
    [2] => Homework2.java
    [3] => factura_oct_2013.pdf
    [test] => Array
    (
        [0] => Homework2 (1).java
        [1] => space-art-hd-473771.jpg
        [2] => Homework2.java
    )
    [test3] => Array
    (
        [0] => Homework2 (1).java
        [testintest] => Array
        (
            [0] => Homework2 (1).java
            [1] => space-art-hd-473771.jpg
            [2] => Homework2.java
        )
        [1] => space-art-hd-473771.jpg
        [2] => Homework2.java
    )
)

and I am trying to display an HTML nested list. So each child of the array should be a new UL in the parent UL. I have tried to get this recursive but I only managed to get a lot of values that I already have.

function map2ul($file_map,$html="") {
    var_dump($file_map);
    print "<br>";
    if ($html == "") $html = '<ul>';
    else $html .= '<ul>';
    foreach ($file_map as $df) :
        if (is_array($df)) :
            $html .= $this->map2ul($df,$html);
        else :
            $html .= '<li>';
            $html .= $df;
            $html .= '</li>';
        endif;
    endforeach;
    $html .= '</ul>';
    return $html;
}

This is what I have tried but it seems that the foreach statement is recurred more times than it's needed.

Can someone please point me the error so I can understand better how to recurse this?

Upvotes: 0

Views: 304

Answers (2)

TazGPL
TazGPL

Reputation: 3748

The error is in this lines:

if ($html == "") $html = '<ul>';
else $html .= '<ul>';

When you try to call this function recursively, the non-empty $html is passed recursively causing the interior loop to glue sub-folder contents. @AgreeOrNot has already pointed one solution. The other is not to pass $html to the recursively called function:

$html .= $this->map2ul($df);

But I think that your approach introduces some unnecessary logic and processing.

By analyzing the array we can draw one important conclusion: if the array value is an array, the corresponding key is folder name. In other case the value is file name:

function map2ul($file_map) {
    $html = '<ul>';
    foreach ($file_map as $file_id_or_folder_name => $file_name_or_folder_content) {
        // if the element is a file
        if ( ! is_array($file_name_or_folder_content)) {
            $html .= '<li>' . $file_name_or_folder_content . '</li>';
        } else { // if the element is a folder
            $html .= '<li>/ ' . $file_id_or_folder_name . '</li>';
        }
    }
    $html .= '</ul>';
    return $html;
}

Now it's enough to inject sub-folders contents where it's necessary, i.e. for folders:

function map2ul($file_map) {
    $html = '<ul>';
    foreach ($file_map as $file_id_or_folder_name => $file_name_or_folder_content) {
        // if the element is a file
        if ( ! is_array($file_name_or_folder_content)) {
            $html .= '<li>' . $file_name_or_folder_content . '</li>';
        } else { // if the element is a folder
            $html .= '<li>/ ' . $file_id_or_folder_name . '</li>';
            // injecting sub-folder's contents
            $html .= map2ul($file_name_or_folder_content);
        }
    }
    $html .= '</ul>';
    return $html;
}

Edit

if I want for this piece of code $html .= '<li>' . $file_name_or_folder_content . '</li>'; to append the data-filepath attribute, which will be the parent_folder/file_name path, what do I need to do?

You have to pass the full path to the function. And the full path needs to be constructed at the function call:

function map2ul($file_map, $path = '') {
    $path = $path . '/';
    $html = '<ul>';
    foreach ($file_map as $file_id_or_folder_name => $file_name_or_folder_content) {
        // if the element is a file
        if ( ! is_array($file_name_or_folder_content)) {
            $html .= '<li data-filepath="' . $path . $file_name_or_folder_content . '">' . $file_name_or_folder_content . '</li>';
        } else { // if the element is a folder
            $html .= '<li>/ ' . $file_id_or_folder_name . '</li>';
            $html .= map2ul($file_name_or_folder_content, $path . $file_id_or_folder_name);
        }
    }
    $html .= '</ul>';
    return $html;
}

Try without second parameter, e.g map2ul($file_map) and with second parameter, e.g map2ul($file_map, 'c:/my_files').

Upvotes: 2

Inglis Baderson
Inglis Baderson

Reputation: 799

$html .= $this->map2ul($df,$html);

It shouldn't be a concatenation, because the recursive call is based on the parameter $html - that is, the concatenation is already done in the recursive call. Change it to:

$html = $this->map2ul($df,$html);

Upvotes: 2

Related Questions