FabRiviere / Livre_Or_Symfony

Développement du projet concernant un livre d'or sur les conférences. Projet du livre Symfony 6.
0 stars 0 forks source link

Ajout de slugs aux conférences #23

Closed FabRiviere closed 1 year ago

FabRiviere commented 1 year ago
FabRiviere commented 1 year ago

Modification du fichier de migration :

L'astuce ici est d'ajouter la colonne et de lui permettre d'être null, puis de définir une valeur non null pour le slug, et enfin, de changer la colonne de slug pour ne plus permettre null.

public function up(Schema $schema): void
    {
        // this up() migration is auto-generated, please modify it to your needs
        // $this->addSql('ALTER TABLE conference ADD slug VARCHAR(255) NOT NULL');
        $this->addSql('ALTER TABLE conference ADD slug VARCHAR(255)');
        $this->addSql("UPDATE conference SET slug=CONCAT(LOWER(city), '-', year)");
        $this->addSql('ALTER TABLE conference ALTER COLUMN slug SET NOT NULL');
    }

Ajout de la contrainte d'élément unique sur le champ "slug" :

use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;

#[ORM\Entity(repositoryClass: ConferenceRepository::class)]
#[UniqueEntity('slug')]
class Conference
#[ORM\Column(length: 255, unique: true)]
    private ?string $slug = null;

Refaire ensuite une migration, et envoi de la migration en base de données.

Ajout d'une méthode (fonction) pour générer les slugs en fonction des données de la conférence :

public function computeSlug(SluggerInterface $slugger)
    {
        if (!$this->slug || '-' === $this->slug) {
            $this->slug = (string) $slugger->slug((string) $this)->lower();
        }
    }

La méthode computeSlug() ne calcule un slug que lorsque le slug courant est vide ou défini à la valeur spéciale -. Pourquoi avons-nous besoin de cette valeur particulière - ? Parce que lors de l'ajout d'une conférence dans l'interface d'administration, le slug est nécessaire. Nous avons donc besoin d'une valeur non vide qui indique à l'application que nous voulons que le slug soit généré automatiquement.

Création d'un listener d'entité Doctrine -> ConferenceEntityListener.php :

<?php

namespace App\EntityListener;

use App\Entity\Conference;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\String\Slugger\SluggerInterface;

class ConferenceEntityListener
{
    public function __construct(private SluggerInterface $slugger)
    {        
    }

    public function prePersist(Conference $conference, LifecycleEventArgs $event)
    {
        $conference->computeSlug($this->slugger);
    }

    public function preUpdate(Conference $conference, LifecycleEventArgs $event)
    {
        $conference->computeSlug($this->slugger);
    }
}

Notez que le slug est modifié lorsqu'une nouvelle conférence est créée (prePersist()) et lorsqu'elle est mise à jour (preUpdate()).

Configuration du service dans le conteneur :

<?php

namespace App\EntityListener;

use Doctrine\ORM\Events;
use App\Entity\Conference;
use Doctrine\Persistence\Event\LifecycleEventArgs;
use Symfony\Component\String\Slugger\SluggerInterface;
use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener;

#[AsEntityListener(event: Events::prePersist, entity: Conference::class)]
#[AsEntityListener(event: Events::preUpdate, entity: Conference::class)]
class ConferenceEntityListener
{
    public function __construct(private SluggerInterface $slugger)
    {        
    }

    public function prePersist(Conference $conference, LifecycleEventArgs $event)
    {
        $conference->computeSlug($this->slugger);
    }

    public function preUpdate(Conference $conference, LifecycleEventArgs $event)
    {
        $conference->computeSlug($this->slugger);
    }
}

Modification du contrôleur :

// #[Route('/conference/{id}', name: 'conference')]
    #[Route('/conference/{slug}', name: 'conference')]

Modification des templates Twig :

{# <a href="{{ path('conference', { id: conference.id }) }}">{{ conference }}</a> #}
    <a href="{{ path('conference', { slug: conference.slug }) }}">{{ conference }}</a>