解决方案很简单,如果你希望在Twig模板中也能使用你的自定义选项,你需要在buildForm
方法中使用$builder->setAttribute()
方法,并且在buildView()
方法中也要使用$view->set()
方法。
<?php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType as FormAbstractType;
use Symfony\Component\Form\FormBuilder;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
// For Symfony 2.1 and higher:
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
/**
* ImagePreviewType
*
*/
class ImagePreviewType extends FormAbstractType
{
/**
* {@inheritDoc}
* For Symfony 2.0
*/
//public function getDefaultOptions(array $options)
//{
// $options = parent::getDefaultOptions($options);
// $options['base_path'] = 'path/to/default/dir/';
//
// return $options;
//}
/**
* {@inheritDoc}
* For Symfony 2.1 and higher
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'base_path' => '',
));
}
/**
* {@inheritDoc}
*/
public function buildView(FormView $view, FormInterface $form, array $options)
{
// For Symfony 2.0:
// $view->set('base_path', $form->getAttribute('base_path'));
// For Symfony 2.1 and higher:
$view->vars['base_path'] = $options['base_path'];
}
/**
* {@inheritDoc}
*/
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->setAttribute('base_path', $options['base_path'])
;
}
/**
* {@inheritDoc}
*/
public function getName()
{
return 'image_preview';
}
public function getParent(array $options)
{
// for Symfony 2.0:
// return 'field';
// for Symfony 2.1 and higher:
return 'form';
}
}
自定义表单类型的模板(文件...Acme/DemoBundle/Resources/views/Form/fields.html.twig):
{% block image_preview_widget %}
{% spaceless %}
<img src="{{ base_path ~ value }}" alt="" {{ block('widget_container_attributes') }} />
{% endspaceless %}
{% endblock %}
在 app/config/config.yml 中注册您的模板以用于自定义表单类型。
twig:
debug: %kernel.debug%
strict_variables: %kernel.debug%
form:
resources:
- 'AcmeDemoAdminBundle:Form:fields.html.twig'
用法:在编辑用户资料时显示用户头像的预览。
// src/Acme/DemoBundle/Form/Type/UserType.php
namespace Acme\DemoBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
class UserType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder->add('user_profile_image_file_name', new ImagePreviewType(), array(
'base_path' => 'some/other/dir',
));
}
}
2014-08-18: 为Symfony 2.1或更高版本更新
更新:请注意,此解决方案仅适用于已经过时的Symfony 2.0.x版本,请使用setDefaultOptions
替代getDefaultOptions
。
Symfony 2表单类型公正地接受您可以在表单类型内部使用的选项。 您需要重写getDefaultOptions
方法来指定您的类型选项。
例如,我有一个类型MyCustomType
,接受my_option
,此选项的默认值为false
,则MyCustomType
的实现可如下所示。
class MyCustomType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
if($options['my_option']){
//do something
} else {
//do another thing
}
...
}
public function getDefaultOptions(array $options)
{
return array(
'my_option' => false
);
}
public function getName()
{
return 'mycustomtype';
}
}
稍后,您需要在控制器中创建表单时使用buildForm
的第三个参数来指定选项:
$form = $this->buildForm(new MyCustomType(), null, array(
'my_option' => true
));
如果您没有指定my_option
选项,它会采用默认值(false
)。getDefaultOptions
方法即可。 - eagleoneraptorbuildForm
的$options
数组用于向类型传递自定义选项。然后,基于这些选项,您可以设置Form
和/或FormView
属性以在不同位置(例如视图)中使用选项,或者您可以设置视图属性而无需任何选项。但问题是,“如何将选项传递给自定义表单类型”,也许这个问题并不适合作者的需求。 - eagleoneraptorgetDefaultOptions()
,而是使用setDefaultOptions()
。否则会显示:“选项'no_animal_type'不存在。已知的选项包括:"action"、"attr"、"auto_initialize",…” - Bonswouar使用Symfony 2.8,通过使用建议的解决方案扩展configureOptions()
方法,我成功了。
class ElementType extends AbstractType
{
// ...
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'my_custom_option_parameter' => null,
));
}
}
我需要将ElementType
作为集合和嵌入式表单使用。我意识到无法将my_custom_option_parameter
传递给CollectionType
,因为我没有自定义CollectionType
的configureOptions()
,而是自定义了ElementType
的configureOptions()
。如果您需要通过CollectionType
传递my_custom_option_parameter
,可以将其定义在CollectionType
的entry_options
(请参见文档CollectionType Field)数组中。
通过CollectionType
传递my_custom_option_parameter
的示例:
class OuterFormType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
//...
$builder->add('elements', CollectionType::class, array(
'entry_type' => ElementType::class,
// ...
'entry_options' => array(
'my_custom_option_parameter' => 'value is now set!'
)
));
//...
}
}
基于 @pulzarraider 的答案,我创建了一个有关Symfony 3的修改代码。
您需要更改:
OptionsResolverInterface
为 OptionsResolver
FormBuilder
为 FormBuilderInterface
在我的情况下:
namespace MediaBundle\Form;
use Symfony\Component\Form\AbstractType as FormAbstractType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
class ImageType extends FormAbstractType {
public function configureOptions(OptionsResolver $resolver) {
$resolver->setDefaults(array(
'max_images' => ''
));
}
public function buildView(FormView $view, FormInterface $form, array $options) {
$view->vars['max_images'] = $options['max_images'];
}
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder
->setAttribute('max_images', $options['max_images'])
;
}
public function getName() {
return 'image_preview';
}
public function getParent() {
return TextareaType::class;
}
}
//Compile whatever your options are here. Assume an array is returned
$customOptions = $this->getMyCustomOptions($args);
//Build the form:
$form = $this->createForm(MyCustomFormType::class, array('my_custom_options' => $customOptions));
MyCustomFormType.php:
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => DataModel::class,
'my_custom_options' => []
]);
}
//custom options is now set in "$options" array:
public function buildForm(FormBuilderInterface $builder, array $options) {
$builder->add('my_custom_fields', Type\ChoiceType::class, [
'choices' => $options['my_custom_options'],
'mapped' => false //if not part of the data model.
. . .
看起来您可以为表单和数据提供程序定义合同,以在表单上设置任意数据。
我刚刚成功地实施了这个过程。请注意,在回程时,由于您在formBuilder中设置了'mapped' => false
,$form->getData()
不会返回选择内容。要获取所选值:
$mySelectedValue = $form->get('my_custom_options')->getViewData();
我曾尝试使用选项 array
,但似乎它只能携带小而预定义的键的子集,因此没有成功。对我来说,这是完全不可接受的...
然而,你可以通过表单的 __construct
方法传递所有选项,并将其存储在类属性中以供以后使用。然后,在 buildForm
中,可以使用 $this->"propertyName"
访问它...
你可以自行决定是否要将单个 array
或仅几个变量传递给 __construct
...
这只是一个简单的示例:
class Foobar{
private $update = false;
public function __construct($update = false){
$this->update = $update;
}
public function buildForm(FormBuilder builder, array options){
if ( $update ){
// something
}else{
// well, this is not an update - do something else
}
}
}