我有一个基本控制器(ContentEditControlllerBase
),它可以完成编辑页面的所有标准功能。这个基本控制器由许多不同编辑页的控制器扩展,通常只是简单地向基本控制器传递一些基本选项。基本控制器加载一个表单,该表单通过基于加载的页面类型的自定义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
。
但是,我需要能够设置默认值,然后只覆盖特定值,因此实际上这些选项需要合并。当前,如果传入自定义选项,则会覆盖默认值的整个数组。
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(相同的合并)。
默认选项不用于合并。这是预期的行为。它们被称为默认值,因为它们只有在您未定义它们时才存在。您可以在此处阅读更多有关界面的信息
以下是覆盖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);
}
没有必要在“选项”下定义你的数组,使用你自己独特的索引。
// These options will be available for you
$resolver->setDefaults(array(
'enableAction' => array('publish' => FALSE),
'enableEntity' => array(
'viewSettings' => FALSE,
'content' => FALSE
),
));
创建表单并使其共享选项的另一种灵活方式是将它们创建为服务。这样,您可以根据需要共享配置中的选项。
最后,扩展FormType与扩展类不同。当您像对ContentSeo表单类型那样扩展类时,Symfony无法解析选项和依赖项。FormType通过在类中定义getParent()
方法相互继承。在一个类中使用getParent()
方法,让symfony知道此表单继承自另一个,选项将正确解析。
你的主要问题有两个:
>
首先,您尝试使用选项
,这已经使用了我的Symfony,如果您深入代码,您将看到Symfony在尝试合并任何内容之前检查它是否定义。您应该使用自己的索引键,而不是symfony默认使用的索引键。
其次,在扩展表单类型时,需要使用getParent,而不是扩展类。
尝试这两个更改,看看它对您的效果如何。我认为这应该是一个良好的开端。
希望这有助于澄清一些问题。
?为什么不在自定义表单类型中覆盖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']);
}
}
"'