合并在setOptionDefaults()中定义的Symfony表单中的自定义和默认选项

时间:2014-10-09 23:50:51

标签: php symfony

结构

我有一个基本控制器(ContentEditControllerBase),它可以完成编辑页面的所有标准功能。该基本控制器由许多不同编辑页面的控制器扩展,通常只是将一些基本选项传递给基本控制器。基本控制器加载一个表单,该表单根据加载的页面类型(每个编辑页面表单看起来不同)通过自定义formType编辑View对象。

编辑文章本身(唯一内容类型的唯一包)

Route: /Admin/Article/Edit
Controller: \Gutensite\ArticleBundle\Controller\ArticleEditController (extends ContentEditControllerBase)
FormType: \Gutensite\ArticleBundle\Form\Type\ArticleEditType (extends ViewType)

编辑此页面的SEO字段(所有页面的标准CMS编辑字段)

Route: /Admin/Content/SEO/Edit
Controller: \Gutensite\CmsBundle\Controller\ContentSeoEditController (extends ContentEditControllerBase)
FormType: \Gutensite\CmsBundle\Form\Type\ContentSeoEditType (extends ViewType)   

扩展的ViewType表单加载自定义ViewVersionType表单(某些选项需要传递给该表单中的此关联实体)。

ContentEditControllerBase (由所有编辑页面扩展)

// the View Object is created
$view = new View;

// We determine the correct custom formType to load based on settings for the 
// particular editing page being loaded (e.g. some pages will edit the main 
// content, others the SEO settings. This will create a path like:
// \Gutensite\CmsBundle\Form\Type\ContentSeoEditType
$formTypePath = $currentPage->getBundleInfo()['bundleNamespace']
                    .'\Form\Type\\'.$$currentPage->getBundleInfo()['controller']
                    .'Type';

// We then load the correct formType and pass in any options, e.g. access level to different fields (i.e. will this form show the publish button or just the save button)
$form = $this->createForm(new $formTypePath, $view, $options);

设置选项

在ViewType中,我们使用setDefaultOptions(),并使用一些合理的默认值(请参阅下面的代码)。这允许我的控制器将选项传递给自定义表单类型。我的ViewType表单会将其中一些值传递给ViewVersionType

但是,我需要能够设置默认值,然后只覆盖特定值,因此实际上这些选项需要 MERGE 。目前,如果我传入自定义选项,则会覆盖整个默认值数组。

课程代码

ContentSeoEditType (使用额外字段扩展ViewType)

namespace Gutensite\CmsBundle\Form\Type;

use Symfony\Component\Form\FormBuilderInterface;

class ContentSeoEditType extends ViewType
{

    public function getName()
    {
        return 'contentSeoEditType';
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        // Enable existing options on ViewVersion object
        $options['options']['viewVersion']['enableGroup']['seo'] = TRUE;

        /**
         * Add New Inputs to View object
         */
        $builder->add('routing', 'collection', array(
            'label' => false,
            'type' => new RoutingType(),
            'allow_add' => true,
            'allow_delete' => true,
            'prototype'     => true,
            'by_reference' => false
        ));

        parent::buildForm($builder, $options);
    }


}

ViewType (包含相关表单的表单类型)

namespace Gutensite\CmsBundle\Form\Type;

use Gutensite\CmsBundle\Entity\View;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ViewType extends AbstractType
{

    public function getName()
    {
        return 'view';
    }


    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'Gutensite\CmsBundle\Entity\View\View',
            'cascade_validation' => true,
            // Custom Options
            'options' => array(
                // Options for viewVersion
                'viewVersion'       => array(),
                // Enabling Options
                'enableAction' => array(
                    'create'        => TRUE,
                    'save'          => TRUE,
                    'publish'       => FALSE,
                    'version'       => FALSE,
                    'duplicate'     => FALSE,
                    'delete'        => FALSE
                )
            )
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {

        // Pass Specific Variables to ViewVersion Options (when loaded below)
        $options['options']['viewVersion']['enableAction']['publish'] = $options['options']['enableAction']['publish'];


        $builder
            ->add('version', new ViewVersionType(), array(
                'label' => false,
                'required' => false,
                // Pass options to viewVersion form type
                'options' => $options['options']['viewVersion']
            ))
        ;
    }
}

ViewVersionType (自定义表单类型库)

namespace Gutensite\CmsBundle\Form\Type;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class ViewVersionType extends AbstractType
{

    public function getName()
    {
        return 'viewVersion';
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver) {
        $resolver->setDefaults(array(
            'data_class' => 'Gutensite\CmsBundle\Entity\View\ViewVersion',
            // Add a custom option bucket
            'options' => array(
                    'enableField'       => array(
                        'title'         => FALSE,
                        'versionNotes'  => FALSE,
                        'timeCustom'    => FALSE
                ),
                'enableAction'      => array(
                    'publish'       => FALSE
                ),
                'enableEntity'      => array(
                        'viewSettings'  => FALSE,
                        'content'       => FALSE
                ),
                'enableGroup'       => array(
                        'layout'        => FALSE,
                        'seo'           => FALSE
                )
            )
        ));
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        // **********************************
        // ERROR: $options['options'] does NOT have all the default options listed in setDefaultOptions()
        // Only has $options['options']['enableGroup']['seo'] = 1
        // Only has $options['options']['enableAction']['publish'] = 1
        // **********************************


    }
}

问题摘要

如何在formType上设置默认选项,还允许我的控制器传入特定的自定义选项以仅覆盖该选项,即将我的自定义选项与默认选项合并。我需要能够将ViewType中的选项传递给从ViewType加载的子窗体ViewTypeVersion(相同的合并)。

2 个答案:

答案 0 :(得分:4)

不进行合并的默认选项。这是预期的行为。它们被称为默认值,因为它们仅在您未定义它们时才存在。您可以阅读有关界面here

的更多信息

以下是覆盖OptionResolver选项的代码部分:

// Make sure this method can be called multiple times
$combinedOptions = clone $this->defaultOptions;

// Override options set by the user
foreach ($options as $option => $value) {
    $combinedOptions->set($option, $value);
}

无需在“options”下定义您的数组,使用您自己的唯一索引。

// These options will be available for you
$resolver->setDefaults(array(
    'enableAction' => array('publish' => FALSE),
    'enableEntity' => array(
        'viewSettings'  => FALSE,
        'content'       => FALSE
     ),
));

另一种创建表单并让它们共享选项的灵活方法是creating them as a service。这样,您可以根据需要共享配置中的选项。

最后,扩展FormType与扩展类不同。与扩展ContentSeo表单类型时,Symfony无法在扩展类时解析选项和依赖项。 FormType通过在类中定义getParent()方法来相互继承。在一个类中使用getParent()方法让symfony知道这个表单是从另一个继承的,并且选项将被正确解析。

您的主要问题是两个问题:

  • 首先,您正在尝试使用已经使用我的symfony的options,如果您深入研究代码,您将看到symfony在尝试合并任何内容之前检查它是否已定义。您应该使用自己的索引键,而不是symfony默认使用的索引键。

  • 其次,在扩展表单类型而不是扩展类时,需要使用getParent。

尝试这两项更改,看看它是如何运作的。我相信这应该是一个好的开始。

希望有助于澄清一些问题。

答案 1 :(得分:0)

¿为什么不在自定义 FormTypes 中覆盖buildView函数?

$view变量有一个名为vars的属性,其中包含选项(一旦解析),您可能需要使用实际合并的值进行更新。

看看这个例子:

class MyFormType extends AbstractType
{
    //some code ...

    public function buildView(FormView $view, FormInterface $form, array $options)
    {
        $view->vars['options'] = array_merge($this->fixedOptions,$view->vars['options']);
    }

}

```