Symfony4,如何正确处理缺少的表单字段? (在$ this-> propertyAccessor-> setValue中无例外)

时间:2019-02-21 21:52:38

标签: symfony symfony4

我有一个Task实体,带有两个必填且不可为空的字段:

  • title
  • dueDatetime

和表格以创建任务。外部脚本通过POSTapplication/x-www-form-urlencoded调用该表单(因此没有json或任何花哨的内容),因此我使用标准的symfony来处理。

问题是我无法控制脚本,并且如果脚本忘记了参数之一,则在我有时间检查表单是否有效之前,symfony4将直接在handleRequest步骤中引发异常或不。导致响应500变丑。

我的问题:如何避免这种情况?对我来说,最好的办法就是像以前一样继续使用“ form-> isValid()”,但是如果还有其他标准的方法可以解决这个问题,那么也可以。

注意:最好是不必将实体的设置器接受为空值

我得到的例外情况:

  

类型为“ DateTimeInterface”的预期参数,给出了“ NULL”。
  在vendor / symfony / property-acces /PropertyAccessor.php::throwInvalidArgumentException中(第153行)
  在vendor / symfony / form / Extension / Core / DataMapper / PropertyPathMapper.php-> setValue(第85行)中
  在vendor / symfony / form / Form.php-> mapFormsToData中(第622行)
  在vendor / symfony / form / Extension / HttpFoundation / HttpFoundationRequestHandler.php-> submit(第108行)中
  在vendor / symfony / form / Form.php-> handleRequest(第492行)中

产生错误的卷曲:

curl -d 'title=foo' http://127.0.0.1:8080/users/api/tasks

代码:

实体:

class Task
{


    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="bigint")
     */
    private $id;

    /**
     * @Assert\NotNull()
     * @Assert\NotBlank()
     * @ORM\Column(type="string", length=500)
     */
    private $title;
    /**
     *
     * @ORM\Column(type="datetimetz")
     */
    private $dueDatetime;

    public function getDueDatetime(): ?\DateTimeInterface
    {
        return $this->dueDatetime;
    }

    public function setDueDatetime(\DateTimeInterface $dueDatetime): self
    {
        $this->dueDatetime = $dueDatetime;
        return $this;
    }

    public function setTitle($title)
    {
        $this->title = $title;
        return $this;
    }

    public function getTitle()
    {
        return $this->title;
    }

}

表格

class TaskType extends AbstractType                                                                                     
{                                                                                                                       
    public function buildForm(FormBuilderInterface $builder, array $options)                                            
    {                                                                                                                   
        $builder                                                  
            ->add('title')                                                                                                                                                   
            ->add('dueDatetime')
        ;
    }
    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(['data_class' => Task::class]);
    }
}

控制器:

class TaskController extends AbstractController
{
   /**
     * @Route(
     *   "/users/api/tasks",
     *   methods={"POST"},
     *   name="user_api_create_task"
     * )
     */
    public function apiCreateTask(Request $request)
    {
        $task = new Task();;

        // the use of createNamed with an empty string is just so that
        // the external scripts don't have to know about symfony's convention
        $formFactory = $this->container->get('form.factory');
        $form = $formFactory->createNamed(
            '',
            TaskType::class,
            $task
        );
        $form->handleRequest($request); // <-- this throw exception

        // but this code should handle this no ? 
        if (!$form->isSubmitted() || !$form->isValid()) {
            return new JsonResponse([], 422);
        }
        $entityManager = $this->getDoctrine()->getManager();
        $entityManager->persist($task);
        $entityManager->flush();


        return new JsonResponse();
    }
}

2 个答案:

答案 0 :(得分:0)

至少有两种方法可以解决此问题。 您必须通过两种方式将@Assert\NotNull()添加到dueDatetime属性。

1-您可以尝试/捕获handleRequest调用的异常。
[edit]这会中断流程,不好。

2-您可以使setter setDueDatetime(\DateTimeInterface $dueDatetime = null)为可空值。如果选择此选项,请确保始终在DB中插入/更新之前验证您的实体,否则会出现SQL错误。

在两种情况下,它将由验证器isValid()处理,并且您的前端会有一个不错的错误。

答案 1 :(得分:0)

您需要在方法setDueDatetime中允许可为空的参数(带有“?”)

public function setDueDatetime(?\DateTimeInterface $dueDatetime): self
{
    $this->dueDatetime = $dueDatetime;
    return $this;
}