我有一个简单的模型(源代码简化):
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;
}
当我POST /users/?form[page]=2&form[limit]=20
时,回应是我所期望的:
Collection Object
(
[page:public] => 2
[limit:public] => 20
)
现在,当我POST /users/?form[page]=3
时,回复是:
Collection Object
(
[page:public] => 3
[limit:public] =>
)
limit
变为空,因为它未提交。
我想得到
Collection Object
(
[page:public] => 3
[limit:public] => 10 // The default value, set before the bind
)
问题:如何更改表单行为,以便忽略未提交的值?
答案 0 :(得分:10)
如果只是参数问题(GET参数),您可以将默认值定义为路由文件
route_name:
pattern: /users/?form[page]={page}&form[limit]={limit}
defaults: { _controller: CompanyNameBundleName:ControllerName:ActionName,
limit:10 }
另一种方法是使用 hook (即PRE_BIND)并将该值手动更新到此事件中。通过这种方式,你没有将“逻辑”扩展到多段代码中。
最终代码 - 由Adrien建议 - 将是
<?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);
}
}
}
}
答案 1 :(得分: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);
}
}