web-dev-qa-db-ja.com

symfony2フォームにカスタムオプションを渡す

symfony 1.4では、フォームのオプションを介してフォームクラス定義をパラメーター化することが可能でした。カスタムオプションをカスタムフォームタイプに渡す方法はありますか?私はbuildFormメソッドのoptionsパラメータを使用しようとしましたが、この配列が何であるかよくわかりません。どうやらそれは私が望むものではないようです...ありがとう!

26
Throoze

解決策は簡単です。カスタムオプションをTwigテンプレートでも利用可能にする場合は、buildFormメソッドで$builder->setAttribute()を使用し、$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以降用に更新

43
pulzarraider

PDATE:このソリューションは、廃止されたSymfony 2.0.xでのみ機能することに注意してください。setDefaultOptionsの代わりにgetDefaultOptionsを使用してください。


当然、Symfony 2のフォームタイプは、フォームタイプ内で必要なものに使用できるオプションを受け入れます。タイプオプションを指定するには、getDefaultOptionsメソッドをオーバーライドする必要があります。

たとえば、my_optionを受け入れるMyCustomType型があり、このオプションのデフォルト値は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の3番目のパラメーターを使用してオプションを指定する必要があります。

$form = $this->buildForm(new MyCustomType(), null, array(
    'my_option' => true
));

my_optionオプションを指定しない場合、デフォルト値(false)が使用されます。

18
eagleoneraptor

Symfony 2.8を使用して、configureOptions()メソッドを拡張する提案されたソリューションを使用することに成功しました。

_class ElementType extends AbstractType
{
    // ...

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'my_custom_option_parameter' => null,
        ));
    }
}
_

コレクションと埋め込みフォームとしてElementTypeを使用する必要がありました。 CollectionTypeconfigureOptions()をカスタマイズしなかったが、CollectionTypeをカスタマイズしていないため、_my_custom_option_parameter_をElementTypeに渡すことができないことを認識しました。 CollectionTypeを介して_my_custom_option_parameter_を渡す必要がある場合は、_my_custom_option_parameter_で_entry_options_を定義することで成功する場合があります(ドキュメント CollectionType FieldCollectionTypeの配列。

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!'
            )
        ));
        //...
    }
}
_
10
Erik Theoboldt

@pulzarraiderの回答に基づいて、Symfony 3用に変更を加えたコードを作成しました。

変更する必要があります

OptionsResolverInterface for OptionsResolver

FormBuilder for 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;
    }
}
4

Symfony 3を使用して、フォームタイプクラスのconfigureOptionsメソッドに挿入されたOptionsResolverでデフォルトオプションを設定することで、カスタムオプションをフォームに渡すことができました。

コントローラーで:

_//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();
_

コントローラーで。なぜこれが私の向こうにあるのか。 。 。

2
eggmatters

私はそのオプションarrayを使用しようとしましたが、キーの事前定義された小さなサブセットのみを運ぶことができると思われたため、成功しませんでした。これはどうしても私には受け入れられませんでした...

ただし、フォーム__constructメソッドを介してすべてのオプションを渡し、後で使用するためにクラスプロパティに保存することができます。次に、buildFormから$this->"propertyName"...を使用してアクセスできます。

__constructに単一のarrayを渡すか、いくつかの変数を渡すかを決めるのはあなた次第です...

これは大まかな例です。

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
        }
    }
}
2
Jovan Perovic