php - Symfony2 + Twig : Using an entity type field to store unsaved entities

标签 php symfony twig

我花了一段时间浏览 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;

这是我迄今为止尝试过的...

  1. 在表单构建器中使用entity类型字段,然后手动输出该字段。我使用 entity 字段时遇到的问题是,如果用户创建内联 Subalbum ,当我提交表单时 symfony2 不喜欢它,因为它没有 ID。

  2. 使用隐藏字段类型并尝试在同一字段名称 (album[subalbums][]) 下提交多个条目。当我提交表单时,Symfony2 也不喜欢这样

我想我的 Album 实体中必须有一个 prePersist 方法来创建用户拥有的任何 Subalbum 实体内联创建?

希望有一个更优雅的解决方案,但我完全忽略了。

如果有任何不清楚的地方,请告诉我。

最佳答案

确实有更好的方法。

实体创建

创建两个实体 POPO,并将多对一关系分配给子实体的其中一个字段(您已正确完成此操作)。您可能还想在父级中定义一对多关系

/**
 * @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 可能不会使用这些方法来绑定(bind)发布数据,但自己拥有这个方法可能会解决几个持续存在的问题。

表单类型创建

为两个实体创建表单类型

/**
 * 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_addallow_delete,您已经有效地告诉Symfony,用户可以从集合中添加或删除实体。 prototype 选项可让您在页面上拥有所谓的子表单的原型(prototype)。

Controller

为了安全起见,您也应该在此处强制执行该关系。我已将其隐藏在一个单独的实体管理层中(对于更复杂的实体,我有单独的管理器),但您当然也可以在 Controller 中执行此操作。

foreach($parent->getChildren() as $child)
{
    if($child->getParent() === NULL)
    {
        $child->setParent($parent);
    }
}

查看

准备表单模板。应通过在模板中的某处调用 form_rest(form) 来呈现原型(prototype)。如果没有或者您想自定义原型(prototype),请参阅以下示例,了解如何执行此操作。

<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()来访问原型(prototype)。在向父级添加新子级时,将原型(prototype)中出现的所有 $$name$$ 替换为正确的索引号非常重要。

我希望这会有所帮助。

编辑我刚刚注意到有一个 article in the Symfony2 Form Type reference关于CollectionType。关于如何为此实现前端,它有一个很好的替代方案。

关于php - Symfony2 + Twig : Using an entity type field to store unsaved entities,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8474041/

相关文章:

PHP __FILE__ 在从 OSX 主机挂载的 Linux VM 文件中返回反斜杠

php - 使html表单文本字段成为必填项

php - 最近安装了 XAMPP 并卡在 "Connection for controluser failed"

php - Doctrine QueryBuilder > 使用多对多关系

php - Symfony 事件订阅者对调度没有反应

url - Symfony2 Twig url() https

php - PHP之后要学什么? Scala 还是 Clojure?

twig - twig 文件中的增量值

php - 将 Twig 与 react.js 集成

symfony - 如何在 Symfony2 的 Twig 中使用没有域的多个翻译文件?