如何在Symfony2中设置表单字段的默认值?


137

有没有一种简单的方法可以为文本表单字段设置默认值?


1
是的,但是这个问题给出的答案不令人满意/不起作用...我将添加一个“编辑”来解释原因:-)
herrjeh42

看来,您追求的“完美”解决方案是使字段具有“ default_value”选项。事情是,目前还不行,所以我认为您目前所寻找的理想解决方案不存在。symfony唯一提供的内容(请参阅链接) data选项。因此,if-then是我看到的atm的唯一方法。即使字段本身有一个“ default_value”选项,我也想像它本质上还是会在内部做同样的事情。
crysallus

另外,我根据下面的评论对方法2中的答案进行了更正。如果这样可以解决您在第2点中提到的语法问题,则可能需要将其注释掉。或者让我知道问题出在哪,我会解决我的答案。
crysallus

1
@Crone这个问题是2年前提出的
OndrejSlinták16年

1
@OndrejSlinták我也没有投票赞成以重复方式关闭,但仅供参考:谁先提出都没关系,如果新问题是一个更好的问题或具有更好的答案,则投票关闭旧的作为重复项的新版本。
杰夫·普基特

Answers:


105

可以在创建过程中轻松使用:

->add('myfield', 'text', array(
     'label' => 'Field',
     'empty_data' => 'Default value'
))

11
对于Symfony 2.1,我需要将'data'密钥更改为'value'
Edd 2012年

175
这不仅设置了默认值,还将始终在任何上下文中强制使用该值。不是我所说的“默认值” ...
休伯特·佩伦

4
我否决了该解决方案,因为它不是解决问题的方法(如上文Hubert Perron所述)。我试图让在这个岗位更好的解决办法stackoverflow.com/questions/17986481/...
herrjeh42

13
这是初始值,默认值为empty_data
Pierre de LESPINAY

3
data没有用-它会覆盖保存的值。empty_data不显示该值,而是将其用于空值提交,并且无法保存未经检查的选择。
Moldcraft '17

115

您可以使用设置默认值 empty_data

$builder->add('myField', 'number', ['empty_data' => 'Default value'])

29
设置数据未设置默认值。这个答案是正确的。
Alexei Tenitski 2014年

9
这似乎仅在没有任何值的情况下将字段设置为1。如果您希望在不存在任何值的情况下使表单默认为在输入中显示1,该怎么办?
布莱恩

在我的测试中,empty_data不允许我覆盖提交为空的字段的默认值,例如,如果要保存为0而不是NULL到数据库。就我所知,此错误仍然很突出:github.com/symfony/symfony/issues/5906
Chadwick Meyer

63

我过去曾多次考虑过这一点,因此以为我记下了我曾经/曾经使用过的不同想法。可能有用,但是没有一个是“完美的” Symfony2解决方案。

构造函数 在Entity中,您可以执行$ this-> setBar('default value');。但这在每次加载实体(无论是否加载db)时都会调用,并且有点混乱。但是,它确实适用于每种字段类型,因为您可以创建日期或其他所需的内容。

如果get中的语句 不是,但可以。

return ( ! $this->hasFoo() ) ? 'default' : $this->foo;

工厂/实例。调用静态函数/辅助类,该类为您提供一个预填充了数据的默认实体。例如

function getFactory() {
    $obj = new static();
    $obj->setBar('foo');
    $obj->setFoo('bar');

   return $obj;
}

如果添加额外的字段,您必须维护此功能,这并不是很理想,但这确实意味着您要分隔数据设置器/默认值和从数据库生成的值。同样,如果您需要不同的默认数据,则可以有多个getFactories。

扩展/反射实体 创建一个扩展实体(例如FooCreate扩展Foo),该实体在创建时(通过构造函数)为您提供默认数据。与工厂/实例的想法类似,只是一种不同的方法-我个人更喜欢静态方法。

在构建表单之前设置数据在 构造函数/服务中,您知道是否有新实体,或者是否从数据库中填充了它。因此,当您获取一个新实体时,在不同的字段上调用集合数据是合理的。例如

if( ! $entity->isFromDB() ) {
     $entity->setBar('default');
     $entity->setDate( date('Y-m-d');
     ...
}
$form = $this->createForm(...)

表单事件 创建表单时,在创建字段时设置默认数据。您可以重写此使用PreSetData事件侦听器。这样做的问题是,您正在复制表单工作负载/复制代码,并使维护/理解变得更加困难。

扩展的表单 与Form事件类似,但是根据它是db / new实体还是调用不同的类型。我的意思是,您拥有定义编辑表单的FooType,BarType扩展了FooType,并将所有数据设置为字段。然后,您只需在控制器中选择要激发的表单类型即可。如果您有一个自定义主题(例如事件),这会很糟糕,但会给我带来太多的维护负担。

树枝 您可以创建自己的主题,也可以在基于每个字段的情况下使用value选项将数据默认设置。如果您希望保持模板干净并且可重用表单,那么没有什么可以阻止您将其包装到表单主题中的。例如

form_widget(form.foo, {attr: { value : default } });

JS 如果字段为空,则用JS函数填充表单很简单。例如,您可以使用占位符。但是,这是一个坏主意。

表单即服务 对于我所做的基于大型表单的项目之一,我创建了一个服务,该服务生成所有表单,进行所有处理等。这是因为表单要在多个环境中的多个控制器之间使用,而表单以相同的方式生成/处理,它们以不同的方式显示/交互(例如错误处理,重定向等)。这种方法的优点在于,您可以默认数据,执行所需的所有操作,一般性地处理错误等,并且都封装在一个地方。

结论 正如我所看到的,您会一次又一次遇到相同的问题-默认数据存放在哪里?

  • 如果将其存储在db / doctrine级别,如果不想每次都存储默认值,会发生什么?
  • 如果将其存储在实体级别,如果您想在其他地方重复使用该实体而又没有任何数据,会发生什么情况?
  • 如果将其存储在实体级别并添加新字段,是否要让以前的版本在编辑时具有该默认值?数据库中的默认设置也是如此...
  • 如果将其存储在表单级别,那么以后再维护代码时很明显吗?
  • 如果在构造函数中,如果您在多个地方使用表单会发生什么?
  • 如果您将其推向JS级别,则说明您已经走得太远了-数据不应该放在视图中,不必担心JS(而且我们忽略了兼容性,渲染错误等)
  • 如果像我一样在多个地方使用它,该服务将是很棒的选择,但是对于在一个站点上简单的添加/编辑表单来说,这是过分的...

为此,我每次都以不同的方式处理该问题。例如,在创建表单之前,可以轻松(逻辑上)在构造函数中设置注册表单的“新闻简报”选项。当我建立链接在一起的表单集合(例如,不同表单类型的单选按钮链接在一起)时,我使用了事件监听器。当我建立了一个更复杂的实体(例如,一个需要子对象或大量默认数据的实体)时,我就根据需要使用了一个函数(例如,“ getFactory”)来创建它。

我认为没有一种“正确”的方法,因为每次我有此要求时,它都会有所不同。

祝好运!我希望我能给您一些思考的东西,不要让您流连忘返;)


您能否详细介绍一下“生成所有表单的服务”的含义?我现在还在从事一个真正以表单为中心的项目,对它有不同的看法将非常棒。
user2268997 2014年

2
使用原则时,从数据库加载实体时不调用构造函数。
NDM

43

如果需要设置默认值并且您的表单与实体相关,则应使用以下方法:

// buildForm() method
public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder
    ...
    ->add(
        'myField',
        'text',
        array(
            'data' => isset($options['data']) ? $options['data']->getMyField() : 'my default value'
        )
    );
}

否则,myField始终将设置为默认值,而不是从实体获取值。


如果是数组而不是实体,则替换$options['data']->getMyField()$option['data']['myField']
ggg 2014年

3
我认为这是添加/更新的正确方法。但是我讨厌Symfony使其过于复杂。
Yarco '17

这是唯一的好答案。当我查看文档时,我不明白其他答案。empty_data:此选项确定当提交的值为空时字段将返回什么值。它没有设置初始值
Vincent Decaux


16

如果您的表单绑定到实体,则只需使用Construct方法在实体本身上设置默认值:

public function __construct()
{
    $this->field = 'default value';
}

即便如此,您的表单也可能有其他字段未映射到您的实体('mapped' => false)。使用setData(...)这些。
Dizzley 2013年

12

方法1(来自http://www.cranespud.com/blog/dead-simple-default-values-on-symfony2-forms/

只需在变量声明或构造函数中为您的实体设置默认值即可:

class Entity {
    private $color = '#0000FF';
    ...
}

要么

class Entity {
    private $color;

    public function __construct(){
         $this->color = '#0000FF';
         ...
    }
    ...
}

上面链接中的注释中的方法2,以及如何在Symfony2中为表单字段设置默认值的 Dmitriy的答案(不是公认的答案)

在使用FormBuilder添加字段时,将默认值添加到data属性,该值根据Dmitriy的答案改编而成。

请注意,这假定该属性在成为新实体(而不是现有实体)时将并且将仅具有 null值。

public function buildForm(FormBuilderInterface $builder, array $options) {
    $builder->add('color', 'text', array(
            'label' => 'Color:',
            'data' => (isset($options['data']) && $options['data']->getColor() !== null) ? $options['data']->getColor() : '#0000FF'
        )
    );
}

第一个有效(谢谢!),第二个无效(对我来说):$ options [“ data]始终被设置,因此默认值将永远不会使用。我仍然想知道解决方案编号1是否是预期的方式去做...
herrjeh42

您总是设置$ options ['data']是正确的。如果您不初始化实体字段,则可以在该字段上测试null。'data'=> $ options ['data']-> getColor()!== null吗?等等...假定null不是颜色字段的有效值,因此现有实体永远不会对该颜色字段具有null值。
crysallus

啊,愚蠢的我:我用'isset($ $ options ['data']-> getColor())'尝试了一下,但收到一条错误消息:“不允许在编写上下文时使用它”,忘记了我必须以不同的方式检查它:-)
herrjeh42

1
实际上,似乎确实有没有设置数据输入的情况。更安全地测试isset($ options ['data'])&& $ options ['data']-> getColor()!== null吗?...
crysallus

9

您可以为表单设置默认值,例如message

$defaultData = array('message' => 'Type your message here');
$form = $this->createFormBuilder($defaultData)
    ->add('name', 'text')
    ->add('email', 'email')
    ->add('message', 'textarea')
    ->add('send', 'submit')
    ->getForm();

如果您的表单已映射到实体,则可以这样进行操作(例如,默认用户名):

$user = new User();
$user->setUsername('John Doe');

$form = $this->createFormBuilder($user)
    ->add('username')
    ->getForm();

2
我更喜欢这种方法,特别是因为在大多数应用程序中,您都是在创建表单并传递该表单所处理的实体。
2014年

9

任何情况/方法的通用解决方案,主要是通过使用不带类的表单或当我们需要访问任何服务来设置默认值时:

// src/Form/Extension/DefaultFormTypeExtension.php

class DefaultFormTypeExtension extends AbstractTypeExtension
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        if (null !== $options['default']) {
            $builder->addEventListener(
                FormEvents::PRE_SET_DATA,
                function (FormEvent $event) use ($options) {
                    if (null === $event->getData()) {
                        $event->setData($options['default']);
                    }
                }
            );
        }
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefault('default', null);
    }

    public function getExtendedType()
    {
        return FormType::class;
    }
}

并注册表格扩展名:

app.form_type_extension:
    class: App\Form\Extension\DefaultFormTypeExtension
    tags:
        - { name: form.type_extension, extended_type: Symfony\Component\Form\Extension\Core\Type\FormType }

之后,我们可以default在任何表单字段中使用option:

$formBuilder->add('user', null, array('default' => $this->getUser()));
$formBuilder->add('foo', null, array('default' => 'bar'));

这应该被认为是最好的答案(最新的)
medunes '17

7

不要使用:

'data' => 'Default value'

在这里阅读:https : //symfony.com/doc/current/reference/forms/types/form.html#data

“数据选项在呈现时始终会覆盖从域数据(对象)获取的值。这意味着当表单编辑一个已保留的对象时,该对象的值也会被覆盖,从而在提交表单时会丢失其保留的值。”


使用以下内容:

可以说,在此示例中,您有一个Entity Foo,并且有一个字段“ active”(在此示例中为CheckBoxType,但是过程与其他所有类型相同),默认情况下要对其进行检查

在您的FooFormType类中添加:

...
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
...
public function buildForm( FormBuilderInterface $builder, array $options )
{
    ...

    $builder->add('active', CheckboxType::class, array(
        'label' => 'Active',
    ));

    $builder->addEventListener(
        FormEvents::PRE_SET_DATA,
        function(FormEvent $event){                 
            $foo = $event->getData();
            // Set Active to true (checked) if form is "create new" ($foo->active = null)
            if(is_null($foo->getActive())) $foo->setActive(true);
        }
   );
}
public function configureOptions( OptionsResolver $resolver )
{
    $resolver->setDefaults(array(
        'data_class' => 'AppBundle:Foo',
    ));
}

这是钱!!在默认值之前,使用表单事件监听器检查您的值。这应该是表单中默认值的可接受答案,因为它适用于“新建”操作和“编辑”操作。
tlorens

这是处理此问题的正确方法,应该是公认的答案。
贝蒂兹

如果使用条件/三进制,则开头提到的内容是不正确的。像这样:'data' => $data['myfield'] ?? 'Default value'
xarlymg89

6
->addEventListener(FormEvents::PRE_SET_DATA, function (FormEvent $event) {
     $form = $event->getForm(); 
     $data = $event->getData(); 

     if ($data == null) {
         $form->add('position', IntegerType::class, array('data' => 0));
     }

});

这是一个很好的解决方案。调用$event->setData()而不是读取字段可能会更好。
user2268997

5

我的解决方案:

$defaultvalue = $options['data']->getMyField();
$builder->add('myField', 'number', array(
            'data' => !empty($defaultvalue) ? $options['data']->getMyField() : 0
        )) ;

4

只是我了解问题所在。

您想根据实体中的数据调整构建表单的方式。如果正在创建实体,则使用一些默认值。如果实体存在,请使用数据库值。

就我个人而言,我认为@MolecularMans的解决方案是必经之路。我实际上将在构造函数或属性语句中设置默认值。但是您似乎不喜欢这种方法。

相反,您可以按照以下步骤操作:http : //symfony.com/doc/current/cookbook/form/dynamic_form_modification.html

您可以在表单类型上挂起一个侦听器,然后可以检查您的实体,并根据希望新建或现有的实体来相应地调整builder-> add语句。尽管您可以只在侦听器中对它们进行编码,但仍需要在某个地方指定默认值。或将它们传递给表单类型。

似乎需要做很多工作。最好仅将实体传递给表单并设置其默认值。


4

如果您使用的FormBuilder是Symfony 2.7中的表单,则还可以将初始数据传递给createFormBuilderControler 的方法。

$values = array(
    'name' => "Bob"
);

$formBuilder = $this->createFormBuilder($values);
$formBuilder->add('name', 'text');

3

通常,对于表单的初始默认值,我使用fixture。当然,这种方式不是最简单的,但非常舒适。

例:

class LoadSurgeonPlanData implements FixtureInterface
{
    public function load(ObjectManager $manager)
    {
        $surgeonPlan = new SurgeonPlan();

        $surgeonPlan->setName('Free trial');
        $surgeonPlan->setPrice(0);
        $surgeonPlan->setDelayWorkHours(0);
        $surgeonPlan->setSlug('free');

        $manager->persist($surgeonPlan);
        $manager->flush();        
    }   
}

但是,symfony类型字段具有选项数据

$builder->add('token', 'hidden', array(
    'data' => 'abcdef',
));

3

有一种非常简单的方法,您可以在此处设置默认值:

$defaults = array('sortby' => $sortby,'category' => $category,'page' => 1);

$form = $this->formfactory->createBuilder('form', $defaults)
->add('sortby','choice')
->add('category','choice')
->add('page','hidden')
->getForm();

3

如果您在创建表单中设置“数据”,则在编辑实体时不会修改此值。

我的解决方案是:

public function buildForm(FormBuilderInterface $builder, array $options) {
    // In my example, data is an associated array
    $data = $builder->getData();

    $builder->add('myfield', 'text', array(
     'label' => 'Field',
     'data' => array_key_exits('myfield', $data) ? $data['myfield'] : 'Default value',
    ));
}

再见


比接受的答案有用得多!如果您使用PHP7 +,则可以使用以下方法使其更加整洁:'data' => $data['myfield'] ?? 'Default value',
Boykodev

您在array_key_exists()函数中有错字
Deadpool

1

通过配置相应的实体来设置默认值。在将实体绑定为表单之前,将其颜色字段设置为“#0000FF”:

// controller action
$project = new Project();
$project->setColor('#0000FF');
$form = $this->createForm(new ProjectType(), $project);

这种方法有效,但缺点是每次使用表单类时都必须这样做,而且非常冗长(很多set语句)。由于表单组件非常优雅,因此必须包含其他内容。但是无论如何还是要感谢:-)
herrjeh42

在我看来,@ jamie0726是控制器的责任,即在对象是新对象或获取对象时设置其值。这样,您就可以在不同情况下以不同的行为使用该表单,例如,新颜色可能会因为用户具有经理或超级管理者角色而发生更改,并且由于这是一种业务逻辑,因此应由控制器或服务,而不是表格。因此,正如Cerad所说,我也更喜欢这种解决方案。您总是可以创建一个服务来设置这些默认值,然后在控制器中使用该服务使其保持DRY状态。
saamorim

这是我选择的解决方案,因为它符合我认为的逻辑。生成的控制器具有用于创建EDIT和CREATE表单的不同方法,这些是我为新实体设置默认/初始数据的地方。
alumi 2015年

1

如果该字段绑定到实体(是该实体的属性),则可以为其设置默认值。

一个例子:

public function getMyField() {
    if (is_null($this->MyField)) {
        $this->setMyField('my default value');
    }
    return $this->MyField;
}

1

我通常只为实体中的特定字段设置默认值:

/**
 * @var int
 * @ORM\Column(type="integer", nullable=true)
 */
protected $development_time = 0;

这将适用于新记录或仅更新现有记录。


'empty_data'使用回调在实体上允许构造函数参数时,这似乎不起作用。
NDM

1

正如Brian所问:

empty_data似乎仅在提交没有值的字段时将其设置为1。如果您希望在不存在任何值的情况下使表单默认为在输入中显示1,该怎么办?

您可以使用设置默认值 empty_value

$builder->add('myField', 'number', ['empty_value' => 'Default value'])

0

我通过在attr中添加解决了这个问题:

->add('projectDeliveringInDays', null, [
    'attr' => [
          'min'=>'1',
          'value'=>'1'
          ]
     ])
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.