Friday, 31 August 2018

Create a multidimensional array from four arrays based on the parent ID

From these four arrays:

$root = (FORD, FIAT, GM, KIA, FERRARI);
$parentIsFiat = (Panda, Punto, Tipo);
$parentIsPanda = (1, 13, 16, 20);
$parentIs13 = (Red, Blue, White);

How can I create a multidimensional array to give me this:
FORD
FIAT
--Panda
----1
----13
------Red
------Blue
------White
----16
----20
--Punto
--Tipo
GM
KIA
FERRARI

Background: The current menu on my site has every link on the site in the HTML. I want to only have the HTML for menu items that are actually visible. At the moment I get each item in the path (FIAT > Panda > 13) and it's siblings with code similar to this:
$categoryPath = \XLite\Core\Database::getRepo('\XLite\Model\Category')->getCategoryPath($this->getCategoryId());
foreach ($categoryPath as $category) {
    $currentCatID = $category->getID();
    $currentCatSiblings = $category->getSiblings(true);
    foreach ($currentCatSiblings as $sibling) {
        $menuItems[$currentCatID][] = $sibling->getName(); // the four arrays above
    }
}

Each of the arrays has the parent ID as the key so I can 'attach' it in the correct place but I don't know how to build the array from my four existing arrays.

You could introduce a temporary $parent variable that will reference the place in the tree where the siblings must be inserted, and move that $parent reference further down the tree for the next "generation" of siblings:
$tree = [];
$parent = &$tree; // Use `= &` to reference the same location
foreach ($categoryPath as $category) {
    $currentCatID = $category->getID();
    $currentCatSiblings = $category->getSiblings(true);
    foreach ($currentCatSiblings as $sibling) {
        $parent[] = [ "name" => $sibling->getName() ];
        if ($sibling->getID() === $currentCatID) $index = count($parent) - 1;
    }
    $parent[$index]["children"] = [];
    $parent = &$parent[$index]["children"]; // Use `= &` to reference the deeper location
}

At the end $tree will contain the nested array. It will have "children" keys to store the nested structure, like this:
[
  [ "name" => "Ford" ],
  [
    "name" => "Fiat",
    "children" => [
      [
        "name" => "Panda",
        "children" => [
          [ "name" => "1" ],
          [
            "name" => "13",
            "children" => [
              [ "name" => "Red" ],
              [
                "name" => "Blue",
                "children" => [],
              ],
              [ "name" => "White" ],
            ],
          ],
          [ "name" => "16" ],
          [ "name" => "20" ],
        ],
      ],
      [ "name" => "Punto" ],
      [ "name" => "Tipo"  ],
    ],
  ],
  [ "name" => "GM" ],
  [ "name" => "Kia" ],
  [ "name" => "Ferrari" ],
]

Or, if you prefer to have the names used as keys in an associative array, then:
$tree = [];
$parent = &$tree; // Use `= &` to reference the same location
foreach ($categoryPath as $category) {
    $currentCatID = $category->getID();
    $currentCatSiblings = $category->getSiblings(true);
    foreach ($currentCatSiblings as $sibling) {
        $parent[$sibling->getName()] = [];
    }
    $parent = &$parent[$category->getName()]; // Use `= &` to reference the deeper location
}

Result:
[
  "Ford" => [],
  "Fiat" => [
    "Panda" => [
      "1" => [],
      "13" => [
        "Red" => [],
        "Blue" => [],
        "White" => []
      ],
      "16" => [],
      "20" => []
    ],
    "Punto" => [],
    "Tipo" => []
  ],
  "GM" => [],
  "Kia" => [],
  "Ferrari" => []
]

0 comments:

Post a Comment