使用CollectionType在表单提交后立即打印新持久的实体ID

时间:2016-06-14 00:23:02

标签: doctrine-orm symfony-forms symfony

简短地说

在提交新项目时,Symfony会处理POST数据,但新持久化的项目没有在相应的隐藏字段值属性中填充其ID,而是缺少value属性。

手术:

我已实施了一些添加/修改/删除功能,让用户使用CollectionType管理“城市”实体池。
添加新城市时:

  • 我确保每个现有条目都有一个隐藏字段,其中包含实体的id(pk),以及可编辑的常规属性,以便正确更新现有实例
  • 在表单提交时,数据可用[确定]
  • 持续循环并跟随刷新成功更新数据库[确定]
  • 使用新添加的城市再次呈现表单

除了事实上任何新提交的城市的隐藏字段缺少“值”属性之外,所有工作都有效。 enter image description here

我读过像 在刷新后立即访问对象getter返回相应的最新属性。新插入的记录ID将填充...

所以我希望Doctrine在刷新时更新新的持久化城市对象,但看起来没有任何事情发生。 表单似乎没有意识到新的插入。这是因为在处理请求后Forms数据不可变吗? 注意:至少,在重新加载页面时(在没有发布数据两次的情况下到达相同的URL),隐藏字段最终会使其属性值打印出相应的实体ID。

有人可以帮我看一下这里需要做什么,以便在提交后立即正确呈现隐藏字段(包含预期实体ID的«value»属性)?

控制器......

<?php
// ...
/**
 * @Route("/cities", name="admin_config_cities")
 */
public function configureCitiesAction(Request $request)
{
    # Retrieving existing cities
    $em = $this->getDoctrine()->getManager();
    $cities = $em->getRepository('AppBundle:City')->findAll();

    # Associate cities ids with corresponding objects
    $sorted = [];
    array_walk($cities, function ($value, $key) use (&$sorted) {
        $sorted[ $value->getId() ] = $value;
    });

    # Initialize form
    $citiesForm = $this->createForm(
        CollectionType::class,
        $cities,
        [
            'entry_type' => CityType::class,
            'allow_add' => true,
            'allow_delete' => true,
            'prototype' => true,
            # I thought "mapped" option would do the trick.
            # worse, seems to do nothing
            'mapped' => true,
            'label' => false,
            'entry_options'  => [
                'label' => false,
                'by_reference'=>true
            ]
        ]
    );
    if ($request->isMethod('POST')) {
        $citiesForm->handleRequest($request);
        if ($citiesForm->isValid()){
            # Persist any submitted datas
            foreach( $citiesForm->getData() as $city ){
                $id = $city->getId();
                if ($id && array_key_exists($id,$sorted)) {
                    unset($sorted[$id]);
                }
                $em->persist($city);
            }
            # Remove discared cities
            foreach( $sorted as $removed ){
                $em->remove($removed);
            }
            $em->flush();
        }
    }
    # TODO: find the way to make newly added cities to be rendered
    # along with their ID available inside an hidden field's attribute
    # right after submission (without the need of a refresh)
    return $this->render('AppBundle:admin:config/cities.html.twig', [
        'form' => $citiesForm->createView()
    ]);
}

CityType包含隐藏字段

//…
$builder->add( 'id', HiddenType::class, [ 'required'=>false ])
//…

相关模板

{# … #}
{{ form_start(form) }}
    <div data-prototype="{{ form_widget(collection.vars.prototype)|e }}">
        {% for item in collection %}
            {{ form_widget(item) }}
        {% endfor %}
        <p>
            <a class="btn btn-default btn-sm" title="{{ 'button-add-title'|trans }}">{{ 'button-add-caption'|trans }}</a>
        </p>
    </div>
    <p class="text-right">
        <button type="submit">Submit</button>
    </p>
{{ form_end(form) }}

跳得很清楚,谢谢。

修改

by_reference在集合entry_options内设置为true 我做过的测试说:它只对那里有影响。 True可以更新DB中的相应(现有)记录。另一方面,false会阻止映射,从而导致数据库中出现重复的条目 在集合本身上设置by_reference似乎根本就什么都不做 也就是说,新记录实际上是持久存在的,但是这个新创建的元素的修改会导致随机行为(由于allow_delete而被删除,发出了重复的条目)。仍然开发工具DOM树不显示隐藏字段的value属性,导航器源快捷方式 Ctrl + u 也不显示。一旦发出新的GET请求,就会出现值属性神奇。 这里有一些我不明白的事情:/

最后,我发现确保使用正确填充的隐藏字段来呈现表单的唯一方法是在$this->redirect($this->generateUrl($_route));之后命令flush()

0 个答案:

没有答案