我有一个包含自引用映射的实体。
class Category
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=100)
*/
private $name;
/**
* @ORM\OneToMany(targetEntity="Category", mappedBy="parent")
*/
private $children;
/**
* @ORM\ManyToOne(targetEntity="Category", inversedBy="children")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
private $parent;
}
在我的CategoryType中,我有这个:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$plan = $this->plan;
$builder->add('name');
$builder->add('parent', 'entity', array(
'class' => 'xxxBundle:Category',
'property' => 'name',
'empty_value' => 'Choose a parent category',
'required' => false,
'query_builder' => function(EntityRepository $er) use ($plan) {
return $er->createQueryBuilder('u')
->where('u.plan = :plan')
->setParameter('plan', $plan)
->orderBy('u.id', 'ASC');
},
));
}
实际上,当我渲染表单字段Category时,这就像
我想知道它是否可能以及如何显示更像是一种简单的树形象:
问候。
答案 0 :(得分:1)
我从你和jperovic所写的内容中得出了一些看似正确的东西。您的Category
课程需要两个新属性:
$level
将包含其父母的ID,例如" idA-idB"等等。此属性将用于在查询数据库时对结果进行排序,以便您可以确定SubCatOf3不会出现在Cat3之前!$treeName
将包含jperovic已写入的内容,并将在表单中打印。我还使用了Doctrine Events [doc],因此当您更新/保留它们时,您不必担心这些属性的价值。
这是您全新的Category.php
文件:
/**
* @ORM\HasLifeCycleCallbacks()
*/
class Category
{
private $level;
private $treeName;
/**
* Renders something like : "---- Subcategory A"
* @ORM\PreUpdate()
* @ORM\PrePersist()
**/
public function updateTreeName()
{
$itemDepth = 0;
$parent = $this->parent;
while ($parent != null) {
$itemDepth++;
$parent = $parent->getParent();
}
$this->treeName = str_repeat('--', $itemDepth) . ' ' . $this->name
}
/** renders something like : "idParent-idChild1-idChild2"
* @ORM\PreUpdate()
* @ORM\PrePersist()
**/
public function updateLevelName()
{
$this->level = '';
$parent = $this->parent;
while ($parent != null) {
$parent = $parent->getParent();
$this->level .= '-' . $p->getId();
}
}
public function getTreeName()
{
return $this->treeName;
}
public function getLevel()
{
return $this->level;
}
// ...
}
然后,将 query_builder 放在CategoryRepository.php
中,如下所示:
namespace Foo\BarBundle\Entity;
use Doctrine\ORM\EntityRepository;
class CategoryRepository extends EntityRepository
{
public function getHierarchicalCategoryList($plan)
{
$qb = $this->createQueryBuilder('u')
->where('u.plan = :plan')
->setParameter('plan', $plan)
->orderBy('u.level', 'ASC');
$return $qb;
}
}
在您的CategoryType.php
:
public function buildForm(FormBuilderInterface $builder, array $options)
{
$plan = $this->plan;
$builder->add('name');
$builder->add('parent', 'entity', array(
'class' => 'xxxBundle:Category',
'property' => 'treeName',
'empty_value' => 'Choose a parent category',
'required' => false,
'query_builder' => function(EntityRepository $er) use ($plan) {
return $er->getHierarchicalCategoryList($plan)
},
));
}
注意:这是快速和肮脏的工作,因此您可能需要更正错别字,注释等。但是,您有这个想法!希望它有所帮助。
答案 1 :(得分:0)
这是一个非常长的镜头,但我认为它很容易实现。
在您指定query_builder
的{{1}}内。您需要将其更改为'property' => 'name'
。 Doctrine将尝试查找和调用属性的'treeName'
方法 - 所有打印逻辑都在其中:
getter
由于需要对class Category
{
....
Everything else
....
public function getTreeName(){
$itemDepth = 0;
$p = $this->parent;
while ( $p != null ){
$itemDepth++;
$p = $p->getParent();
}
return str_repeat('--', $itemDepth) . ' ' . $this->name
}
}
次的每个项目进行迭代,这可能会造成严重的性能损失。
为了清楚起见,depth
属性及其getter和setter将保持不变。