构建类别树 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;
}
我正在尝试在 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;
}