Symfony 4 - Créer un blog pas à pas - Créer une interface d'administration

Par Nouvelle-Techno.fr le 14 novembre 2019 - Catégories : MVC Tutoriel Symfony Live-Coding

Lire l'article sur le site d'origine

Après avoir mis en place notre site, il est souvent nécessaire de créer une interface d'administration, qui permettra de créer, modifier, et supprimer différents types de contenus.

Cette interface d'administration peut être créée de toute pièce ou peut être créée en utilisant un bundle disponible sur Symfony, appelé Easy Admin, que nous utiliserons ici.

Avant toute chose, nous aurons besoin d'installer différents outils qui nous permettront :

Création des slugs

Voir cette partie en vidéo

Lors de l'ajout d'un article, nous allons générer une version simplifiée de son titre qui sera utilisée dans les routes pour générer des urls qui seront plus compréhensibles. Il s'agit d'un "slug". Le slug ne contient ni majuscules, ni accents, ni espaces ni caractères spéciaux.

Pour commencer nous allons installer les extensions Doctrine qui nous permettront d'effectuer cette tâche

composer require stof/doctrine-extensions-bundle

Une fois ces extensions installées, nous allons activer l'extension "Sluggable".

Celà se passe dans le fichier "config/packages/stof_doctrine_extensions.yaml", fichier à créer si il n'est pas présent

# Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html
# See the official DoctrineExtensions documentation for more details: https://github.com/Atlantic18/DoctrineExtensions/tree/master/doc/
stof_doctrine_extensions:
    default_locale: fr_FR
    orm:
        default:
            sluggable: true

Nous allons ensuite ajouter le "use" ci-dessous dans la ou les entités contenant des slugs

use Gedmo\Mapping\Annotation as Gedmo;

Enfin, dans ces mêmes entités, nous allons modifier l'annotation de la propriété "slug"

/**
 * @Gedmo\Slug(fields={"titre"})
 * @ORM\Column(length=128, unique=true)
 */
private $slug;

Il est également nécessaire de supprimer le "setter" setSlug.

Mise en place des dates de création et mise à jour

Voir cette partie en vidéo

Lors de l'ajout d'un article, nous allons générer automatiquement la date de création et la date de mise à jour.

Pour commencer nous allons installer les extensions Doctrine qui nous permettront d'effectuer cette tâche (inutile si vous avez effectué la partie précédente)

composer require stof/doctrine-extensions-bundle

Une fois ces extensions installées, nous allons activer l'extension "Timestampable".

Celà se passe dans le fichier "config/packages/stof_doctrine_extensions.yaml", fichier à créer si vous n'avez pas effectué la partie précédente

# Read the documentation: https://symfony.com/doc/current/bundles/StofDoctrineExtensionsBundle/index.html
# See the official DoctrineExtensions documentation for more details: https://github.com/Atlantic18/DoctrineExtensions/tree/master/doc/
stof_doctrine_extensions:
    default_locale: fr_FR
    orm:
        default:
            timestampable: true

Nous allons ensuite ajouter le "use" ci-dessous dans la ou les entités contenant des dates

use Gedmo\Mapping\Annotation as Gedmo;

Enfin, dans ces mêmes entités, nous allons modifier l'annotation des propriétés de date

    /**
     * @var \DateTime $created_at
     * 
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(type="datetime")
    */
    private $created_at;

    /**
     * @var \DateTime $updated_at
     *
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(type="datetime")
     */
    private $updated_at;

Il est également nécessaire de supprimer les "setters" setCreatedAt et setUpdatedAt si ils existent.

L'éditeur Wysiwig

Voir cette partie en vidéo

Nous utiliserons un éditeur appelé CKEditor, disponible en téléchargement pour tout projet sur le site officiel, et adapté à Symfony par le groupe "Friends of Symfony", sous le nom FOSCkeditor.

Installer CKEditor

Pour procéder à l'installation de FOSCkeditor, nous allons utiliser le terminal et composer.

La 1ère commande à entrer dans le terminal va récupérer CKEditor et l'intégrer à Symfony et au dossier vendor.

composer require friendsofsymfony/ckeditor-bundle

Il faudra ensuite télécharger les ressources nécessaires au fonctionnement de CKEditor (HTML, CSS, Javascript) et les installer.

php bin/console ckeditor:install

Enfin, nous allons installer toutes les ressources nécessaires dans le dossier "public"

php bin/console assets:install public

Voilà CKEditor maintenant installé.

Configurer CKEditor

Une fois installé, CKEditor est configurable directement depuis le fichier "config/packages/fos_ckeditor.yaml" qui a été créé automatiquement

Par défaut, il contient les lignes suivantes

# Read the documentation: https://symfony.com/doc/current/bundles/FOSCKEditorBundle/index.html

twig:
    form_themes:
        - '@FOSCKEditor/Form/ckeditor_widget.html.twig'

Nous allons y ajouter les configurations qui nous intéressent, et principalement la liste des options qui seront proposées aux utilisateurs.

Dans l'exemple ci-dessous, nous créons une configuration appelée "main_config" en ajoutant quelques lignes dans le fichier

# Read the documentation: https://symfony.com/doc/current/bundles/FOSCKEditorBundle/index.html

twig:
    form_themes:
        - '@FOSCKEditor/Form/ckeditor_widget.html.twig'

fos_ck_editor:
    configs:
        main_config:
            toolbar:
                - { name: "styles", items: ['Bold', 'Italic', 'Underline', 'Strike', 'Blockquote', '-', 'Link', '-', 'RemoveFormat', '-', 'NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock', '-', 'Image', 'Table', '-', 'Styles', 'Format','Font','FontSize', '-', 'TextColor', 'BGColor', 'Source'] }

L'upload d'images

Voir cette partie en vidéo

Pour pouvoir envoyer l'image d'illustration lors de l'ajout d'un article, il va être nécessaire de modifier l'entité "Articles" afin de prendre en compte cette option. A ce stade, notre entité "Articles" contient une propriété de type texte pour stocker le nom du fichier.

Le bundle Vich Uploader va nous permettre de paramétrer l'envoi de fichiers de façon simple.

Installer Vich Uploader

Pour installer le bundle Vich Uploader, nous allons utiliser composer.

composer require vich/uploader-bundle

Après cette installation, nous allons configurer l'emplacement des fichiers après l'upload.

Cette configuration sera à effectuer dans plusieurs fichiers YAML.

Le premier d'entre eux, "services.yaml", contiendra le paramètre qui formalisera le chemin vers le dossier d'upload ainsi qu'un nom qui sera attribué à ce chemin, ici "featured_images". "app.path" permet de spécifier que notre valeur est un chemin.

parameters:
    app.path.featured_images: /uploads/images/featured

Dans le deuxième fichier, "vich_uploader.yaml" nous allons configurer le "mapping", c'est à dire le lien entre le chemin et le nom attribué dans l'uploader. Les différentes valeurs se comprennent comme ceci :

vich_uploader:
    db_driver: orm
    
    mappings:
        featured_images:
            uri_prefix: '%app.path.featured_images%'
            namer: Vich\UploaderBundle\Naming\UniqidNamer
            upload_destination: '%kernel.project_dir%/public%app.path.featured_images%'

Enfin, nous allons mettre à jour notre entité pour que Vich Uploader fasse le lien entre la propriété "featured_image" et le fichier envoyé.

Les modifications à apporter dans l'entité "Articles" sont les suivantes

// Au début du fichier
use Symfony\Component\HttpFoundation\File\File;
use Vich\UploaderBundle\Mapping\Annotation as Vich;


// Juste au dessus de la classe Articles
/**
 * @ORM\Entity(repositoryClass="App\Repository\ArticlesRepository")
 * @Vich\Uploadable
 */
class Articles


// Près de la propriété $featured_image
/**
 * @ORM\Column(type="string", length=255)
 * @var string
 */
private $featured_image;

/**
 * @Vich\UploadableField(mapping="featured_images", fileNameProperty="featured_image")
 * @var File
 */
private $imageFile;


// Dans les Getters/setters
public function setImageFile(File $image = null)
{
    $this->imageFile = $image;

    if ($image) {
        $this->updated_at = new \DateTime('now');
    }
}

public function getImageFile()
{
    return $this->imageFile;
}

public function getFeaturedImage()
{
    return $this->featured_image;
}

public function setFeaturedImage($featured_image)
{
    $this->featured_image = $featured_image;

    return $this;
}

Voilà, le terrain est prêt pour créer l'interface d'administration.

L'interface d'administration

Voir cette partie en vidéo

Installer Easy Admin

Nous allons maintenant passer à l'installation d'Easy Admin afin de mettre en place l'interface d'administration du site.

Comme pour les bundles précédents, nous allons utiliser composer

composer require admin

Configurer Easy Admin

Une fois installé, la configuration d'Easy Admin se déroule dans le fichier "config/packages/easy_admin.yaml".

Nous allons pouvoir définir de nombreuses propriétés générales ainsi que pour chacune de nos entités.

Les propriétés générales

Quelques propriétés nous permettent de définir le titre de l'administration, l'affichage de l'utilisateur, les menus situés à gauche, entre autres, très nombreuses. L'exemple ci-dessous en définit certaines.

easy_admin:
    # On définit le nom de l'interface d'administration
    site_name: 'Gestion de mon blog'
    # On définit l'affichage de l'utilisateur
    user:
        display_name: true
        display_avatar: false
    design:
        # Ces lignes sont utiles pour CKEditor
        form_theme:
            - "@EasyAdmin/form/bootstrap_4.html.twig"
            - "@FOSCKEditor/Form/ckeditor_widget.html.twig"
        # Ces lignes définiront notre menu
        menu:
            - { label: 'Articles' }
            - { entity: 'Articles', label: 'Articles', icon: 'book' }
            - { entity: 'Categories', label: 'Catégories', icon: 'tag' }
            - { entity: 'MotsCles', label: 'Mots Clés', icon: 'tag' }
            - { label: 'Utilisateurs' }
            - { entity: 'Users', label: 'Utilisateurs', icon: 'user' }
    formats:
        # Ici on définit le format des dates
        datetime: 'd/m/Y à H:i'

Les entités

Pour chacune des entités, nous pourrons définir quelles informations s'affichent dans la liste, lesquelles s'affichent dans le formulaire d'ajout, entre autres.

L'exemple ci-dessous correspond à la configuration de l'entité "Articles"

    entities:
        Articles:
            # Correspond au fichier Articles.php
            class: App\Entity\Articles
            # On définit ci-dessous le contenu de la liste qui affichera les articles et les critères de tri
            list:
                fields:
                    - id
                    - titre
                    # Le champ ci-dessous affichera l'image de l'article
                    - { property: 'featured_image', label: 'Image', type: 'image', base_path: '%app.path.featured_images%' }
                    - { property: 'created_at', label: 'Créé' }
                    # Les catégories et les mots-clé sont listés ci-dessous
                    - { property: 'categories', label: 'Catégories', type: 'array'}
                    - { property: 'motsCles', label: 'Mots-Clés', type: 'array'}
                sort: ['created_at', 'desc']
            # On définit ci-dessous le contenu du formulaire d'ajout ou modification d'article
            form:
                fields:
                    - titre
                    # Affichage de l'éditeur Wysiwyg
                    - { property: 'contenu', type: 'fos_ckeditor', type_options: { config_name: 'main_config' }}
                    # Affichage du champ d'ajout d'image
                    - { property: 'imageFile', type: 'vich_image', label: 'Image' }
                    - users
                    # Les catégories et mots-clés peuvent s'afficher avec une sélection multiple
                    - { property: 'categories', label: 'Catégories', type: 'entity', type_options: { class: 'App\Entity\Categories', multiple: true,by_reference: false, attr: { data-widget: 'select2' }}}
                    - { property: 'motsCles', label: 'Mots Clés', type: 'entity', type_options: { class: 'App\Entity\MotsCles', multiple: true,by_reference: false, attr: { data-widget: 'select2' }}}

Les autres entités pourront être affichées de la même façon.

Pour l'entité Users, nous allons également pouvoir modifier le rôle de l'utilisateur.

La configuration de cette entité sera donc la suivante (avec rôles user et admin)

Users:
    class: App\Entity\Users
    label: 'Utilisateurs'
    list:
        fields:
            - id
            - email
            - { property: 'roles', label: 'Rôles', type: json_array}
    form:
        fields:
            - email
            - { property: 'roles', label: 'Rôles', type: choice, type_options: {expanded: true, multiple: true, choices: {'Utilisateur':'ROLE_USER', 'Administrateur':'ROLE_ADMIN'}}}

Gérer les relations

Dans le cas d'entités avec relations, comme par exemple les entités "Articles" et "Categories", il est nécessaire de définir quelle valeur sera affichée pour les catégories lors de l'ajout ou la modification d'un article.

Nous allons afficher le nom de la catégorie, option la plus logique.

Afin de permettre cet affichage, il sera nécessaire d'implémenter la méthode magique "__toString" dans les entités qui le nécessitent, "Categories" dans cet exemple.

Nous ajouterons donc cette méthode comme ci-dessous

public function __toString()
{
    return $this->nom;
}

Protéger notre administration

Voir cette partie en vidéo

L'interface d'administration ne doit pas être accessible par tous les utilisateurs.

Afin de la protéger, nous allons demander l'authentification des utilisateurs avant de pouvoir y accéder, et vérifier qu'ils sont administrateurs.

Pour ce faire, rendez-vous à la fin de "config/packages/security.yaml" et retirez le # devant la ligne ci-dessous

- { path: ^/admin, roles: ROLE_ADMIN }

C'est tout, merci de votre fidélité.

Obtenir de l'aide

Pour obtenir de l'aide, vous pouvez accéder aux forums de Nouvelle-Techno.fr ou au serveur Discord pour une entraide par chat

#Tutoriel #Framework #Base de données #MVC #Symfony #Live-Coding