动态表单(切换实体)symfony2

Posted

技术标签:

【中文标题】动态表单(切换实体)symfony2【英文标题】:Dynamic form (switch entity) symfony2 【发布时间】:2013-11-06 21:01:56 【问题描述】:

我正在制作一个广告页面。广告可以是不同的类型,因此具有不同的数据。例如,车辆会将makemodel 作为额外数据。

现在,我有一个基本原则实体Advert,其中包含每个广告所需的数据。不同的广告依次继承这些数据(doctrine2 discriminatormap)

如果用户选择创建车辆广告,我需要动态填充表单(使用 ajax 和 symfony2 表单)我想显示车辆广告的选项。但我还需要将实体更改为AdvertVehicle 的形式。

这可能吗?我确实在 symfony2 主页上阅读了食谱条目

《如何使用表单事件动态修改表单》: 这应该通过对您的应用程序进行 AJAX 回调来处理。在该控制器中,您可以提交表单,但无需处理它,只需使用提交的表单来呈现更新的字段。然后可以使用来自 AJAX 调用的响应来更新视图。

我了解如何将 ajax 回调回我的控制器,并且我了解如何使用表单事件,但是如何获取渲染的选择框(例如包含车辆模型)的响应?使用新的 AbstractType?还是表单生成器?

然后当用户实际提交表单时,我需要使用所选广告类型的实体。我可以根据用户在表单中的选择动态更改实体吗?

编辑 我检查了表格继承,这很好,谢谢。我扩展了AdvertType 并覆盖了buildForm() 方法,在添加AdvertVehicleType 所需的项目之前,我调用了父方法。

进一步说明 每个广告实体都包含pricedescriptiontitlecategory。有些广告包含更多,例如makemodel。它们由discriminatormap (doctrine2) 区分

示例:

// -- Entity
class CarAdvert extends Advert 

    protected $model;
    protected $make;



// -- Entity
// -- This uses discriminator mapping
class Advert 
    protected $title;
    protected $description;
    protected $price;
    protected $category;

如果用户选择类别 cars 我想使用 CarAdvert 实体(用于验证和持久性)如果用户选择家庭项目类别我只想使用普通的 Advert 实体。

一个主要问题仍然是我无法弄清楚如何通过 ajax 呈现扩展表单。这部分有什么提示吗?当用户选择汽车作为类别时,我希望更新表单(通过 jQuery/ajax)但是我如何制作一个控制器来检索表单的扩展部分并将 html 作为响应发送回(不使用树枝并在视图中渲染,这可能吗)?

解决方案:

请看下面的答案!

【问题讨论】:

你可以在你的表单类型中使用继承,它避免了为两个相似的表单重复代码。示例:AdvertType 有 2 个字段。 AdvertVehicleType 可以扩展 AdvertType 以添加 2 个字段。请告诉我们有关您的实体的更多信息,它们是如何声明的,您如何区分两种类型的Advert 等。 关于这个问题@Asbestos 的任何更新?我面临着类似的问题,因此我对可能的解决方案或解决此问题的经验等感兴趣。谢谢! 我希望更新后的答案足够好@acrobat 如果您需要更多信息,请随时发表评论! 【参考方案1】:

解决方案:

我的问题的解决方案是在控制器中创建一些额外的函数来解决我希望能够从用户的选择中“动态”更改实体和表单的问题..

public function indexAction(Request $request)

    $form = $this->getForm($request);
    $form->handleRequest($request);

    return array(
           'form' => $form->createView(),
           'request' => $request->request,
    );

getForm 检索表单的位置,(例如,用于车辆的 AdvertVehicleType 或用于“默认”广告的 AdvertType)。

getForm 方法如下所示:

 private function getForm(Request $request)

    $categoryTitle = 'NONE';
    $categoryId = $request->request->get('advert', false)['category'];

    if ($categoryId) 
        $categoryTitle = $this->getDoctrine()->getRepository('Bundle:Category')->find($categoryId)->getTitle();
    

    return $this->createForm($this->getFormType($categoryTitle), $this->getEntity($categoryTitle));

在这里,我检索categoryID(在请求中的表单中选择)并使用 getFormType 检索 formType 并使用 getEntity 检索实体。

private function getEntity($categoryTitle)

    $entity = new Advert();
    switch ($categoryTitle) 
        case Category::CARS:
            $entity = new AdvertCar();
    

    return $entity;


private function getFormType($categoryTitle)

    switch ($categoryTitle) 
        case Category::CARS:
            return new AdvertCarType();
        default:
            return new AdvertType();
    

为了能够使用 ajax “即时”更新此内容(但如果用户尝试提交表单也可以使用),我在控制器中创建了另一个操作。

此操作呈现我想要更新的表单部分(在 ajax 调用上),我通过实际选择表单中不需要的内容来执行此操作,并使用 twig 将表单对象设置为如下所示:

% do form.title.setRendered %

(这只是一个示例,我实际上对所有我不想呈现的表单对象执行此操作。

然后我只需调用:

 form_rest(form) 

这将检索不同类别的表单的“其余部分”。

现在假设您要选择州和城镇。首先选择该州,然后在 twig 中渲染该州的城镇(但实际上您可以只渲染您需要的部分,例如 form_row(form.towns) ,然后将此渲染的模板作为 json-response 返回,然后将其放入您的 div想用jquery。

$html = $this->renderView('@Bundle/NewAddPage/filter_area.twig', array('form' => $form->createView()));

然后在响应中返回 $html 变量。

我希望这会有所帮助,并且解释足够好,如果不只是发表评论,我会用我的答案更新这个!

【讨论】:

以上是关于动态表单(切换实体)symfony2的主要内容,如果未能解决你的问题,请参考以下文章

symfony2 构建表单实体 oneToMany

Symfony2 - 使用没有附加任何实体的表单生成器

Symfony2 在表单本身中创建新的实体元素

Symfony2 防止多个表单提交

为啥 Chrome 不缓存我的动态表单字段?

从 Symfony2 表单存储实体不起作用