构建类别树 Symfony3

Build category tree Symfony3

我正在尝试在 Symfony3 中构建类别树。

我有以下内容:

类别实体:

<?php    
namespace AppBundle\Entity;


use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity(repositoryClass="AppBundle\Repository\CategoryRepository")
 * @ORM\Table(name="category")
 */
class Category
{
    /**
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     * @ORM\Column(type="integer")
     *
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="children")
     * @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
     */
    private $id;
    /**
     * @ORM\Column(type="string")
     */
    private $name;
    /**
     * @ORM\Column(type="string", unique=true)
     */
    private $slug;
    /**
     * One Category has Many Categories.
     * @ORM\OneToMany(targetEntity="AppBundle\Entity\Category", mappedBy="parent")
     */
    private $children;
    /**
     * Many Categories have One Category.
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Category", inversedBy="children")
     */
    private $parent;
    /**
     * @ORM\Column(type="string")
     */
    private $pageTitle;
    /**
     * @ORM\Column(type="text")
     */
    private $description;
    /**
     * @ORM\ManyToOne(targetEntity="AppBundle\Entity\User")
     * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
     */
    private $created_by;

    /**
     * @return mixed
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * @return mixed
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * @param mixed $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * @return mixed
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * @param mixed $slug
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;
    }

    /**
     * @return mixed
     */
    public function getParent()
    {
        return $this->parent;
    }

    /**
     * @param mixed $parent
     */
    public function setParent($parent)
    {
        $this->parent = $parent;
    }

    /**
     * @return mixed
     */
    public function getPageTitle()
    {
        return $this->pageTitle;
    }

    /**
     * @param mixed $pageTitle
     */
    public function setPageTitle($pageTitle)
    {
        $this->pageTitle = $pageTitle;
    }

    /**
     * @return mixed
     */
    public function getDescription()
    {
        return $this->description;
    }

    /**
     * @param mixed $description
     */
    public function setDescription($description)
    {
        $this->description = $description;
    }

    /**
     * @return mixed
     */
    public function getChildren()
    {
        return $this->children;
    }

    /**
     * @param mixed $children
     */
    public function setChildren($children)
    {
        $this->children = $children;
    }

    /**
     * @return mixed
     */
    public function getCreatedBy()
    {
        return $this->created_by;
    }

    /**
     * @param mixed $created_by
     */
    public function setCreatedBy($created_by)
    {
        $this->created_by = $created_by;
    }

    public function __toString()
    {
        return (string) $this->getName();
    }
}

类别存储库:

<?php    
namespace AppBundle\Repository;


use Doctrine\ORM\EntityRepository;

class CategoryRepository extends EntityRepository
{
    public function findAllParentCategories()
    {
        return $this->createQueryBuilder('category')
            ->where('category.parent IS NULL')
            ->getQuery()
            ->execute();
    }
}

构建树的代码:

/**
 * @Route("/category")
 */
public function createCategoryMenu()
{
    $categoryRepository = $this->getDoctrine()->getRepository('AppBundle:Category');
    $categories = $categoryRepository->findAllParentCategories();

    $test = $this->generateCategoryMenu($categories, '');
    echo $test;
    exit;
}

protected function generateCategoryMenu($categories, $tree) {
    $tree .= "<ul>";
    foreach($categories as $category) {
        $tree .= "<li>" . $category->getName();
        if($category->getChildren() != null) {
            $tree .= $this->generateCategoryMenu($category->getChildren(), $tree);
        }
        $tree .= "</li>";
    }
    $tree .= "</ul>";

    return $tree;
}

在我看来,这应该可行,但我不明白为什么它不起作用。我得到以下结果:

<ul><li>Hiking<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul></ul></li></ul></li></ul></li><li>Survival<ul><li>Hiking<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul></ul></li></ul></li></ul></li><li>Survival<ul><li>Axes<ul><li>Hiking<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul><li>Hiking<ul><li>Backpacks<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul></ul></li></ul></li></ul></li><li>Survival<ul><li>Axes<ul></ul></li></ul></li></ul>

我期待以下结果:

<ul><li>Hiking<ul><li>Backpacks<ul></ul></li><li>Shoes<ul><li>Men<ul></ul></li></ul></li></ul></li><li>Survival<ul><li>Axes<ul></ul></li></ul></li></ul>

如您所见,我想要的 <ul> 是较大的 <ul> 的末尾。为什么要渲染所有这些重复的 <li>-tags?

问题(和解决方案)很简单。在递归调用中,您传入已经部分构建的树:

$tree .= $this->generateCategoryMenu($category->getChildren(), $tree);
// ^--------------------------------------------------------------^

然后连接结果到调用函数中的树。此时有效地复制了整棵树。

解决方案:简单地不要传递树。这使得 传入 树也变得不必要了。例如:

protected function generateCategoryMenu($categories) {
    $tree = "<ul>"; // initialize fresh
    foreach($categories as $category) {
        $tree .= "<li>" . $category->getName();
        if($category->getChildren() != null) {
            // just add the result
            $tree .= $this->generateCategoryMenu($category->getChildren());
        }
        $tree .= "</li>";
    }
    $tree .= "</ul>";

    return $tree;
}