上传的图片太大:出现循环引用

Upoaded image's too big : a circular reference occurs

我正在尝试使用 Symfony4 构建一个订阅表单,我认为它可以正常工作,但似乎当我尝试上传太大的个人资料图片时,我遇到了以下错误: 序列化 class "App\Entity\User" 的对象时检测到循环引用(配置限制:1)

但是我确实对 属性 profilePicture 设置了关于用户将尝试上传的文件的 maxSize 的限制,所以我不明白为什么会这样(我有所有其他错误显示良好)。

这是关于 属性 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;
    }
}

实体用户和存储有关用户的补充数据的实体用户配置文件之间存在一对一关系。

我希望它像显示所有其他类型的错误一样简单地显示有关文件大小的错误消息。 如果您需要我代码的其他部分,请告诉我。

事实证明,表单产生了错误,并且至少有一个错误内部有一个复杂的对象,这将递归引入了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);

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

附带说明:返回的状态代码(在您的情况下为 200)不正常,应该是 400 秒,因为请求产生错误,响应不应该是 200("OK").

*) 对于任何想知道如何注意的人:它通常需要 30 秒的所有标准执行时间,直到发生超时。如果标准执行时间设置为无限制,则整个计算机可能会死机,因为它会缓慢(或非常快)耗尽所有内存以准备无限长的答案。这几乎总是发生在 var_dumping 或 print_ring 复杂对象时,这些对象在它们的引用中(可能有多层深度)引用复杂对象或彼此引用,创建一个无限循环,因为序列化过程遵循更深层次的引用对象。 dump 以及 dd(symfony 调试输出)通常会更好地执行 way(避免递归),从而允许检查对象。 - 但是,dddump 都不应在生产中使用,而且调试组件在生产环境中默认禁用。