我花了一段时间查看symfony2文档,试图找到一种合适的方法来做我需要做的事情,也许我在错误的地方寻找。
基本上,我有一个名为Album
的实体,它可以与许多Subalbums
相关联。当用户使用表单创建Album
实体时,我希望他们能够在线快速创建Subalbum
实体,稍后将保存这些实体。我还想以自定义格式显示字段,所以我不想使用带有multiple
属性的select
标记,而是在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][]
)下提交多个条目。当我提交表单 时,Symfony2也不喜欢这个
我想我将不得不有一个prePersist
方法在我的Album
实体创建任何Subalbum
实体,用户已经创建内联?
希望有一个更优雅的解决方案,我只是完全忽略了。
确实有更好的方法。
实体创建
创建两个Entity
popo并将many-to-one
关系分配给子实体的一个字段(您已经正确地完成了此操作)。您可能还想在父
one-to-many
关系。/**
* @var ArrayCollection
*
* @ORM'OneToMany(targetEntity="Child", mappedBy="parent", cascade={"persist", "remove" }, orphanRemoval=true)
*/
protected $children;
我不确定是否有必要,但你应该在你的setter中显式地设置关系,以确保。例如在您的所属实体中:
public function addChild(ChildInterface $child)
{
if(!$this->hasChild($child))
{
$this->children->add($child);
$child->setParent($this);
}
}
Doctrine
可能不会使用这些方法来绑定post数据,但是为自己使用这些方法可能会解决几个持续存在的问题。
表单类型创建
为两个实体创建一个表单类型
/**
* 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);
}
}
<<p> 视图/strong> 准备表单模板。原型应该通过在模板中的某处调用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$$
是很重要的。
我希望这对你有帮助。
EDIT我刚刚注意到Symfony2表单类型参考中有一篇关于CollectionType
的文章。对于如何实现前端,它有一个很好的替代方案。