浮夸的图片太大:出现了循环引用

时间:2019-10-22 07:56:45

标签: forms file-upload symfony4 circular-reference

我正在尝试使用Symfony4构建订阅表单,但我认为它是可行的,但是当我尝试上传太大的个人资料图片时,出现以下错误: 序列化类“ App \ Entity \ User”的对象时检测到循环引用(配置的限制:1)

但是我确实在属性profilePicture上设置了关于文件的maxSize的约束,用户将尝试上传该文件,因此我不明白为什么会发生这种情况(所有其他错误都显示得很好)。 / p>

这是关于属性profilePicture的代码的一部分:

/**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank(message="Merci de bien vouloir sélectionner une image")
     * @Assert\Image(
     *     minRatio="1",
     *     maxRatio="1",
     *     minWidth="250",
     *     minHeight="250",
     *     minRatioMessage="Votre photo de profil doit avoir un ratio de 1:1",
     *     maxRatioMessage="Votre photo de profil doit avoir un ratio de 1:1",
     *     minWidthMessage="Votre image doit faire minimum {{ minWidth }} de large",
     *     maxWidthMessage="Votre image doit faire minimun {{ minHeight }} de hauteur", 
     *     maxSize="2M",
     *     maxSizeMessage="Votre image ne peut pas fait plus de 2M")
     */
    private $profilePicture;

处理订阅表单的HomeController:

/**
     * @Route("/", name="home")
     */
    public function index(Request $request, UserPasswordEncoderInterface $passwordEncoder): Response
    {
        //To Manage registration
        $user = new User();
        $form = $this->createForm(RegistrationFormType::class, $user);
        $form->handleRequest($request);

        if ($form->isSubmitted() && !$form->isValid()) {
            return $this->json([
                "status" => "error(s)",
                "errors" => $form->getErrors(true, true)
            ], 200);
        }
        if ($form->isSubmitted() && $form->isValid()) {
            // move the file from the temp folder
            $fileUploader = new FileUploader($this->getParameter('profile_pictures_directory'));
            $profilePicture = $form['userProfile']['profilePicture']->getData();
            if ($profilePicture) {
                $profilePictureFilename = $fileUploader->upload($profilePicture);
                $user->getUserProfile()->setProfilePicture($profilePictureFilename);
            }
            // encode the plain password
            $user->setPassword(
                $passwordEncoder->encodePassword(
                    $user,
                    $form->get('plainPassword')->getData()
                )
            );
            $user->setCreationDate(new \DateTime());

            $entityManager = $this->getDoctrine()->getManager();
            $entityManager->persist($user);
            $entityManager->flush();

            // do anything else you need here, like send an email

            return $this->json(["status" => "success"]);
        }

        return $this->render('home/index.html.twig', [
            'registrationForm' => $form->createView(),
        ]);
    }

FileUploader服务:

<?php
namespace App\Service;

use Symfony\Component\HttpFoundation\File\Exception\FileException;
use Symfony\Component\HttpFoundation\File\UploadedFile;

class FileUploader
{
    private $targetDirectory;

    public function __construct($targetDirectory)
    {
        $this->targetDirectory = $targetDirectory;
    }

    public function upload(UploadedFile $file)
    {
        $originalFilename = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        $safeFilename = transliterator_transliterate('Any-Latin; Latin-ASCII; [^A-Za-z0-9_] remove; Lower()', $originalFilename);
        $fileName = $safeFilename.'-'.uniqid().'.'.$file->guessExtension();
        try {
            $file->move($this->getTargetDirectory(), $fileName);
        } catch (FileException $e) {

        }

        return $fileName;
    }

    public function getTargetDirectory()
    {
        return $this->targetDirectory;
    }
}

实体User和实体UserProfile之间存在一个OneToOne关系,其中存储了有关该用户的补充数据。

我想像所有其他类型的错误一样简单地显示有关文件大小的错误消息。 让我知道您是否需要代码的其他部分。

1 个答案:

答案 0 :(得分:1)

事实证明,表单会产生错误,并且至少其中一个错误包含一个复杂的对象,这将递归引入json编码过程*:

        return $this->json([
            "status" => "error(s)",
            "errors" => $form->getErrors(true, true)
        ], 200);

为防止这种情况发生,最好准备要显示的错误:

$formerrors = [];
foreach($form->getErrors(true, true) as $error) {
    $fieldname = ($origin = $error->getOrigin()) ? $origin->getName() : null;
    if($fieldname) {
        $formerrors[$fieldname] = $error->getMessage();
    } else {
        $formerrors[] = $error->getMessage();
}
return $this->json([
    "status" => "error(s)",
    "errors" => $formerrors,
], 200);

由于错误可以是 no 的起源,而不能是表单本身,因此循环可能中的条件是必需的。另外:对于深层嵌套的表单,可能有必要改进此方法。

请注意:返回的状态码(在您的情况下为200不好,应该是400 s,因为请求产生了错误,因此响应不应为200(“ OK”) )。

*),供任何想知道如何注意的人使用:通常需要30s的标准执行时间,直到超时为止。如果将标准执行时间设置为无限制,则整个计算机可能会冻结,因为它会缓慢(或很快)耗尽所有内存以准备无限长的答案。当var_dumpprint_r复杂对象在其引用(可能是多层)中引用复杂对象或彼此引用时,这种情况几乎总是会发生,当序列化过程遵循更深层次的引用时,会形成无限循环对象。 dumpdd(symfony调试输出)通常会更好地执行 way (避免递归),从而可以检查对象。 -但是,dddump都不能在生产中使用,并且默认情况下,prod env中禁用了调试组件。