我有一个基本控制器(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(相同的合并)。
答案 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']);
}
}
```