跳到内容

如何使用没有数据类的表单

编辑此页

在大多数情况下,表单会绑定到一个对象,表单的字段会在该对象的属性上获取和存储数据。这是关于表单的主要文章所讲述的内容。

但有时,您可能希望使用没有类的表单,并返回提交数据的数组。getData() 方法允许您完全做到这一点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// src/Controller/ContactController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
// ...

class ContactController extends AbstractController
{
    public function contact(Request $request): Response
    {
        $defaultData = ['message' => 'Type your message here'];
        $form = $this->createFormBuilder($defaultData)
            ->add('name', TextType::class)
            ->add('email', EmailType::class)
            ->add('message', TextareaType::class)
            ->add('send', SubmitType::class)
            ->getForm();

        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            // data is an array with "name", "email", and "message" keys
            $data = $form->getData();
        }

        // ... render the form
    }
}

默认情况下,表单实际上假定您要使用数据数组,而不是对象。您可以通过两种方式更改此行为,并将表单绑定到对象

  1. 在创建表单时传递一个对象(作为 createFormBuilder() 的第一个参数或 createForm() 的第二个参数);
  2. 在您的表单上声明 data_class 选项。

如果您没有执行上述任一操作,则表单将以数组形式返回数据。在此示例中,由于 $defaultData 不是对象(并且未设置 data_class 选项),$form->getData() 最终返回一个数组。

提示

您还可以通过请求对象直接访问 POST 值(在本例中为“name”),如下所示

1
$request->getPayload()->get('name');

但是,请注意,在大多数情况下,使用 getData() 方法是更好的选择,因为它返回的数据(通常是对象)已经过 Form 组件的转换。

添加验证

唯一缺失的部分是验证。通常,当您调用 $form->handleRequest($request) 时,对象会通过读取您应用于该类的约束进行验证。如果您的表单映射到一个对象(即您正在使用 data_class 选项或将对象传递给表单),这几乎总是您想要使用的方法。有关更多详细信息,请参阅 验证

但是,如果表单未映射到对象,并且您希望检索提交数据的数组,那么如何为表单的数据添加约束?

字段级别的约束

一种可能性是自行设置约束,并将它们附加到各个字段。这篇验证文章更详细地介绍了总体方法,但这里有一个简短的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;

public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $builder
        ->add('firstName', TextType::class, [
            'constraints' => new Length(['min' => 3]),
        ])
        ->add('lastName', TextType::class, [
            'constraints' => [
                new NotBlank(),
                new Length(['min' => 3]),
            ],
        ])
    ;
}

提示

如果您正在使用验证组,则需要在创建表单时引用 Default 组,或者在您添加的约束上设置正确的组

1
new NotBlank(['groups' => ['create', 'update']]);

提示

如果表单未映射到对象,则提交数据数组中的每个对象都将使用 Symfony\Component\Validator\Constraints\Valid 约束进行验证,除非您禁用验证

警告

当表单仅部分提交时(例如,在 HTTP PATCH 请求中),只会评估来自已提交表单字段的约束。

类级别的约束

另一种可能性是在类级别添加约束。这可以通过在 configureOptions() 方法中设置 constraints 选项来完成

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;

public function buildForm(FormBuilderInterface $builder, array $options): void
{
    $builder
        ->add('firstName', TextType::class)
        ->add('lastName', TextType::class);
}

public function configureOptions(OptionsResolver $resolver): void
{
    $resolver->setDefaults([
        'data_class' => null,
        'constraints' => new Collection([
            'firstName' => new Length(['min' => 3]),
            'lastName' => [
                new NotBlank(),
                new Length(['min' => 3]),
            ],
        ]),
    ]);
}

这意味着您也可以在控制器中使用 createFormBuilder() 方法来执行此操作

1
2
3
4
5
6
7
8
9
10
11
12
$form = $this->createFormBuilder($defaultData, [
        'constraints' => [
            'firstName' => new Length(['min' => 3]),
            'lastName' => [
                new NotBlank(),
                new Length(['min' => 3]),
            ],
        ],
    ])
    ->add('firstName', TextType::class)
    ->add('lastName', TextType::class)
    ->getForm();
这项工作,包括代码示例,根据 Creative Commons BY-SA 3.0 许可获得许可。
目录
    版本