Form: Avoid setting null to non submitted field

自古美人都是妖i 提交于 2019-12-21 05:09:24

问题


I've got a simple model (simplified of source):

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

And a form type:

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',
        ));
    }
}

My controller:

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;
}

When i POST /users/?form[page]=2&form[limit]=20, the response is what i expect:

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

Now, when i POST /users/?form[page]=3, the response is:

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

limit becomes null, because it was not submitted.

I wanted to get

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

Question: How can i change the form behaviour, so that it ignores non submitted values ?


回答1:


If is only a problem of parameters (GET parameters) you can define the default value into routing file

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

An alternative way could be to use a hook (i.e. PRE_BIND) and update manually that value into this event. In that way you haven't the "logic" spreaded into multi pieces of code.

Final code - suggested by Adrien - will be

<?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);
            }
        }
    }
}



回答2:


Here's a modification of the original answer. The most important benefit of this solution is that validators can now behave as if the form post would always be complete, which means there's no problems with error bubbling and such.

Note that object field names must be identical to form field names for this code to work.

<?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);

    }
}


来源:https://stackoverflow.com/questions/11687760/form-avoid-setting-null-to-non-submitted-field

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!