Symfony 3 - Сериализация файла не допускается - PullRequest
1 голос
/ 17 апреля 2019

Я работаю над сайтом, который позволяет пользователям загружать пакеты.

У меня есть объект Packages, который содержит атрибуты (заголовок, комментарий, ...) и атрибуты файла.Эти файлы загружаются благодаря VichUploaderBundle.

У меня также есть две таблицы пользователей.Один для тех, кто подключается к сайту локально (форма входа на сайт) и аутентификация CAS.

Когда я аутентифицируюсь в CAS и хочу получить доступ к странице, представляющей пакеты для загрузки, я сталкиваюсь с этой ошибкой:

Сериализация 'Symfony \ Component \ HttpFoundation \ File \ File' не разрешена

Тем не менее, когда я подключаюсь локально, такой проблемы не возникает.Я не понимаю, почему у меня возникает эта ошибка.

Это мой код:

Аутентификация CAS: успех:

/**
     * Traitement personnalisé après récupération du token
     * 
     * Il est possible d'enrichir le token (attributs...) ou d'effectuer des contrôles supplémentaire
     * 
     * @param $token 
     *      Token d'authification généré
     * 
     * @return null
     */
    public function onSuccess($token){

        $mail = $this->ai->getMail();
        $nomComplet = $this->ai->getCompletName();
        $rne = $this->ai->getRne();

        $token->setAttribute('mail', $mail);
        $token->setAttribute('nomComplet', $nomComplet);
        $token->setAttribute('rne', $rne);   
        $token->setAttribute('typeAuth','cas');

        $user = $this->checkBDD($mail); //I retrieve the user object

        $token->setAttribute('user',$user);


    }

Объект Userразмещается в качестве атрибута в токене.

Он переходит к своему профилю, который должен содержать его информацию, а также к таблице, представляющей пакеты, которые он уже скачал.

/**
 * @Route ("/profile", name="user_profile")
 */
public function profileAction()
{
    $token = $this->get('security.token_storage')->getToken();
    //dump($token->getAttribute('nomComplet'));
    $user = $token->getAttribute('user');


    return $this->render('@Pages/cas/profile.html.twig');
}

Профиль.html.twig:

{% extends "base.html.twig" %}
{% block body %}

{% set user = app.getToken().getAttribute('user') %}
{% dump(user) %}

{% dump(app.getToken().getAttribute('nomComplet')) %}
<div class="container">
    <h1><u>{{ user.mail }}</u></h1><br/>

    <h2>Profil</h2>

    <br/>

    <table class="table">
        <tbody>
            <tr>
                <th scope="row">Nom d'utilisateur</th>
                <td>{{app.user.username}}</td>
            </tr>
            <tr>
                <th scope="row">Email</th>
                <td>{{user.mail}}</td>
            </tr>
            <tr>
                <th scope="row">Téléchargements restants</th>
                <td>4</td>
            </tr>
        </tbody>
    </table>

    <br/><br/><br/>

    <h3> Liste des packages téléchargés </h3> <br/>
    <table class="table table-stripped">
        <thead>
            <tr>
                <th>Titre</th>
                <th>Package</th>
                <th>Notice</th>
                <th>Commentaire</th>
            </tr>
        </thead>
        <tbody>
                {% for unPackage in user.packages %}
            <tr>
                <td> {{unPackage.titre}} </td>
                <td> {{unPackage.urlPaquet}} </td>
                <td> {{unPackage.urlNotice}} </td>
                <td> {{unPackage.commentaire}} </td>
            </tr>
                {% endfor %}
        </tbody>
    </table>

    <a href="{{path('connexion_index')}}" class="btn btn-primary">Retour à l'accueil</a>
    <a href="{{ path('deconnexion') }}" class="btn btn-primary">Déconnexion</a><br/><br/><br/><br/>
    </div>

в ветке, мы извлекаем атрибут User, который был в токене, и отображаем его информацию, включая его пакеты.(У пользователя есть атрибут packages, который является ArrayCollection и связан в ManyToMany с сущностью Package)

Сущность My User:

<?php

namespace Site\PagesBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Site\PagesBundle\Security\Traits\traitUser;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

/**
 * UserCas
 *
 * @ORM\Table(name="user_cas")
 * @ORM\Entity(repositoryClass="Site\PagesBundle\Repository\UserCasRepository")
 * @UniqueEntity("mail")
 */
class UserCas
{

    use traitUser;


    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var int
     *
     * @ORM\Column(name="nbTelechargementsAuto", type="integer", nullable=true)
     */
    private $nbTelechargementsAuto;

    /**
     * @var bool
     *
     * @ORM\Column(name="enabled", type="boolean")
     */
    private $enabled;


    /**
     * @ORM\Column(name="mail", type="string")
     */
    private $mail;

    /**  
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="Paquet")  
     * @ORM\JoinTable(name="paquetsDDLUserCas") 
     * @ORM\JoinColumn(nullable=false)
     */  
    private $packages;

    /**
     * Constructor
     */
    public function __construct()
    {
        $this->packages = new ArrayCollection();
        $this->setEnabled(true);

    }




    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }


    /**
     * @return string
     */
    public function getMail()
    {
        return $this->mail;
    }

    public function setMail($mail)
    {
        $this->mail = $mail;
    }


    /**
     * Set enabled
     *
     * @param boolean $enabled
     *
     * @return UserCas
     */
    public function setEnabled($enabled)
    {
        $this->enabled = $enabled;

        return $this;
    }

    public function isEnabled()
    {
        return $this->enabled;
    }

}

MyПакетная сущность:

<?php

namespace Site\PagesBundle\Entity;

use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
use Site\PagesBundle\Entity\Paquet;
use Site\PagesBundle\Entity\TypeUser;
use Symfony\Component\HttpFoundation\File\File;
use Doctrine\Common\Collections\ArrayCollection;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Paquet
 *
 * @ORM\Table(name="paquet")
 * @ORM\Entity(repositoryClass="Site\PagesBundle\Repository\PaquetRepository")
 * @Vich\Uploadable
 */
class Paquet
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;


    /**  
     * @var \Doctrine\Common\Collections\Collection
     * @ORM\ManyToMany(targetEntity="TypeUser")  
     * @ORM\JoinTable(name="Packages_des_TypesUser") 
     * @ORM\JoinColumn(nullable=false)
     */  
    private $typeUser;

    public function __construct()
    {
        $this->typeUser = new ArrayCollection();
    }

    /** 
     * Get TypeUser 
     * 
     * @return Site\PagesBundle\Entity\TypeUser 
     */ 
    public function getTypeUser() 
    { 
        return $this->typeUser; 
    }

    public function deleteTypeFromTypesUser(TypeUser $type)
    {
        $this->typeUser->removeElement($type);
    }



    /**
     * Set typeUser
     *
     * @param Site\PagesBundle\Entity\TypeUser $typeUser
     *
     * @return Paquet
     */
    public function setTypeUser(Site\PagesBundle\Entity\TypeUser $typeUser)
    {
        $this->typeUser = $typeUser;

        return $this;
    }


    /**
     * @var string
     *
     * @ORM\Column(name="titre", type="string", length=255)
     * @Assert\Length(min=5, max=255, minMessage="Le titre doit comporter au minimum 5 caractères")
     */
    private $titre;

    /**
     * @var string
     *
     * @ORM\Column(name="urlPaquet", type="string", length=255)
     */
    private $urlPaquet;

    /**
     * @Vich\UploadableField(mapping="paquet", fileNameProperty="urlPaquet")
     * @var File
     */
    private $paquetFile;

    /**
     * @ORM\Column(type="datetime")
     *
     * @var \DateTime
    */
    private $updatedAt;

    /**
 * @param File|UploadedFile $unPaquetFile
 *
 * @return Paquet
*/
public function setPaquetFile(File $unPaquetFile = null)
{
    $this->paquetFile = $unPaquetFile;

    if ($unPaquetFile) 
    {
        $this->updatedAt = new \DateTimeImmutable();
    }


    return $this;
}

    /**
     * Set updatedAt
     *
     * @param \DateTime $updatedAt
     *
     * @return Paquet
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updatedAt = $updatedAt;

        return $this;
    }

    /**
     * Get updatedAt
     *
     * @return \DateTime
     */
    public function getUpdatedAt()
    {
        return $this->updatedAt;
    }

/**
 * @return File|null
 */
public function getPaquetFile()
{
    return $this->paquetFile;
}


    /**
     * @var string
     *
     * @ORM\Column(name="urlNotice", type="string", length=255,nullable=true)
     */
    private $urlNotice;

    /**
     * @Vich\UploadableField(mapping="notice", fileNameProperty="urlNotice",nullable=true)
     * @var File
     */
    private $noticeFile;

    /**
     * @var string
     *
     * @ORM\Column(name="commentaire", type="text")
     */
    private $commentaire;


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set titre
     *
     * @param string $titre
     *
     * @return Paquet
     */
    public function setTitre($titre)
    {
        $this->titre = $titre;

        return $this;
    }

    /**
     * Get titre
     *
     * @return string
     */
    public function getTitre()
    {
        return $this->titre;
    }

    /**
     * Set urlPaquet
     *
     * @param string $urlPaquet
     *
     * @return Paquet
     */
    public function setUrlPaquet($urlPaquet)
    {
        $this->urlPaquet = $urlPaquet;

        return $this;
    }

    /**
     * Get urlPaquet
     *
     * @return string|null
     */
    public function getUrlPaquet()
    {
        return $this->urlPaquet;
    }

    /**
     * @return File|null
     */
    public function getNoticeFile()
    {
        return $this->noticeFile;
    }

        /**
     * @param File|UploadedFile $uneNoticeFile
     *
     * @return Paquet
    */
    public function setNoticeFile(File $uneNoticeFile = null)
    {
        $this->noticeFile = $uneNoticeFile;

        if ($uneNoticeFile) 
        {
            $this->updatedAt = new \DateTimeImmutable();
        }


        return $this;
}

    /**
     * Set urlNotice
     *
     * @param string $urlNotice
     *
     * @return Paquet
     */
    public function setUrlNotice($urlNotice)
    {
        $this->urlNotice = $urlNotice;

        return $this;
    }

    /**
     * Get urlNotice
     *
     * @return string
     */
    public function getUrlNotice()
    {
        return $this->urlNotice;
    }

    /**
     * Set commentaire
     *
     * @param string $commentaire
     *
     * @return Paquet
     */
    public function setCommentaire($commentaire)
    {
        $this->commentaire = $commentaire;

        return $this;
    }

    /**
     * Get commentaire
     *
     * @return string
     */
    public function getCommentaire()
    {
        return $this->commentaire;
    }
}

Вот и все, я думаю, я положил всю необходимую информацию.И я повторяю, что когда я аутентифицируюсь локально (а не в CAS), у меня нет этой проблемы.И мне не нужно было бы сериализовать какой-либо файл как обычно, верно?


EDIT:

В Paquet.php я реализовал \ Serializable и два метода:

  /** @see \Serializable::serialize() */
  public function serialize()
  {
      return serialize(array(
          $this->id,
          $this->noticeFile,
          $this->paquetFile,

      ));
  }

  /** @see \Serializable::unserialize() */
  public function unserialize($serialized)
  {
      list (
          $this->id,
          $this->noticeFile,
          $this->paquetFile,
      ) = unserialize($serialized, array('allowed_classes' => false));
  }

Та же ошибка, мои методы хороши?


РЕДАКТИРОВАТЬ: Хорошо, это работает, я только что добавил эти две функции в свой UserCas.php:

public function serialize()
{
    return serialize($this->id);
}

public function unserialize($serialized)
{
   $this->id = unserialize($serialized);

}

1 Ответ

0 голосов
/ 17 апреля 2019

Это серьезное предположение с моей стороны, оно может быть или не быть правильным ответом.Я полагаюсь, может быть не правильный ответ.Для меня практически невозможно протестировать его локально, используя ваш код.

Я предполагаю, что в какой-то момент произойдет следующее:

$serlialization = serialize($userClass);

Ваш пользовательский класс имеет ссылку на ресурспоток, в этом случае File.Который не может быть сериализован.

См. здесь

Ресурсы не предназначены для сериализации и не могут сохраняться при загрузке страницы через переменные сеанса.Они в основном просто обрабатывают какой-то системный ресурс.PHP автоматически выделяет эти дескрипторы ресурсов в конце выполнения скрипта.

Вам придется реализовать интерфейс Serializable в ваших классах, который будет сериализован и будет иметь ссылки на ресурсы.

Давайте возьмем, к примеру, Paquet класс.

class Paquet implements \Serializable
{
    ...

    public function __clone()
    {
        // now it's a string reference not a resournce reference
        $this->noticeFile = $this->noticeFile->getPath();
         // Alternatively i think you can use base64_encode 
        $this->paquetFile = $this->paquetFile->getPath();

        // the rest can stay the same
    }

    public function serialize()
    {
        return serialize(clone $this);
    }

    public function unserialize($serialized)
    {
        // TODO: Implement unserialize() method.
    }
}

Конечно, вам не нужно делать это с клоном, есть и другие способы.

class Paquet implements \Serializable
{
    public function serialize()
    {
        $toSerialize = new \stdClass();

        $toSerialize->noticeFile = $this->noticeFile->getPath();
        $toSerialize->paquetFile = $this->paquetFile->getPath();

        return serialize($toSerialize);
    }

    public function unserialize($serialized)
    {
        $unseriliazed = unserialize($serialized);

        $this->noticeFile = new File($unseriliazed->noticeFile);
    }
}

Это должно заботиться о ссылке на ресурсный поток, так как это больше не ссылка, а строка.

Обратите внимание, что вы также можете использовать __sleep(), но вам также придется использовать__wakeup.Они делают более или менее то же самое, что и интерфейс Serializable, вам просто нужно написать собственную реализацию.


Опять же, это главное предположение с моей стороны.Вероятно, он не будет работать на 100% без настройки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...