如何使用没有数据类的表单
在大多数情况下,表单会绑定到一个对象,表单的字段会在该对象的属性上获取和存储数据。这是关于表单的主要文章所讲述的内容。
但有时,您可能希望使用没有类的表单,并返回提交数据的数组。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
}
}
默认情况下,表单实际上假定您要使用数据数组,而不是对象。您可以通过两种方式更改此行为,并将表单绑定到对象
- 在创建表单时传递一个对象(作为
createFormBuilder()
的第一个参数或createForm()
的第二个参数); - 在您的表单上声明
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
约束进行验证,除非您禁用验证。
警告
当表单仅部分提交时(例如,在 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();