5

私は単純なモデルを持っています(ソースを単純化したもの):

class Collection
{
    public $page;
    public $limit;
}

そしてフォームタイプ:

class CollectionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('page', 'integer');
        $builder->add('limit', 'integer');
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'FSC\Common\Rest\Form\Model\Collection',
        ));
    }
}

私のコントローラー:

public function getUsersAction(Request $request)
{
    $collection = new Collection();
    $collection->page = 1;
    $collection->limit = 10;

    $form = $this->createForm(new CollectionType(), $collection)
    $form->bind($request);

    print_r($collection);exit;
}

iPOST /users/?form[page]=2&form[limit]=20の場合、応答は私が期待するものです:

Collection Object
(
    [page:public] => 2
    [limit:public] => 20
)

ここで、 iのときPOST /users/?form[page]=3の応答は次のとおりです。

Collection Object
(
    [page:public] => 3
    [limit:public] =>
)

limit送信されていないため、null になります。

もらいたかった

Collection Object
(
    [page:public] => 3
    [limit:public] => 10 // The default value, set before the bind
)

質問: フォームの動作を変更して、送信されていない値を無視するにはどうすればよいですか?

4

2 に答える 2

10

パラメータ(GETパラメータ)のみの問題である場合は、ルーティングファイルにデフォルト値を定義できます

route_name:
pattern: /users/?form[page]={page}&form[limit]={limit}
defaults: { _controller: CompanyNameBundleName:ControllerName:ActionName, 
                         limit:10 }

別の方法は、フック(つまり、 PRE_BIND)を使用して、その値をこのイベントに手動で更新することです。このようにして、「ロジック」が複数のコードに分散することはありません。

最終的なコード-エイドリアンによって提案された-は

<?php

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;

class IgnoreNonSubmittedFieldSubscriber implements EventSubscriberInterface
{
    private $factory;

    public function __construct(FormFactoryInterface $factory)
    {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents()
    {
        return array(FormEvents::PRE_BIND => 'preBind');
    }

    public function preBind(FormEvent $event)
    {
        $submittedData = $event->getData();
        $form = $event->getForm();

        // We remove every child that has no data to bind, to avoid "overriding" the form default data
        foreach ($form->all() as $name => $child) {
            if (!isset($submittedData[$name])) {
                $form->remove($name);
            }
        }
    }
}
于 2012-07-27T12:34:43.167 に答える
2

これが元の回答の変更です。このソリューションの最も重要な利点は、フォームの投稿が常に完了しているかのようにバリデーターが動作できるようになったことです。つまり、エラーのバブリングなどの問題はありません。

このコードが機能するには、オブジェクトのフィールド名がフォームのフィールド名と同じでなければならないことに注意してください。

<?php
namespace Acme\DemoBundle\Form;

use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormFactoryInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Form\FormEvents;

class FillNonSubmittedFieldsWithDefaultsSubscriber implements EventSubscriberInterface
{
    private $factory;

    public function __construct(FormFactoryInterface $factory)
    {
        $this->factory = $factory;
    }

    public static function getSubscribedEvents()
    {
        return array(FormEvents::PRE_BIND => 'preBind');
    }

    public function preBind(FormEvent $event)
    {
        $submittedData = $event->getData();
        $form = $event->getForm();

        // We complete partial submitted data by inserting default values from object
        foreach ($form->all() as $name => $child) {
            if (!isset($submittedData[$name])) {
                $obj = $form->getData();

                $getter = "get".ucfirst($name);
                $submittedData[$name] = $obj->$getter();
            }
        }
        $event->setData($submittedData);

    }
}
于 2013-05-13T12:47:05.433 に答える