Asked  8 Months ago    Answers:  5   Viewed   54 times

I have an array with the following keys

id   
parent_id
name

A sample array:

array(7) {
  [0]=>
  array(3) {
    ["id"]=>
    string(1) "4"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 4"
  }
  [1]=>
  array(3) {
    ["id"]=>
    string(1) "5"
    ["parent_id"]=>
    string(1) "1"
    ["name"]=>
    string(19) "Second Level Page 1"
  }
  [2]=>
  array(3) {
    ["id"]=>
    string(1) "6"
    ["parent_id"]=>
    string(1) "2"
    ["name"]=>
    string(19) "Second Level Page 2"
  }
  [3]=>
  array(3) {
    ["id"]=>
    string(1) "7"
    ["parent_id"]=>
    string(1) "5"
    ["name"]=>
    string(18) "Third Level Page 1"
  }
  [4]=>
  array(3) {
    ["id"]=>
    string(1) "3"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 3"
  }
  [5]=>
  array(3) {
    ["id"]=>
    string(1) "2"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 2"
  }
  [6]=>
  array(3) {
    ["id"]=>
    string(1) "1"
    ["parent_id"]=>
    string(1) "0"
    ["name"]=>
    string(16) "Top Level Page 1"
  }
}

What I would like to do is display a hierarchy tree using this array, the code I have at the moment is producing:

Top Level Page 4
--Second Level Page 1
---Second Level Page 2
----Third Level Page 1
Top Level Page 3
Top Level Page 2
Top Level Page 1

Ideally I need to produce the below result but with unlimited levels:

Top Level Page 4
-Second Level Page 1
-Second Level Page 2
--Third Level Page 1
Top Level Page 3
Top Level Page 2
Top Level Page 1

The code I have so far is:

$level = 1;
        foreach ($data as $row) {
            if ($row['parent_id'] == 0) {
                echo $row['name'] . '<br/>';
            } else {
                $level++;
                foreach ($data as $m) {
                    if ($m['parent_id'] === $row['parent_id']) {
                        $c = 0;
                        $append = '';
                        while ($c < $level) {
                            $append.="-";
                            $c++;
                        }
                        echo $append . $row['name'] . '<br/>';
                    }
                }
            }
        }
    }

If anyone could give me some pointers on how to achieve this it would be much appreciated.

I found a solution here: Create nested list from PHP array for dropdown select field

 Answers

60

You should use recursion.

Here an exemple of code:

$datas = array(
    array('id' => 1, 'parent' => 0, 'name' => 'Page 1'),
    array('id' => 2, 'parent' => 1, 'name' => 'Page 1.1'),
    array('id' => 3, 'parent' => 2, 'name' => 'Page 1.1.1'),
    array('id' => 4, 'parent' => 3, 'name' => 'Page 1.1.1.1'),
    array('id' => 5, 'parent' => 3, 'name' => 'Page 1.1.1.2'),
    array('id' => 6, 'parent' => 1, 'name' => 'Page 1.2'),
    array('id' => 7, 'parent' => 6, 'name' => 'Page 1.2.1'),
    array('id' => 8, 'parent' => 0, 'name' => 'Page 2'),
    array('id' => 9, 'parent' => 0, 'name' => 'Page 3'),
    array('id' => 10, 'parent' => 9, 'name' => 'Page 3.1'),
    array('id' => 11, 'parent' => 9, 'name' => 'Page 3.2'),
    array('id' => 12, 'parent' => 11, 'name' => 'Page 3.2.1'),
    );

function generatePageTree($datas, $parent = 0, $depth=0){
    $ni=count($datas);
    if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion
    $tree = '<ul>';
    for($i=0; $i < $ni; $i++){
        if($datas[$i]['parent'] == $parent){
            $tree .= '<li>';
            $tree .= $datas[$i]['name'];
            $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1);
            $tree .= '</li>';
        }
    }
    $tree .= '</ul>';
    return $tree;
}

echo(generatePageTree($datas));

You can test it at: http://phpfiddle.org/main/code/1qy-5fj

Or if you want the exact format:

function generatePageTree($datas, $parent = 0, $depth = 0){
    $ni=count($datas);
    if($ni === 0 || $depth > 1000) return ''; // Make sure not to have an endless recursion
    $tree = '';
    for($i=0; $i < $ni; $i++){
        if($datas[$i]['parent'] == $parent){
            $tree .= str_repeat('-', $depth);
            $tree .= $datas[$i]['name'] . '<br/>';
            $tree .= generatePageTree($datas, $datas[$i]['id'], $depth+1);
        }
    }
    return $tree;
}

The test: http://phpfiddle.org/main/code/jw3-s1j

Wednesday, March 31, 2021
 
muncherelli
answered 8 Months ago
26

Here's a shorter recursive one:

function dir_tree($dir) {    
    $files = array_map('basename', glob("$dir/*"));
    foreach($files as $file) {
        if(is_dir("$dir/$file")) {
            $return[$file] = dir_tree("$dir/$file");
        } else {
            $return[] = $file;
        }
    }
    return $return;
}
Wednesday, March 31, 2021
 
phpmeh
answered 8 Months ago
39

When you set cell values individually, you have the option of setting the datatype explicitly, but when you use the fromArray() method, you don't have this option.

However, by default, PHP uses a default value binder to identify datatypes from the values passed, and set the cell datatype accordingly. This default behaviour is defined in a class /PHPExcel/Cell/DefaultValueBinder.php.

So you can create your own value binder, as described in the PHPExcel Documentation, that would set every value as a string datatype.

Something like:

class PHPExcel_Cell_MyColumnValueBinder extends PHPExcel_Cell_DefaultValueBinder implements PHPExcel_Cell_IValueBinder
{
    protected $stringColumns = [];

    public function __construct(array $stringColumnList = []) {
        // Accept a list of columns that will always be set as strings
        $this->stringColumns = $stringColumnList;
    }

    public function bindValue(PHPExcel_Cell $cell, $value = null)
    {
        // If the cell is one of our columns to set as a string...
        if (in_array($cell->getColumn(), $this->stringColumns)) {
            // ... then we cast it to a string and explicitly set it as a string
            $cell->setValueExplicit((string) $value, PHPExcel_Cell_DataType::TYPE_STRING);
            return true;
        }
        // Otherwise, use the default behaviour
        return parent::bindValue($cell, $value);
    }
}

// Instantiate our custom binder, with a list of columns, and tell PHPExcel to use it
PHPExcel_Cell::setValueBinder(new PHPExcel_Cell_MyColumnValueBinder(['A', 'B', 'C', 'E', 'F']));

$objPHPExcel = new PHPExcel();
$objPHPExcel->getActiveSheet()->fromArray($dataArray,null,"A2");
Friday, May 28, 2021
 
Wilk
answered 5 Months ago
31

Here is some code to handle what you had originally proposed as output.

/**
 * Give it and array, and an array of parents, it will decent into the
 * nested arrays and set the value.
 */
function set_nested_value(array &$arr, array $ancestors, $value) {
  $current = &$arr;
  foreach ($ancestors as $key) {

    // To handle the original input, if an item is not an array, 
    // replace it with an array with the value as the first item.
    if (!is_array($current)) {
      $current = array( $current);
    }

    if (!array_key_exists($key, $current)) {
      $current[$key] = array();
    }
    $current = &$current[$key];
  }

  $current = $value;
}


$education = array(
  'x[1]'     => 'Georgia Tech',
  'x[1][1]'  => 'Mechanical Engineering',
  'x[1][2]'  => 'Computer Science',
  'x[2]'     => 'Agnes Scott',
  'x[2][1]'  => 'Religious History',
  'x[2][2]'  => 'Women's Studies',
  'x[3]'     => 'Georgia State',
  'x[3][1]'  => 'Business Administration',
);

$neweducation = array();

foreach ($education as $path => $value) {
  $ancestors = explode('][', substr($path, 2, -1));
  set_nested_value($neweducation, $ancestors, $value);
}

Basically, split your array keys into a nice array of ancestor keys, then use a nice function to decent into the $neweducation array using those parents, and set the value.

If you want the output that you have updated your post to have, add this in the foreach loop after the line with 'explode'.

$ancestors[] = 0;
Saturday, May 29, 2021
 
Nate
answered 5 Months ago
13

There's a lot been written about PHPExcel and memory use, and I'm not going to repeat it all here.

Try reading some of the threads on the PHPExcel discussion board discussing the issue, such as this one; or previous answers here on SO such as this one or this one

Tuesday, July 6, 2021
 
Slinky
answered 4 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share