同一实体类型的多种形式

时间:2018-09-18 14:00:34

标签: php symfony twig symfony-forms

我无法为似乎如此直接的事情找到解决方案,这真是令人惊讶。

我的网站有一个简单的设置页面。所有设置都存储在一个简单的表中:

| id | name                | label                                             | type   | value                 | is_user_created | is_editable | edit_date           | original_name | category         | file                 | subcategory |
+----+---------------------+---------------------------------------------------+--------+-----------------------+-----------------+-------------+---------------------+---------------+------------------+----------------------+-------------+
| 21 | index_header_large  | Large header for index page                       | bool   | true                  |               0 |           1 | 2018-09-17 13:22:20 |               | Layout           |                      | Heading     |
| 25 | website_title       | Short title                                       | string | My website            |               0 |           1 | 2018-09-17 13:22:20 |               | Details website  |                      |             |
| 26 | website_owner       | Name of the owner                                 | string | Not specified         |               0 |           1 | 2018-09-17 13:22:20 |               | Gegevens website |                      |             |
+----+---------------------+---------------------------------------------------+--------+-----------------------+-----------------+-------------+---------------------+---------------+------------------+----------------------+-------------+

设置表中有一个名为type的列。我用它来生成一个FormType,该字段具有正确的字段/断言,用于表单将要呈现的值的类型。

它们看起来都非常相似,这种类型的字符串类型为:

class SettingsType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        /* @var $entity \App\Entity\Setting */
        $entity=$builder->getData();
        $builder
            ->add('value', TextType::class, array(
                'label'             => $entity->getLabel(),
                'trim'              => true,
                'translation_domain' => 'app'
            ));
        ;
    }
}

在控制器中,我获取设置并对其进行迭代以创建表单

    $settings = $repSettings->findAllOrderedByCategory();

    $settingForms = [];
    /* @var $setting Setting */
    foreach ($settings as $setting) {
        if ($setting->getType() === 'bool') {
            array_push($settingForms, $this->createForm(SettingsBoolType::class, $setting, array(
                'action' => $this->generateUrl(
                    'admin_set_setting_value',
                    array(
                        "_locale" => $request->getLocale(),
                        "_id" => $setting->getId()
                    )
                )
            ))->createView());
        } else if ($setting->getType() === 'file') {
            array_push($settingForms, $this->createForm(SettingsFileType::class, $setting, array(
                'action' => $this->generateUrl(
                    'admin_set_setting_file',
                    array(
                        "_locale" => $request->getLocale(),
                        "_id" => $setting->getId())
                )
            ))->createView());
        } else {
            array_push($settingForms, $this->createForm(SettingsType::class, $setting, array(
                'action' => $this->generateUrl(
                    'admin_set_setting_value',
                    array(
                        "_locale" => $request->getLocale(),
                        "_id" => $setting->getId())
                )
            ))->createView());
        }
    }

    return $this->render('admin/manage_settings.html.twig', array_merge(
        array(
            'settingForms'      => $settingForms,
        )
    ));

到目前为止,这些表单可以呈现和工作,因为每个表单在操作URL中都设置了唯一的ID。但是这种方法存在一些问题。

  • 提交了错误的值:似乎适用于字符串值形式,但有时布尔值形式会为错误的设置提交值。

  • 重复ID:每种表单的block_prefixes被设置为类名(例如settings_value)。

我知道这不是您应该采取的方式,但是我对应该采取的方式一无所知。可能是收藏吗?我应该创建一个 super 类以呈现CollectionType吗?在那种情况下,我需要知道如何应用自己的布局,因为我为设置表中的每个categorysubcategory列渲染了标题。

朝正确方向的推动将不胜感激:)

1 个答案:

答案 0 :(得分:1)

我今天遇到了同样的问题。这是我解决的方法:

您将不得不修改您的代码以填写您的应用程序,以下代码只是我所做的关于事情如何工作的演示。 不要犹豫,在评论中提问 $data只是一个包含一些Setting对象的数组。 为了获得更快的速度,我将Symfony内置类型用于Settings :: type属性。您可以在ExtendedFieldCollectionType中自由编码适配器

<?php

namespace App\Controller;

use App\Model\Setting;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class DemoController extends AbstractController
{
    /**
     * @Route(name="demo_demo", path="/demo")
     * @Template()
     * @param Request $request
     * @return array
     */
    public function demo(Request $request)
    {
        $data = [
            new Setting('count', NumberType::class, 0.5),
            new Setting('text', TextType::class,'sample text'),
            new Setting('date', DateType::class, new \DateTime())
        ];

        $form = $this->createForm('App\Form\ExtendedFieldCollectionType', $data);

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            // ...
        }

        return [
            'form' => $form->createView()
        ];
    }
}

以及表单类型:

<?php

namespace App\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;

class ExtendedFieldCollectionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
            $form = $event->getForm();
            $data = $event->getData();

            foreach ($data as $name => $value) {
                $form->add($value->id, $value->type, [
                    'property_path' => '[' . $name . '].value', // the value property is my setting value
                ]);
            }
        });
    }
}

我使用的模型

<?php

namespace App\Model;


class Setting
{
    public $id;
    public $type;
    public $value;

    /**
     * ProjectField constructor.
     * @param $id
     * @param $type
     * @param $value
     */
    public function __construct($id, $type, $value)
    {
        $this->id = $id;
        $this->type = $type;
        $this->value = $value;
    }
}