使用映射的 false 和多个 true 验证 symfony 4 formfield 文件类型

Validate symfony 4 formfield filetype with mapped false and multiple true

我有一个关于滑雪板技巧的项目。在我的项目中,我得到了一个实体 Trick,它的 itslef 有一个属性 "illustrations",它是另一个实体的集合:Illustration。我正在尝试做一个表单 TrickType,用户可以在其中一次加载许多插图(图像:png、jpeg、jpg、gif)。然后控制器保存文件,并创建几个插图实体,文件的名称和路径作为 "url" 属性。

因此,TrickType 无法直接管理插图实体,因为我必须在表单中使用 FileType 字段,这样才能加载文件,而 filetype 当然不会直接创建实体。这就是为什么我的 tricktype 表单中的文件类型字段必须具有以下选项:

我的实体、表单和控制器已正确完成:如果我不对文件进行任何验证,或者如果我进行了验证,但只对一个文件进行验证,则一切正常。但我必须确保每个文件都是真正的图像。

这是我尝试这样做的:

1 - 直接在 TrickType 中进行约束:

->add('illustrations', FileType::class, [
                "label" => "Illustrations (optionnel)",
                "multiple" => true,
                "mapped" => false,
                "required" => false,
                "constraints" => [
                    new File([
                        "maxSize" => "10M",
                        "mimeTypes" => [
                            "image/png",
                            "image/jpg",
                            "image/jpeg",
                            "image/gif"
                        ],
                        "mimeTypesMessage" => "Veuillez envoyer une image au format png, jpg, jpeg ou gif, de 10 mégas octets maximum"
                    ])
                ]
            ])

问题:约束尝试检查字段,它是一个集合而不是一个文件。所以我得到了错误 "this value should be of type string"

2 - 形式上没有约束,但在实体中

注意:此解决方案和以下解决方案不会阻止保存错误的文件,因为它只涉及实体,不​​涉及文件。所以即使它有效,它也只是防止从数据库中的 url 中找到错误的文件并放入网站,但它无论如何都不是一个很好的解决方案

插图实体中:

/**
     * @ORM\Column(type="string", length=255)
     * @Assert\Regex("/((.jpg)|(.jpeg)|(.png)|(.gif))$/")
     */
    private $url;

在 Trick 实体中,尝试了 2 件事:

/**
     * @ORM\OneToMany(targetEntity="App\Entity\Illustration", mappedBy="trick")
     * @Assert\All({
     *      @Assert\Valid
     * })
     */
    private $illustrations;

error : "The constraint Valid cannot be nested inside constraint Symfony\Component\Validator\Constraints\All"

第二次尝试技巧:

/**
     * @ORM\OneToMany(targetEntity="App\Entity\Illustration", mappedBy="trick")
     * @Assert\Valid
     */
    private $illustrations;

没有错误,但无论发生什么形式都被认为是有效的(我可以添加任何类型的文件,symfony 不会阻止我)

3 - none 我之前所做的,但在 Trick 实体中回调

/**
     * @Assert\Callback
     */
    public function checkIllustrations(ExecutionContextInterface $context, $payload)
    {
        $forbidenExtensions = false;

        foreach ($this->illustrations as $illustration) {
            $url = $illustration->getUrl();
            if (! preg_match('/((.jpg)|(.jpeg)|(.png)|(.gif))$/', $url))
                $forbidenExtensions = true;
        }

        if ($forbidenExtensions)
        {
            $context->buildViolation("L'un des fichiers semble ne pas être une image. Seuls les extensions jpg, jpeg, png et gif sont acceptés.")
                    ->atPath("illustrations")
                    ->addViolation();
        }
    }

这与之前的情况一样,当我只使用 Valid(不在 All 约束内)时没有做任何事情。就像什么都不勾选一样

添加

dump($this->illustrations);
die();

在我的回调开始时给我一个结果:一个空数组集合。当然,我会发送一些文件。

所以,回调被执行了,但是没有插图。

这让我想知道是否在我尝试提交表单时直接执行了回调(所以空插图是正常的:控制器创建之前没有插图)

有关信息,这是我在控制器中处理表单提交的方法:

    /**
     * @Route("/adding-trick", name="adding_trick")
     * @IsGranted("ROLE_USER")
     */
    public function addingTrick(Request $request, ObjectManager $manager)
    {
        $trick = new Trick();

        $form = $this->createForm(TrickType::class, $trick);
        $form->handleRequest($request);

        if ($form->isSubmitted() && $form->isValid()) {
            $trick->setEditeur($this->getUser());

            $illustrations = $form['illustrations']->getData();

            if($illustrations)
            {
                foreach ($illustrations as $illustrationFile) {
                    $folder = "illustrations";
                    $extension = $illustrationFile->guessExtension();
                    if(!$extension)
                        $extension = "bin";
                    $illustrationName = rand(1, 999999999);

                    $illustrationFile->move($folder, $illustrationName . "." . $extension);

                    $illustration = new Illustration();

                    $illustration->setUrl("/" . $folder . "/" . $illustrationName . "." . $extension)
                                 ->setAlt("une illustration de la figure " . $trick->getNom())
                                 ->setTrick($trick);

                    $manager->persist($illustration);

                    $figure->addIllustration($illustration);
                }
            }

            // some code for other fields

            $manager->persist($figure);
            $manager->flush();

            $this->addFlash("success", "Figure ajoutée avec succès");

            return $this->redirectToRoute("trick_display", [
                "slug" => $trick->getSlug()
            ]);
        }

        return $this->render('handlingTricks/addingTrick.html.twig', [
            "form" => $form->createView()
        ]);
    }

如果有人知道我要做什么?

谢谢!

jakumi 在我的第一条消息下方的评论中给出了解决方案。这些是我的更改:

与第一次尝试一样,但有修改(新的全部包含新文件):

->add('illustrations', FileType::class, [
                "label" => "Illustrations (optionnel)",
                "multiple" => true,
                "mapped" => false,
                "required" => false,
                "constraints" => [
                    new All([
                        new File([
                            "maxSize" => "10M",
                            "mimeTypes" => [
                                "image/png",
                                "image/jpg",
                                "image/jpeg",
                                "image/gif"
                            ],
                            "mimeTypesMessage" => "Veuillez envoyer une image au format png, jpg, jpeg ou gif, de 10 mégas octets maximum"
                        ])
                    ])
                ]
            ])