Symfony — «spl_object_hash () ожидает, что параметром 1 будет объект, заданный массив»

У меня проблема с загрузкой фото в форму. Я могу сохранить свою форму с помощью Doctrine в SQL, но когда я хочу сохранить несколько изображений, появляется это сообщение об ошибке:

ContextErrorException HTTP 500 Внутренняя ошибка сервера Предупреждение:
spl_object_hash () ожидает, что параметр 1 будет объектом, задан массив

РОДИТЕЛЬ: WebApp.php

<?php

namespace MO\WebAppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
//pour le slug
use Gedmo\Mapping\Annotation as Gedmo;
use Vich\UploaderBundle\Mapping\Annotation as Vich;/**
* WebApp
*
* @ORM\Table(name="mo_travel")
* @ORM\Entity(repositoryClass="MO\WebAppBundle\Repository\WebAppRepository")
* @ORM\HasLifecycleCallbacks()
*
*
*/
class WebApp
{
/**
* @var int
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

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

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

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

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

/**
* @ORM\Column(name="published", type="boolean")
*/
private $published = true;

/**
* @ORM\OneToMany(targetEntity="MO\WebAppBundle\Entity\Image", cascade={"persist"}, mappedBy="webapp"))
* @ORM\JoinTable(name="mo_travel_image")
*/
private $image;

/**
* @ORM\ManyToMany(targetEntity="MO\WebAppBundle\Entity\Category", cascade={"persist"})
* @ORM\JoinTable(name="mo_travel_category")
*/
private $categories;

/**
* @Gedmo\Slug(fields={"title"})
* @ORM\Column(name="slug", type="string", length=255, unique=true)
*/
private $slug;

/**
* @ORM\Column(name="updated_at", type="datetime", nullable=true)
* @var \DateTime
*/
private $updatedAt;

/**
* WebApp constructor.
*/
public function __construct()
{
// Par défaut, la date de l'annonce est la date d'aujourd'hui
$this->date = new \Datetime();
$this->categories = new ArrayCollection();
$this->image = new ArrayCollection();
}

/**
* @ORM\PreUpdate
*/
public function updateDate()
{
$this->setUpdatedAt(new \Datetime());
}

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

/**
* Set date
*
* @param \DateTime $date
*
* @return WebApp
*/
public function setDate($date)
{
$this->date = $date;

return $this;
}

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

/**
* Set title
*
* @param string $title
*
* @return WebApp
*/
public function setTitle($title)
{
$this->title = $title;

return $this;
}

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

/**
* Set author
*
* @param string $author
*
* @return WebApp
*/
public function setAuthor($author)
{
$this->author = $author;

return $this;
}

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

/**
* Set content
*
* @param string $content
*
* @return WebApp
*/
public function setContent($content)
{
$this->content = $content;

return $this;
}

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

/**
* @param boolean $published
*
* @return WebApp
*/
public function setPublished($published)
{
$this->published = $published;
}

/**
* @return mixed
*/
public function getPublished()
{
return $this->published;
}

public function setImage(Image $image = null)
{
$this->image = $image;
}

public function getImage()
{
return $this->image;
}

/**
* Add category
*
* @param \MO\WebAppBundle\Entity\Category $category
*
* @return WebApp
*/
public function addCategory(\MO\WebAppBundle\Entity\Category $category)
{
$this->categories[] = $category;

return $this;
}

/**
* Remove category
*
* @param \MO\WebAppBundle\Entity\Category $category
*/
public function removeCategory(\MO\WebAppBundle\Entity\Category $category)
{
$this->categories->removeElement($category);
}

/**
* Get categories
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getCategories()
{
return $this->categories;
}

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

/**
* @param mixed $updatedAt
*
* @return WebApp
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
}

/**
* Set slug
*
* @param string $slug
*
* @return WebApp
*/
public function setSlug($slug)
{
$this->slug = $slug;

return $this;
}

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

}

ДЕТИ: Image.php

<?php

namespace MO\WebAppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;

/**
* @ORM\Table(name="mo_image")
* @ORM\Entity
* @ORM\HasLifecycleCallbacks
*/
class Image
{
/**
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

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

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

/**
* @var UploadedFile
*/
private $file;

// On ajoute cet attribut pour y stocker le nom du fichier temporairement
private $tempFilename;

/**
* @ORM\PrePersist()
* @ORM\PreUpdate()
*/
public function preUpload()
{
// Si jamais il n'y a pas de fichier (champ facultatif), on ne fait rien
if (null === $this->file) {
return;
}

// Le nom du fichier est son id, on doit juste stocker également son extension
// Pour faire propre, on devrait renommer cet attribut en « extension », plutôt que « url »
$this->url = $this->file->guessExtension();

// Et on génère l'attribut alt de la balise <img>, à la valeur du nom du fichier sur le PC de l'internaute
$this->alt = $this->file->getClientOriginalName();
}

/**
* @ORM\PostPersist()
* @ORM\PostUpdate()
*/
public function upload()
{
// Si jamais il n'y a pas de fichier (champ facultatif), on ne fait rien
if (null === $this->file) {
return;
}

// Si on avait un ancien fichier (attribut tempFilename non null), on le supprime
if (null !== $this->tempFilename) {
$oldFile = $this->getUploadRootDir().'/'.$this->id.'.'.$this->tempFilename;
if (file_exists($oldFile)) {
unlink($oldFile);
}
}

// On déplace le fichier envoyé dans le répertoire de notre choix
$this->file->move(
$this->getUploadRootDir(), // Le répertoire de destination
$this->id.'.'.$this->url   // Le nom du fichier à créer, ici « id.extension »
);
}

/**
* @ORM\PreRemove()
*/
public function preRemoveUpload()
{
// On sauvegarde temporairement le nom du fichier, car il dépend de l'id
$this->tempFilename = $this->getUploadRootDir().'/'.$this->id.'.'.$this->url;
}

/**
* @ORM\PostRemove()
*/
public function removeUpload()
{
// En PostRemove, on n'a pas accès à l'id, on utilise notre nom sauvegardé
if (file_exists($this->tempFilename)) {
// On supprime le fichier
unlink($this->tempFilename);
}
}

public function getUploadDir()
{
// On retourne le chemin relatif vers l'image pour un navigateur (relatif au répertoire /web donc)
return 'uploads/img';
}

protected function getUploadRootDir()
{
// On retourne le chemin relatif vers l'image pour notre code PHP
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}

public function getWebPath()
{
return $this->getUploadDir().'/'.$this->getId().'.'.$this->getUrl();
}

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

/**
* @param string $url
*/
public function setUrl($url)
{
$this->url = $url;
}

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

/**
* @param string $alt
*/
public function setAlt($alt)
{
$this->alt = $alt;
}

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

/**
* @return UploadedFile
*/
public function getFile()
{
return $this->file;
}

/**
* @param UploadedFile $file
*/
// On modifie le setter de File, pour prendre en compte l'upload d'un fichier lorsqu'il en existe déjà un autre
public function setFile(UploadedFile $file)
{
$this->file = $file;

// On vérifie si on avait déjà un fichier pour cette entité
if (null !== $this->url) {
// On sauvegarde l'extension du fichier pour le supprimer plus tard
$this->tempFilename = $this->url;

// On réinitialise les valeurs des attributs url et alt
$this->url = null;
$this->alt = null;
}
}
}

WebAppType.php

<?php
namespace MO\WebAppBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
class WebAppType extends AbstractType
{
/**
* Réutilisabilité de notre formulaire
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('date',      DateTimeType::class)
->add('title',     TextType::class)
->add('author',    TextType::class)
->add('content',   TextareaType::class)
->add('image',ImageType::class, array("data_class" => null))

/*
** - 1er argument : nom du champ, ici « categories », car c'est le nom de l'attribut
** - 2e argument : type du champ, ici « CollectionType » qui est une liste de quelque chose
** - 3e argument : tableau d'options du champ
*/
->add('categories', EntityType::class, array(
'class'        => 'MOWebAppBundle:Category',
'choice_label' => 'name',
'expanded'     => true,
'multiple'     => true,
))
->add('save',      SubmitType::class);
// On ajoute une fonction qui va écouter un évènement de formulaire
$builder->addEventListener(
FormEvents::PRE_SET_DATA,    // 1er argument : L'évènement qui nous intéresse : ici, PRE_SET_DATA
function(FormEvent $event) { // 2e argument : La fonction à exécuter lorsque l'évènement est déclenché
// On récupère notre objet WebApp (travel) sous-jacent
$travel = $event->getData();
// Cette condition est importante, on en reparle plus loin
if (null === $travel) {
return; // On sort de la fonction sans rien faire lorsque $advert vaut null
}
// Si l'annonce n'est pas publiée, ou si id null
if (!$travel->getPublished() || null === $travel->getId()) {
// Alors on ajoute le champ published
$event->getForm()->add('published', CheckboxType::class, array('required' => false));
} else {
// Sinon, on le supprime
$event->getForm()->remove('published');
}
}
);
}

/**
* {@inheritdoc}
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MO\WebAppBundle\Entity\WebApp'
));
}
}

ImageType.php

<?php

namespace MO\WebAppBundle\Form;

use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\FileType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class ImageType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', FileType::class, array(
'multiple'     => true ))
->add('url', TextType::class)
->add('alt', TextType::class)
;
}

public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'MO\WebAppBundle\Entity\Image'
));
}
}

Большое спасибо за ваши ответы.

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]