Accueil » Symfony Menu d’administration EasyAdmin 4

Symfony Menu d’administration EasyAdmin 4

Le Bundle EasyAdmin 4 permet de créer un menu d’administration avec le Framework Symfony 6. Dans cette procédure, je vais vous montrer comment créer un menu d’administration à l’aide ce Bundle Symfony 6. Nous allons commencer par créer un nouveau projet avec de nouvelles entités et puis nous les intégrerons dans EasyAdmin.

Logo Symfony

Prérequis :

Création d’un menu d’administration sous Symfony 6 avec EasyAdmin 4 :

Avant de créer le menu d’administration, nous allons préparer le projet dans lequel nous allons créer ce menu d’administration.

Préparation de l’application Symfony :

Pour préparer le projet, nous allons créer le projet, puis le connecter à notre base de données et ensuite nous allons créer deux entités pour la présentation.

Création du projet et configuration de la base de données :

Pour débuter ce projet, nous allons créer un nouveau projet Symfony 6 à l’aide de la commande suivante :

symfony new projet_administration --webapp

Puis on rentre dans le dossier du projet :

cd projet_administration

Ensuite nous allons modifier le fichier .env pour changer les accès à la base de données. J’utilise dans le cadre de cette procédure MariaDB (Installer Mariadb sur Debian 11).

DATABASE_URL="mysql://nom_utilisateur:mot_de_passe@127.0.0.1:3306/nom_bdd?serverVersion=version_mariadb&charset=utf8mb4"
   
avec mes valeurs 
   
DATABASE_URL="mysql://symfony:password@127.0.0.1:3306/projet_administration?serverVersion=mariadb-10.5.15&charset=utf8mb4"

Création de la base de données à l’aide de la CLI Symfony :

symfony console doctrine:database:create

Ou avec cette commande qui est plus courte :
	
symfony console d:d:c

Ensuite on importe Encore et Webpack :

composer require encore
composer require symfony/webpack-encore-bundle

Création de deux entités (Article et Catégories) dans l’application Symfony :

Pour créer l’entité article, si vous avez besoin de plus de détails, je vous invite à suivre cette procédure : Symfony 6 Créer une entité

On créer l’entité Categorie :

symfony console make:entity Categorie

# Ou 

symfony console m:e Categorie

Categorie :

  • id : int
  • nom : String (255)
  • active : Boolean
  • dateModification : DateTimeImmutable
  • dateCreation : DateTimeImmutable

Ensuite il faut répondre au questionnaire du script comme ci-dessous :

 created: src/Entity/Categorie.php
 created: src/Repository/CategorieRepository.php
 
 Entity generated! Now let's add some fields!
 You can always add more fields later manually or by re-running this command.

 New property name (press <return> to stop adding fields):
 > nom

 Field type (enter ? to see all types) [string]:
 > 

 Field length [255]:
 > 

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 

 updated: src/Entity/Categorie.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > active

 Field type (enter ? to see all types) [string]:
 > boolean

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 

 updated: src/Entity/Categorie.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > dateModification

 Field type (enter ? to see all types) [string]:
 > datetime_immutable

 Can this field be null in the database (nullable) (yes/no) [no]:
 > yes

 updated: src/Entity/Categorie.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > dateCreation

 Field type (enter ? to see all types) [string]:
 > datetime_immutable

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 

 updated: src/Entity/Categorie.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > 


           
  Success! 
           

 Next: When you're ready, create a migration with php bin/console make:migration
 

Pour créer l’entité Article nous allons saisir la commande suivant :

symfony console make:entity Article

# Ou 

symfony console m:e Article

Article :

  • id: int
  • titre : String (255)
  • contenu : Text
  • datePublication : DateTimeImmutable
  • dateModification : DateTimeImmutable
  • actif : Boolean
  • categorie : relation (Many To One)

Ensuite il faut répondre au questionnaire du script comme ci-dessous :

MODIFIER QUESTIONNAIRE ENTITE ARTICLE

 created: src/Entity/Article.php
 created: src/Repository/ArticleRepository.php
 
 Entity generated! Now let's add some fields!
 You can always add more fields later manually or by re-running this command.

 New property name (press <return> to stop adding fields):
 > titre 

 Field type (enter ? to see all types) [string]:
 > 

 Field length [255]:
 > 

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 

 updated: src/Entity/Article.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > contenu

 Field type (enter ? to see all types) [string]:
 > text

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 

 updated: src/Entity/Article.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > datePublication

 Field type (enter ? to see all types) [string]:
 > datetime_immutable

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 

 updated: src/Entity/Article.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 > dateModification

 Field type (enter ? to see all types) [string]:
 > datetime_immutable

 Can this field be null in the database (nullable) (yes/no) [no]:
 > yes

 updated: src/Entity/Article.php

 
New property name (press <return> to stop adding fields):
 > actif 

 Field type (enter ? to see all types) [string]:
 > boolean

 Can this field be null in the database (nullable) (yes/no) [no]:
 > 
 
New property name (press <return> to stop adding fields):
 > categorie

 Field type (enter ? to see all types) [string]:
 > relation

 What class should this entity be related to?:
 > Categorie

What type of relationship is this?
 ------------ ------------------------------------------------------------------------ 
  Type         Description                                                             
 ------------ ------------------------------------------------------------------------ 
  ManyToOne    Each Article relates to (has) one Categorie.                            
               Each Categorie can relate to (can have) many Article objects            
                                                                                       
  OneToMany    Each Article can relate to (can have) many Categorie objects.           
               Each Categorie relates to (has) one Article                             
                                                                                       
  ManyToMany   Each Article can relate to (can have) many Categorie objects.           
               Each Categorie can also relate to (can also have) many Article objects  
                                                                                       
  OneToOne     Each Article relates to (has) exactly one Categorie.                    
               Each Categorie also relates to (has) exactly one Article.               
 ------------ ------------------------------------------------------------------------ 

 Relation type? [ManyToOne, OneToMany, ManyToMany, OneToOne]:
 > ManyToOne

 Is the Article.categorie property allowed to be null (nullable)? (yes/no) [yes]:
 > no

 Do you want to add a new property to Categorie so that you can access/update Article objects from it - e.g. $categorie->getArticles()? (yes/no) [yes]:
 > 

 A new property will also be added to the Categorie class so that you can access the related Article objects from it.

 New field name inside Categorie [articles]:
 > 

 Do you want to activate orphanRemoval on your relationship?
 A Article is "orphaned" when it is removed from its related Categorie.
 e.g. $categorie->removeArticle($article)
 
 NOTE: If a Article may *change* from one Categorie to another, answer "no".

 Do you want to automatically delete orphaned App\Entity\Article objects (orphanRemoval)? (yes/no) [no]:
 > 

 updated: src/Entity/Article.php
 updated: src/Entity/Categorie.php

 Add another property? Enter the property name (or press <return> to stop adding fields):
 >   


           
  Success! 
           

 Next: When you're ready, create a migration with php bin/console make:migration

Une fois que les entitées ont étés créées, nous pouvons réalisé la migration vers la base de données :

symfony console make:migration 

Puis on migre les données :

symfony console d:m:m

Mise en place du menu d’administration EasyAdmin Symfony :

Pour créer notre dashboard d’administration nous avons besoin d’importer le Bundle EasyAdmin :

composer require easycorp/easyadmin-bundle

Puis création de menu d’administration :

symfony console make:admin:dashboard
 Which class name do you prefer for your Dashboard controller? [DashboardController]:
 > 

 In which directory of your project do you want to generate "DashboardController"? [src/Controller/Admin/]:
 > 


                                                                                
 [OK] Your dashboard class has been successfully generated.                     
                                                                                

 Next steps:
 * Configure your Dashboard at "src/Controller/Admin/DashboardController.php"
 * Run "make:admin:crud" to generate CRUD controllers and link them from the Dashboard.

Ensuite si vous démarrer votre serveur Symfony 6 vous pouvez allez consulter la route /admin :

symfony serve 
Symfony Menu d'administration avec EasyAdmin - Premier démarrage

Puis nous pouvons créer le CRUD (Create, Read, Update, Delete) :

symfony console make:admin:crud

Ensuite un questionnaire nous demande quelle Entité le CRUD doit gérer :

 Which Doctrine entity are you going to manage with this CRUD controller?:
  [0] App\Entity\Article
  [1] App\Entity\Categorie
 > 0

 Which directory do you want to generate the CRUD controller in? [src/Controller/Admin/]:
 > 

 Namespace of the generated CRUD controller [App\Controller\Admin]:
 > 

                                                                
 [OK] Your CRUD controller class has been successfully          
      generated.                                                
                                                                

 Next steps:
 * Configure your controller at "src/Controller/Admin/ArticleCrudController.php"
 * Read EasyAdmin docs: https://symfony.com/doc/master/bundles/EasyAdminBundle/index.html

Puis on refait la même étape pour créer le CRUD des catégories :

symfony console make:admin:crud
 Which Doctrine entity are you going to manage with this CRUD controller?:
  [0] App\Entity\Article
  [1] App\Entity\Categorie
 > 1

 Which directory do you want to generate the CRUD controller in? [src/Controller/Admin/]:
 > 

 Namespace of the generated CRUD controller [App\Controller\Admin]:
 > 

                                                                
 [OK] Your CRUD controller class has been successfully          
      generated.                                                
                                                                

 Next steps:
 * Configure your controller at "src/Controller/Admin/CategorieCrudController.php"
 * Read EasyAdmin docs: https://symfony.com/doc/master/bundles/EasyAdminBundle/index.html

Ensuite on installe les librairies :

npm install

Puis ensuite on compile avec NPM :

npm run build

Ajout du CRUD dans l’affiche de l’administration dans le fichier src/Controller/Admin/DashboardController.php :

<?php

namespace App\Controller\Admin;

use App\Entity\Article;
use App\Entity\Categorie;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use EasyCorp\Bundle\EasyAdminBundle\Config\Crud;
use EasyCorp\Bundle\EasyAdminBundle\Config\MenuItem;
use EasyCorp\Bundle\EasyAdminBundle\Config\Dashboard;
use EasyCorp\Bundle\EasyAdminBundle\Router\AdminUrlGenerator;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractDashboardController;

class DashboardController extends AbstractDashboardController
{

    public function __construct(
        private AdminUrlGenerator $adminUrlGenerator
    )
    {
    }

    #[Route('/admin', name: 'admin')]
    public function index(): Response
    {
        $url = $this->adminUrlGenerator
            ->setController(ArticleCrudController::class)
            ->generateUrl();

        return $this->redirect($url);
    }

    public function configureDashboard(): Dashboard
    {
        return Dashboard::new()
            ->setTitle('Projet Administration');
    }

    public function configureMenuItems(): iterable
    {      
        yield MenuItem::section('Blog');

        yield MenuItem::linkToDashboard('Dashboard', 'fa fa-home');

        yield MenuItem::section('Articles');

        yield MenuItem::subMenu('Actions', 'fas fa-bar')->setSubItems([
            MenuItem::linkToCrud('Create Article', 'fas fa-plus-circle', Article::class)->setAction(Crud::PAGE_NEW),
            MenuItem::linkToCrud('Show Articles', 'fas fa-eye', Article::class),
        ]);

        yield MenuItem::section('Categories');

        yield MenuItem::subMenu('Actions', 'fas fa-bar')->setSubItems([
            MenuItem::linkToCrud('Create Categorie', 'fas fa-plus-circle', Categorie::class)->setAction(Crud::PAGE_NEW),
            MenuItem::linkToCrud('Show Categories', 'fas fa-eye', Categorie::class),
        ]);
    }
}

Modification des champs dans le CRUD des Categories et le fonctionnement (src/Controller/CategorieCrudController.php) :

<?php

namespace App\Controller\Admin;

use App\Entity\Categorie;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;

class CategorieCrudController extends AbstractCrudController
{
    public static function getEntityFqcn(): string
    {
        return Categorie::class;
    }


    public function configureFields(string $pageName): iterable
    {
        return [
            IdField::new('id')->hideOnForm(),
            TextField::new('nom'),
            BooleanField::new('active'),
            DateTimeField::new('dateModification')->hideOnForm(),
            DateTimeField::new('dateCreation')->hideOnForm(),
        ];
    }

    public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
    {
        if (!$entityInstance instanceof Categorie) return;
        
        $entityInstance->setDateCreation(new \DateTimeImmutable());

        parent::persistEntity($entityManager, $entityInstance);
    }

    public function updateEntity(EntityManagerInterface $entityManager, $entityInstance):void
    {
        if (!$entityInstance instanceof Categorie) return;
        
        $entityInstance->setDateModification(new \DateTimeImmutable());

        parent::persistEntity($entityManager, $entityInstance);
    }
}

On refait la même opération pour le CRUD Article (src/Controller/Admin/ArticleCrudController.php) :

<?php

namespace App\Controller\Admin;

use App\Entity\Article;
use Doctrine\ORM\EntityManagerInterface;
use EasyCorp\Bundle\EasyAdminBundle\Field\IdField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Controller\AbstractCrudController;
use EasyCorp\Bundle\EasyAdminBundle\Field\AssociationField;

class ArticleCrudController extends AbstractCrudController
{
    public const ACTION_DUPLICATE = 'duplicate';

    public static function getEntityFqcn(): string
    {
        return Article::class;
    }
    
    public function configureFields(string $pageName): iterable
    {
        return [
            IdField::new('id')->hideOnForm(),
            TextField::new('titre'),
            TextField::new('contenu'),
            BooleanField::new('actif'),
            AssociationField::new('categorie'),
            DateTimeField::new('dateModification')->hideOnForm(),
            DateTimeField::new('datePublication')->hideOnForm(),
        ];
    }

    public function persistEntity(EntityManagerInterface $entityManager, $entityInstance): void
    {
        if (!$entityInstance instanceof Article) return;
        
        $entityInstance->setDatePublication(new \DateTimeImmutable());

        parent::persistEntity($entityManager, $entityInstance);
    }

    public function updateEntity(EntityManagerInterface $entityManager, $entityInstance):void
    {
        if (!$entityInstance instanceof Article) return;
        
        $entityInstance->setDateModification(new \DateTimeImmutable());

        parent::persistEntity($entityManager, $entityInstance);
    }
    
}

Ensuite dans l’entité Categorie ajouter la méthode suivant (__toString) qui va permettre d’afficher le nom de la catégorie lors de la recherche d’une categorie pour un article :

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

Enfin nous pouvons utilisé le crud depuis la route /admin :

Symfony Menu d'administration avec EasyAdmin - Administration

Sources :

https://symfony.com/bundles/EasyAdminBundle/current/index.html

Susceptible de vous intéresser :