Changer l'image de la homepage (CRUD d'upload d'image)
Le but de cet article est de vous détailler toutes les étapes pour réaliser un upload d'image en back et afficher ces images en front sur la homepage
front
s
back
Nous allons commencer par créer une Entity que nous appelerons src/Entity/BannerImage.php
<?php
declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Sylius\Component\Core\Model\Image;
/**
* @ORM\Entity()
*/
class BannerImage extends Image implements BannerImageInterface
{
}
ainsi que son interface src/Entity/BannerImageInterface.php
<?php
declare(strict_types=1);
namespace App\Entity;
use Sylius\Component\Core\Model\ImageInterface;
interface BannerImageInterface extends ImageInterface
{
}
C'est tout. Tout se trouve dans le modèle ImageInterface dont nous héritons
Mettons à jour la base de données avec
php bin/console doctrine:migrations:diff
puis créons cette nouvelle entité
php bin/console doctrine:migrations:migrate
Dans le fichier config/packages/resources.yaml
nous définissons cette entité
sylius_resource:
resources:
app.banner_image:
driver: doctrine/orm
classes:
model: App\Entity\BannerImage
Créations de la grille qui va nous permettre d'afficher l'entité dans le dashboard
dans le fichier config/packages/grids.yaml
sylius_grid:
grids:
app_admin_banner_image:
driver:
name: doctrine/orm
options:
class: App\Entity\BannerImage
actions:
main:
create:
type: create
item:
update:
type: update
delete:
type: delete
Enfin, création de la route dans config/routes.yaml
app_banner_image:
resource: |
alias: app.banner_image
section: admin
templates: SyliusAdminBundle:Crud
grid: app_admin_banner_image
redirect: index
type: sylius.resource
prefix: admin
Nous avons la route, qui appelle notre ressource banner_image définie dans resources.yaml et également dans la route est définie quelle grille est relié à cette ressource. Grile app_admin_banner_image que nous avons définie dans grids.yaml
Dans le terminal avec la commande
php bin/console debug:router
on peut constater les nouvelles routes :
app_admin_banner_image_index GET ANY ANY /admin/banner-images/
app_admin_banner_image_create GET|POST ANY ANY /admin/banner-images/new
app_admin_banner_image_update GET|PUT|PATCH ANY ANY /admin/banner-images/{id}/edit
app_admin_banner_image_show GET ANY ANY /admin/banner-images/{id}
app_admin_banner_image_bulk_delete DELETE ANY ANY /admin/banner-images/bulk-delete
app_admin_banner_image_delete DELETE ANY ANY /admin/banner-images/{id}
Si vous vous rendez dans votre dashboard localhost/admin/banner-images/
vous devriez avoir ce résultat :
A partir de ce moment cliquer sur Create nous amène à cette page mais ne nous permet pas d'envoyer d'image sur le serveur
Nous allons créer le formulaire qui va nous permettre d'envoyer une image.
src/Form/Type/BannerImageType.php
<?php
declare(strict_types=1);
namespace App\Form\Type;
use Sylius\Bundle\CoreBundle\Form\Type\ImageType as BaseImageType;
class BannerImageType extends BaseImageType
{
}
Encore une fois, pas besoin de le remplir, tout se trouve dans la classe ImageType dont nous héritons
Il faut déclarer ce form comme service, dans config/services.yaml
rajoutez :
services:
app.banner_image.type.form.type:
class: App\Form\Type\BannerImageType
tags:
- { name: form.type }
arguments: ['App\Entity\BannerImage']
et enfin l'indiquer à notre ressource dans config/packages/resources.yaml
sylius_resource:
resources:
app.banner_image:
driver: doctrine/orm
classes:
model: App\Entity\BannerImage
form: App\Form\Type\BannerImageType # on rajoute cette ligne
Voici le résultat sur la page Create
event uploader
Il n'est toujours pas possible d'uploader une image. On va créer un event qui va écouter le moment où le form est submit pour transférer l'image. Pour l'event il faut créer le listener src/Uploader/BannerImageUploadListener.php
<?php
declare(strict_types=1);
namespace App\Uploader;
use App\Entity\BannerImageInterface;
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Webmozart\Assert\Assert;
class BannerImageUploadListener
{
/** @var ImageUploaderInterface */
private $uploader;
public function __construct(ImageUploaderInterface $uploader)
{
$this->uploader = $uploader;
}
public function upload(GenericEvent $event): void
{
$subject = $event->getSubject();
Assert::isInstanceOf($subject, BannerImageInterface::class);
if ($subject->hasFile()) {
$this->uploader->upload($subject);
}
}
}
On déclare le listener dans config/services.yaml
app.listener.banner_image_upload:
class: App\Uploader\BannerImageUploadListener
autowire: true
autoconfigure: false
public: false
tags:
- { name: kernel.event_listener, event: app.banner_image.pre_create, method: upload }
L'uploader sera appelé juste avant de persist. L'event correspond à la ressource, ici notre ressource s'appelle app.banner_image
Si nous ajoutons des images, l'upload s'effectue correctement, maintenant nous allons les afficher dans le dashboard
Pour ça il faut créer le template templates/_fieldImage.html.twig
qu'on va utiliser dans la colonne avec comme contenu
<img class="ui small bordered image" src="{{ data|imagine_filter('sylius_small') }}" />
data nous retourne l'information de la colonne, ici c'est la valeur du path qui est retourné, il faut encore indiquer à notre grille où est le template, dans config/packages/grids.yaml
:
app_admin_banner_image:
driver:
name: doctrine/orm
options:
class: App\Entity\BannerImage
fields:
path:
type: twig
options:
template: "_fieldImage.html.twig" # ici on indique le template
Nous pouvons maintenant ajouter une image, et la voir dans la liste.
editer et supprimer l'image
Pour editer et supprimer l'image on utilise le même listener.
src/Uploader/BannerImageUploadListener.php
<?php
declare(strict_types=1);
namespace App\Uploader;
use App\Entity\BannerImageInterface;
use Sylius\Component\Core\Uploader\ImageUploaderInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
use Webmozart\Assert\Assert;
class BannerImageUploadListener
{
/** @var ImageUploaderInterface */
private $uploader;
public function __construct(ImageUploaderInterface $uploader)
{
$this->uploader = $uploader;
}
public function upload(GenericEvent $event): void
{
$subject = $event->getSubject();
Assert::isInstanceOf($subject, BannerImageInterface::class);
if ($subject->hasFile()) {
$this->uploader->upload($subject);
}
}
public function edit(GenericEvent $event): void
{
$subject = $event->getSubject();
// remove older file
if ($subject->hasFile()) {
$this->uploader->remove($subject->getPath());
Assert::isInstanceOf($subject, BannerImageInterface::class);
$this->uploader->upload($subject);
}
}
public function remove(GenericEvent $event): void
{
$subject = $event->getSubject();
Assert::isInstanceOf($subject, BannerImageInterface::class);
if ($subject->hasFile()) {
$this->uploader->remove($subject);
}
}
}
On ajoute deux tags à notre listener
app.listener.banner_image_upload:
class: App\Uploader\BannerImageUploadListener
autowire: true
autoconfigure: false
public: false
tags:
- { name: kernel.event_listener, event: app.banner_image.pre_create, method: upload }
- { name: kernel.event_listener, event: app.banner_image.pre_update, method: edit }
- { name: kernel.event_listener, event: app.banner_image.pre_delete, method: remove }
Maintenant les actions editer et supprimer fonctionne. La fonction edit supprime l'image actuelle avant d'ajouter la nouvelle.
Homepage
Il nous reste à afficher ces images sur la homepage. On crée le template :
templates/Homepage/_banner.html.twig
{{ render(controller('App\\Controller\\BannerImageController::getImages')) }}
<div class="ui hidden divider"></div>
Puis on va utiliser les events de sylius_ui, de cette façon on ne surcharge pas le template :
config/packages/sylius_ui.yaml
sylius_ui:
events:
sylius.shop.homepage:
blocks:
banner:
template: "Homepage/_banner.html.twig"
On va créer getImages l'action qu'on appelle dans le template, pour ça il faut créer le controller src/Controller/BannerImageController.php
<?php
namespace App\Controller;
use App\Repository\BannerImageRepository;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
class BannerImageController extends AbstractController
{
/**
* This controller is called directly via the render() function
*/
public function getImages(BannerImageRepository $bannerImage)
{
return $this->render('Homepage/_images.html.twig', [
'images' => $bannerImage->findAll()
]);
}
}
Nous avons besoin du repository, nous allons donc le créer src/Repository/BannerImageRepository.php
<?php
namespace App\Repository;
use App\Entity\BannerImage;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
/**
* @method BannerImage|null find($id, $lockMode = null, $lockVersion = null)
* @method BannerImage|null findOneBy(array $criteria, array $orderBy = null)
* @method BannerImage[] findAll()
* @method BannerImage[] findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null)
*/
class BannerImageRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, BannerImage::class);
}
}
Dans notre action, nous appelons également un template qui boucle sur les images.
templates/Homepage/_images.html.twig
{% for image in images %}
<img style="width: 50%; float: right;" class="ui fluid image" src="{{ "/media/image" ~ asset(image.path) }}">
{% endfor %}
Vous pouvez maintenant vous rendre sur la homepage et découvrir les images que vous avez uploadés !