Bonjour,
*Ce que je veux *
Je voudrai mettre une image à la une pour chacun de mes produits, je suis le tuto de grafikart 10/16 gérer les images à la une
https://www.youtube.com/watch?v=OZBVd4ZTIqk
J'utilise le bundle VichUploaderBundle pour pouvoir uploader des photos et les utiliser comme image à la une.
L'upload fonctionne, mais au niveau de la vue,cela me génère une image avec style="display:none" et hidden="" dans mon
Ce que je fais
Mon Entity
<?php
namespace App\Entity;
use Cocur\Slugify\Slugify;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping\HasLifecycleCallbacks;
use Symfony\Component\HttpFoundation\File\File;
use Doctrine\Common\Collections\ArrayCollection;
use Vich\UploaderBundle\Mapping\Annotation as Vich;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
/**
* @ORM\Entity(repositoryClass="App\Repository\AdRepository")
* @Vich\Uploadable
* @ORM\HasLifecycleCallbacks
* @UniqueEntity(
* "title",
* message="Le champs est déjà utilisé"
* )
*
*/
class Ad
{
/**
* @ORM\Id()
* @ORM\GeneratedValue()
* @ORM\Column(type="integer")
*
*/
private $id;
/**
* NOTE: This is not a mapped field of entity metadata, just a simple property.
*
* @Vich\UploadableField(mapping="ads_image", fileNameProperty="fileName")
*
* @var File
*/
private $imageFile;
/**
* @ORM\Column(type="string", length=255)
*
* @var string|null
*/
private $fileName;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Length(
* min=10,
* max=50,
* minMessage="Le minimum est de {{ limit }}",
* maxMessage="Le maximum est de {{ limit }}"
* )
*/
private $title;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Url(
* message="L'url '{{ value }}' est invalide",
* relativeProtocol = true
* )
*/
private $coverImage;
/**
* @ORM\Column(type="string", length=255)
* @Assert\Length(
* min=30,
* max=75,
* minMessage="Le minimum est de {{ limit }}",
* maxMessage="Le maximum est de {{ limit }}"
* )
*/
private $intro;
/**
* @ORM\Column(type="text")
* @Assert\Length(
* min=50,
* max=125,
* minMessage="Le minimum est de {{ limit }}",
* maxMessage="Le maximum est de {{ limit }}"
* )
*/
private $description;
/**
* @ORM\OneToMany(targetEntity="App\Entity\Image", mappedBy="linkImage", orphanRemoval=true)
* @Assert\Valid()
*/
private $images;
/**
* @ORM\ManyToOne(targetEntity="App\Entity\User", inversedBy="ads")
* @ORM\JoinColumn(nullable=false)
*/
private $author;
/**
* @ORM\Column(type="string", length=255)
*/
private $slug;
/**
* @ORM\Column(type="integer")
*/
private $surface;
/**
* @ORM\Column(type="integer")
*/
private $price;
/**
* @ORM\Column(type="integer")
*/
private $rooms;
/**
* @ORM\Column(type="integer")
*/
private $floor;
/**
* @ORM\Column(type="integer")
*/
private $bedrooms;
/**
* @ORM\Column(type="boolean", options={"default":false})
*/
private $sold = false;
/**
* @ORM\Column(type="string", length=255)
*/
private $adresse;
/**
* @ORM\Column(type="integer")
*/
private $postalCode;
/**
* @ORM\ManyToMany(targetEntity="App\Entity\OptionAd", inversedBy="ads")
*/
private $optionsAd;
/**
* @ORM\Column(type="datetime")
*/
private $updated_At;
public function __construct()
{
$this->images = new ArrayCollection();
$this->optionsAd = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getCoverImage(): ?string
{
return $this->coverImage;
}
public function setCoverImage(string $coverImage): self
{
$this->coverImage = $coverImage;
return $this;
}
public function getIntro(): ?string
{
return $this->intro;
}
public function setIntro(string $intro): self
{
$this->intro = $intro;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(string $description): self
{
$this->description = $description;
return $this;
}
/**
* @return Collection|Image[]
*/
public function getImages(): Collection
{
return $this->images;
}
public function addImage(Image $image): self
{
if (!$this->images->contains($image)) {
$this->images[] = $image;
$image->setLinkImage($this);
}
return $this;
}
public function removeImage(Image $image): self
{
if ($this->images->contains($image)) {
$this->images->removeElement($image);
// set the owning side to null (unless already changed)
if ($image->getLinkImage() === $this) {
$image->setLinkImage(null);
}
}
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
public function getSlug(): ?string
{
return $this->slug;
}
public function setSlug(string $slug): self
{
$this->slug = $slug;
return $this;
}
/**
* Permet d'intialiser le slug !
* @ORM\PrePersist
* @ORM\PreUpdate
*
* @return void
*/
public function initializeSlug(){
if(empty($this->slug)){
$slugify = new Slugify();
$this->slug=$slugify->slugify($this->title);
}
}
public function getSurface(): ?int
{
return $this->surface;
}
public function setSurface(int $surface): self
{
$this->surface = $surface;
return $this;
}
public function getPrice(): ?int
{
return $this->price;
}
public function setPrice(int $price): self
{
$this->price = $price;
return $this;
}
public function getRooms(): ?int
{
return $this->rooms;
}
public function setRooms(int $rooms): self
{
$this->rooms = $rooms;
return $this;
}
public function getFloor(): ?int
{
return $this->floor;
}
public function setFloor(int $floor): self
{
$this->floor = $floor;
return $this;
}
public function getBedrooms(): ?int
{
return $this->bedrooms;
}
public function setBedrooms(int $bedrooms): self
{
$this->bedrooms = $bedrooms;
return $this;
}
public function getSold(): ?bool
{
return $this->sold;
}
public function setSold(bool $sold): self
{
$this->sold = $sold;
return $this;
}
public function getAdresse(): ?string
{
return $this->adresse;
}
public function setAdresse(string $adresse): self
{
$this->adresse = $adresse;
return $this;
}
public function getPostalCode(): ?int
{
return $this->postalCode;
}
public function setPostalCode(int $postalCode): self
{
$this->postalCode = $postalCode;
return $this;
}
/**
* @return Collection|OptionAd[]
*/
public function getOptionsAd(): Collection
{
return $this->optionsAd;
}
public function addOptionsAd(OptionAd $optionsAd): self
{
if (!$this->optionsAd->contains($optionsAd)) {
$this->optionsAd[] = $optionsAd;
}
return $this;
}
public function removeOptionsAd(OptionAd $optionsAd): self
{
if ($this->optionsAd->contains($optionsAd)) {
$this->optionsAd->removeElement($optionsAd);
}
return $this;
}
/**
* Undocumented function
*
* @return string|null
*/
public function getFileName(): string {
return $this->fileName;
}
/**
* Undocumented function
*
* @param string|null $fileName
* @return self
*/
public function setFileName(?string $fileName): self {
$this->fileName = $fileName;
return $this;
}
/**
* Undocumented function
*
* @return null|File
*/
public function getImageFile() {
return $this->imageFile;
}
/**
* Undocumented function
*
* @param File|null $imageFile
* @return self
*/
public function setImageFile(?File $imageFile): self {
$this->imageFile = $imageFile;
if ($this->imageFile instanceof UploadedFile) {
$this->updated_At = new \DateTime('now');
}
return $this;
}
public function getUpdatedAt(): ?\DateTimeInterface
{
return $this->updated_At;
}
public function setUpdatedAt(\DateTimeInterface $updated_At): self
{
$this->updated_At = $updated_At;
return $this;
}
}
vich_uploader.yaml
Code yaml :
vich_uploader:
db_driver: orm
mappings:
ads_image:
uri_prefix: /images/ads
upload_destination: '%kernel.project_dir%/public/images/ads'
namer: Vich\UploaderBundle\Naming\UniqidNamer
inject_on_load: false
delete_on_update: true
delete_on_remove: true
Form:
<?php
namespace App\Form;
use App\Entity\Ad;
use App\Form\ImageType;
use App\Entity\OptionAd;
use App\Form\ApplicationType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Form\Extension\Core\Type\UrlType;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Vich\UploaderBundle\Form\Type\VichImageType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Core\Type\MoneyType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
class AdType extends ApplicationType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('title',TextType::class,$this->getConfiguration('titre','Insérer un titre'))
->add('coverImage',UrlType::class,$this->getConfiguration('Image','Insérer une image'))
->add('intro',TextType::class,$this->getConfiguration('intro','insérer une intro'))
->add('description',TextareaType::class,$this->getConfiguration('description','insérer une description'))
->add('surface',NumberType::class,$this->getConfiguration('Surface','insérer une surface'))
->add('price',MoneyType::class,$this->getConfiguration('Prix','insérer un prix'))
->add('rooms',NumberType::class,$this->getConfiguration('Chambre','indiquez le nombre de chambre'))
->add('floor',NumberType::class,$this->getConfiguration('Etage','indiquez le nombre d\'étage'))
->add('bedrooms',NumberType::class,$this->getConfiguration('Chambres à coucher ','indiquez le nombre chambre à coucher'))
->add('adresse',TextType::class,$this->getConfiguration('Adresse','Indiquer une adresse'))
->add('postalCode',IntegerType::class,$this->getConfiguration('Code postal','Indiquer un code postal'))
->add('optionsAd',EntityType::class,$this->getconfiguration('Options',false,[
'class' => OptionAd::class,
'choice_label' => 'name',
'multiple' => true
]))
->add('imageFile',VichImageType::class,[
'required'=> false
])
->add('images',CollectionType::class,[
'entry_type'=>ImageType::class,
'allow_add'=> true,
'allow_delete'=>true
])
;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'data_class' => Ad::class,
'csrf_protection' => true,
'csrf_field_name' => '_form',
'csrf_token_id' => 'edit_form'
]);
}
}
La Vue :
Code twig :
{% extends 'base.html.twig' %}
{% block title %}Home{% endblock %}
{% block body %}
<div class="jumbotron">
<div class="container">
{% form_theme form _self %}
{{ form_start(form) }}
<div class="form-row align-items-center justify-content-center">
<div class="col-auto">
{{form_row(form.maxPrice)}}
</div>
<div class="col-auto">
{{form_row(form.minSurface)}}
</div>
<div class="col-auto">
{{form_row(form.optionsAd)}}
</div>
{{form_rest(form)}}
<div class="col-auto">
<input type="submit" class="btn btn-primary">
</div>
{{ form_end(form) }}
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-10">
<div class="row justify-content-center mt-5">
{% for ad in articles %}
{% include 'ad/_ad.html.twig'%}
{% endfor %}
</div>
</div>
</div>
<div class="row justify-content-center">
<div class="col-2">
<div class="navigation mt-5">
{{ knp_pagination_render(articles) }}
</div>
</div>
</div>
{% endblock %}
include 'ad/_ad.html.twig'
Code twig :
<div class="col-lg-4 col-md-6 col-sm-12">
<a href="{{path('show_ad',{id:ad.id})}}">
<div class="card">
{% if ad.fileName %}
<img src="{{ vich_uploader_asset(ad,'imageFile') }}" alt="{{ ad.Filename }}">
{% endif %}
<div class="card-body">
<h2>{{ad.title}}</h2>
<p class="card-text">{{ad.intro}}</p>
<h3>{{ad.price}}€</h3>
<h4>{{ad.surface}} m²</h4>
</div>
</div>
</a>
</div>
Ce que j'obtiens