我花了一段时间浏览symfony2文档试图找到一种合适的方法来做我需要做的事情,也许我正在寻找错误的地方。
基本上,我有一个名为Album
的实体,它可以与许多Subalbums
相关联。当用户使用表单创建Album
实体时,我希望他们能够在线创建快速Subalbum
实体,稍后将保存这些实体。我还希望以自定义格式显示字段,因此我不想使用带有select
属性的multiple
标记,而是使用Twig手动渲染它(我没有有这个问题)。
Subalbum
上的关系定义如下:
/**
* @ORM\ManyToOne(targetEntity="Vhoto\AlbumBundle\Entity\Album")
* @ORM\JoinColumn(name="parent_id", referencedColumnName="id")
*/
protected $parent;
这是我到目前为止所尝试的......
在表单构建器中使用entity
类型字段,然后手动输出字段。我使用entity
字段时遇到的问题是,如果用户创建Subalbum
内联,symfony2在提交表单时不喜欢它,因为它没有ID。
使用隐藏字段类型并尝试在相同字段名称(album[subalbums][]
)下提交多个条目。当我提交表格
我想我必须在prePersist
实体中使用Album
方法来创建用户内联创建的任何Subalbum
个实体?
希望有一个更优雅的解决方案,我只是完全忽略了。
如果有什么不清楚,请告诉我。
答案 0 :(得分:3)
确实有更好的方法。
实体创建
创建两个Entity
POPO,并为子实体的其中一个字段分配many-to-one
关系(您已正确完成此操作)。您可能还想在父
one-to-many
关系
/**
* @var ArrayCollection
*
* @ORM\OneToMany(targetEntity="Child", mappedBy="parent", cascade={"persist", "remove" }, orphanRemoval=true)
*/
protected $children;
我不确定是否有必要,但您应该明确设置您的安装者中的关系以确保。例如,在您拥有的实体中:
public function addChild(ChildInterface $child)
{
if(!$this->hasChild($child))
{
$this->children->add($child);
$child->setParent($this);
}
}
Doctrine
可能不会使用这些方法绑定帖子数据,但是这样做可能会解决几个持续存在的问题。
表单类型创建
为两个实体创建表单类型
/**
* This would be the form type for your sub-albums.
*/
class ChildType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
//$builder->add(...);
//...
}
public function getDefaultOptions(array $options) {
return array(
'data_class' => 'Acme\Bundle\DemoBundle\Entity\Child'
);
}
public function getName()
{
return 'ChildType';
}
}
/**
* This would be the form type for your albums.
*/
class ParentType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
// This part here describes the relationship between the two
// form types.
$builder->add('children', 'collection', array(
'type' => new ChildType(),
'allow_add' => true,
'allow_delete' => true,
'prototype' => true
));
}
public function getName()
{
return 'ChildType';
}
}
使用选项allow_add
和allow_delete
,您已经有效地告诉Symfony,用户可以在集合中添加或删除实体。 prototype
选项可让您在页面上拥有所谓子表单的原型。
<强>控制器强>
你应该在这里加强这种关系以保证安全。我已将其隐藏在一个单独的实体管理器层中(我有更多复杂实体的单独管理器),但您也可以在控制器中执行此操作。
foreach($parent->getChildren() as $child)
{
if($child->getParent() === NULL)
{
$child->setParent($parent);
}
}
查看强>
准备表单的模板。应该通过在模板中的某个地方调用form_rest(form)
来呈现原型。如果没有,或者你想自定义原型,这里有一个如何做的样本。
<script id="ParentType_children_prototype" type="text/html">
<li class="custom_prototype_sample">
<div class="content grid_11 alpha">
{{ form_widget(form.children.get('prototype').field1) }}
{{ form_widget(form.children.get('prototype').field2) }}
{{ form_rest(form.children.get('prototype') ) }}
</div>
</li>
</script>
您必须使用JavaScript使表单动态化。如果您使用jQuery
,则可以通过调用$('ParentType_children_prototype').html()
来访问原型。在将新子项添加到父项时,使用正确的索引号替换原型中所有出现的$$name$$
非常重要。
我希望这会有所帮助。
编辑我刚注意到CollectionType
有一个article in the Symfony2 Form Type reference。它有一个关于如何为此实现前端的很好的替代方案。