Подтвердить что ты не робот

Передача пользовательских параметров в форму symfony2

в symfony 1.4 можно было параметризовать определение класса формы с помощью опций формы. Есть ли способ передать пользовательские параметры в свой собственный тип формы??? Я попытался использовать параметр options метода buildForm, но я не очень уверен, что это за массив, и, видимо, это не то, что я хочу... Спасибо!

4b9b3361

Ответ 1

Решение прост, если вы хотите, чтобы ваша пользовательская опция была доступна также в шаблоне Twig, вы должны использовать $builder->setAttribute() в buildForm а также $view->set() в методе buildView().

<?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 или выше

Ответ 2

ОБНОВЛЕНИЕ: Обратите внимание, что это решение работает только в 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).

Ответ 3

Используя 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 невозможно, потому что я не настроил configureOptions() из CollectionType, а моего ElementType. Если вам нужно передать my_custom_option_parameter через a CollectionType, вы можете добиться успеха, указав my_custom_option_parameter в entry_options (см. Документация Поле CollectionType) массива CollectionType.

Пример прохождения my_custom_option_parameter через a CollectionType:

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!'
            )
        ));
        //...
    }
}

Ответ 4

Я пробовал использовать эти опции 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
        }
    }
}

Ответ 5

Основываясь на ответе @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;
    }
}

Ответ 6

Используя Symfony 3, я смог передать пользовательские параметры форме, установив параметр по умолчанию в OptionsResolver, введенный в метод configureOptions моего класса типа формы:

В контроллере:

//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.
       . . .

Итак, похоже, вы можете определить контракт с вашей формой и поставщиком данных для установки произвольных данных в форме.

Я только что успешно выполнил эту процедуру. Обратите внимание, что в обратном пути, поскольку вы установили 'mapped' => false, в formBuilder, $form->getData() не вернет выделение. Чтобы получить выбранное значение:

$mySelectedValue = $form->get('my_custom_options')->getViewData();

в вашем контроллере. Почему это за пределами меня.,.