Recursive function for tree menu array

286 views Asked by At

please I have function for 2 level menu... but I dont know how use it for 3 level. Can you help me please ? Example array

  [/c300112000-zvire] => Array
    (
        [/c300112001-pes] => Array
            (
                [0] => /c300112005-antiparazitni-pripravky
                [1] => /c300112002-granulovana-krmiva
                [2] => /c300112009-hracky-misky-a-ostatni
                [3] => /c300112003-konzervy-a-kapsicky
                [4] => /c300112004-pamlsky-a-doplnky-stravy
                [5] => /c300112008-psi-hygiena-a-zdravi
            )

        [/c300112010-kocka] => Array
            (
                [0] => /c300112015-antiparazitni-pripravky
                [1] => /c300112011-granulovana-krmiva
                [2] => /c300112017-hracky-a-misky
                [3] => /c300112016-kocici-hygiena-a-zdravi
                [4] => /c300112012-konzervy-a-kapsicky
                [5] => /c300112013-pamlsky-a-doplnky-stravy
                [6] => /c300112014-podestylky
            )

        [/c300112018-mala-zvirata] => Array
            (
                [0] => /c300112019-krmiva
                [1] => /c300112020-steliva
            )

        [/c300112021-ptactvo] => Array
            (
                [0] => /c300112022-krmiva
                [1] => /c300112023-steliva
            )

        [/c300112024-akvaristika-a-teraristika] => Array
            (
                [0] => /c300112025-krmiva
            )

    )

And my function working only 2 level not 3

  public function saveCategoryTree($categoryTree, Eshop $eshop)
{

    $em = $this->getEntityManager();


    for ($i = 0; $i < sizeof($categoryTree); $i++) {
        $categoryParent = new Category();
        $parent = array_keys($categoryTree)[$i];
        $parentName = explode("/", $parent);
        $parentName = end($parentName);
        $categoryParent->setCreatedAt(new \DateTime());
        $categoryParent->setLastCheckAt(new \DateTime());
        $categoryParent->setLastHttpStatusCode(\Symfony\Component\HttpFoundation\Response::HTTP_OK);
        $categoryParent->setActive(true);
        $categoryParent->setLeaf(false);
        $categoryParent->setEshop($eshop);
        $categoryParent->setName($parentName);
        $categoryParent->setLink($parent);
        $em->persist($categoryParent);
        $em->flush();


        foreach ($categoryTree[array_keys($categoryTree)[$i]] as $childItem) {
            if (is_array($childItem)) {
             echo "Is array ! Recursive call";
            } else {
                $child = new Category();
                $child->setParentCategory($categoryParent);
                $child->setCreatedAt(new \DateTime());
                $child->setLastCheckAt(new \DateTime());
                $child->setLastHttpStatusCode(\Symfony\Component\HttpFoundation\Response::HTTP_OK);
                $child->setActive(true);
                $child->setLeaf(true);
                $child->setEshop($eshop);
                $child->setName($childItem);
                $child->setLink($childItem);
                $em->persist($child);
                $em->flush();
            }

        }

    }
    exit;
}

Thanks for any help. Sorry for my english.

1

There are 1 answers

3
Fyntasia On

Move your child iteration logic to a new function and call it recursively;

This way it will work for 2, 3, 4, ... layers of tree functionality.

Edit: In my haste, I've built this code in PHP 7. Be aware this won't work on PHP < 7. Feel free to remove the type hints and return type declarations.

I'd try something along these lines:

    /**
     * @var EntityManager $_em
     */
    private $_em;
    /**
     * @var Eshop $_eshop
     */
    private $_eshop;

    /**
     * @param array $categoryTree
     * @param Eshop $eshop
     */
    public function saveCategoryTree(array $categoryTree, Eshop $eshop)
    {
        $this->_em    = $this->getEntityManager();
        $this->_eshop = $eshop;
        foreach ($categoryTree as $categoryKey => $categoryChildren)
        {
            if (is_array($categoryChildren))
            {
                $parentCategory = $this->_processCategory($categoryKey, $categoryChildren);
                $this->_processRecursiveChildren($parentCategory, $categoryChildren);
            } else
            {
                $this->_processCategory($categoryKey);
            }
        }
        exit;
    }

    /**
     * @param string        $categoryKey
     * @param Category|null $parentCategory
     *
     * @return Category
     */
    private function _processCategory(string $categoryKey, Category $parentCategory=null): Category
    {
        $category   = new Category();
        $parentName = explode("/", $categoryKey);
        $parentName = end($parentName);
        if ($parentCategory !== null)
        {
            $category->setParentCategory($parentCategory);
        }
        $category
            ->setCreatedAt(new \DateTime())
            ->setLastCheckAt(new \DateTime())
            ->setLastHttpStatusCode(\Symfony\Component\HttpFoundation\Response::HTTP_OK)
            ->setActive(true)
            ->setLeaf(false)
            ->setEshop($this->_eshop)
            ->setName($parentName)
            ->setLink($categoryKey)
        ;
        $this->_em->persist($category);
        $this->_em->flush();

        return $category;
    }

    /**
     * @param Category $parentCategory
     * @param array    $children
     */
    private function _processRecursiveChildren(Category $parentCategory, array $children)
    {
        foreach ($children as $childKey => $childItems)
        {
            if (is_array($childItems))
            {
                $nextParentCategory = $this->_processCategory($childKey, $parentCategory);
                $this->_processRecursiveChildren($nextParentCategory, $childItems);
            } else
            {
                $this->_processCategory($childItems, $parentCategory);
            }
        }
    }