如何仅在表单有效时将Symfony中的表单数据映射到对象?



想象Symfony中的示例表单:

public function buildForm(FormBuilderInterface $builder)
{
$builder
->add('email', EmailType::class, [
'constraints' => 
new NotBlank(),
new IsUnique(),
],
])
->add('password', PasswordType::class, [
'constraints' => 
new NotBlank(),
new IsStrongEnough(),
],
])
}

现在,当我提交表格并确保其有效时,我希望$form->getData()返回名为CreateAccountCommand的 DTO:

final class CreateAccountCommand
{
private $email;
private $password;
public function __construct(string $email, string $password)
{
$this->email = $email;
$this->password = $password;
}
public function getEmail(): string
{
return $this->email;
}
public function getPassword(): string
{
return $this->password;
}
}

示例控制器:

$form = $this->formFactory->create(CreateAccountForm::class);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->commandBus->dispatch($form->getData());
return new JsonResponse([]);
}

我不能直接使用data_class来使用这个类,因为表单显然希望模型具有允许空值的setter。表单本身运行良好,验证也是如此。

我尝试使用数据映射器方法,但在验证之前调用了mapFormsToData方法。

这可能吗?还是我应该将数据作为数组获取并在表单之外创建对象?

以下是我如何使用Symfony 4.1处理表单

假设您想要一个简单的添加表单

表格

class CreateAccountForm extends AbstractType
{
public function buildForm(FormBuilderInterface $builder)
{
//same method than yours
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array('data_class' => 'AppEntityCreateAccountCommand'));
}
}

控制器

public function add(Request $request)
{
$createAccountCommand = new CreateAccountCommand();
//The object is "injected" to the form, that way, it's mapped when submitted
$form = $this->get('form.factory')->create(CreateAccountForm::class, $createAccountCommand);
//Form was submitted
if ($request->isMethod('POST') && $form->handleRequest($request)->isValid())
{
//no need to getData(), the object $createAccountCommand is directly mapped to the form and can be used as is
$em = $this->getDoctrine()->getManager();
//persist, convert to json, or whatever
$em->persist($createAccountCommand);
$em->flush();
return ($this->redirectToRoute('someRoute'));
}
//form not submitted, or has been submit with errors (isValid() == false)
return ($this->render('account/add.html.twig',
array('form' => $form->createView())));
}

有一种方法,但对于您想要做的事情来说太复杂了。 为此,需要使用数据映射器。

我知道这不是最好的解决方案,但最简单的解决方案是(在我看来(将资源库添加到您的模型类并允许空值 (SOLUTION1(。另一种解决方案是为表单使用另一个对象,并在提交后构建命令(并且您无需修改命令 - SOLUTION2(。

public function handleForm(Request $request)
{
/// SOLUTION 1
$form = $this->createForm(RegisterFormType::class, new CreateAccountCommand());
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$command = $form->getData();
// do whatever you want
}
// ... 
// SOLUTION 2
$obj = new stdClass();
$obj->login = '';
$obj->password = '';
$form = $this->createForm(LoginFormType::class, $obj);
$form->handleRequest($request);
if($form->isSubmitted() && $form->isValid()) {
$data = $form->getData();
$command = new CreateAccountCommand($data->login, $data->password);
// do whatever you want
}
}

使用此模型:

final class CreateAccountCommand
{
//// ... 
/**
* @param string $email
*/
public function setEmail(string $email): void
{
$this->email = $email;
}
/**
* @param string $password
*/
public function setPassword(string $password): void
{
$this->password = $password;
}
}

最新更新