Administrer une entité custom dans un back-office Sylius
Lorsqu’on utilise le formulaire de contact par défaut de Sylius, celui-ci se contente d’envoyer un e-mail sans enregistrer les informations en base de données.
Dans le cadre d’un projet, j’ai eu besoin d’aller plus loin en sauvegardant les contacts du site pour un suivi ultérieur. Pour cela, j’ai créé une entité personnalisée dédiée aux contacts, ainsi qu’une administration pour gérer ces données directement depuis le back-office de Sylius.
Dans cet article, je vais vous détailler chaque étape de ce processus et partager quelques erreurs que vous pourriez rencontrer en chemin.
Section intitulée 1-creer-l-entite-et-le-repository1. Créer l’entité et le repository
Pour cela, rien de plus simple avec MakerBundle :
bin/console make:entity
Class name of the entity to create or update (e.g. GrumpyGnome):
> Contact\Contact
Mark this class as an API Platform resource (expose a CRUD API for it) (yes/no) [no]:
> yes
created: src/Entity/Contact/Contact.php
created: src/Repository/Contact/ContactRepository.php
Entity generated! Now let's add some fields!
You can always add more fields later manually or by re-running this command.
L’entité Contact
et son repository ont ainsi été créées, rangées dans le dossier Contact pour rester bien organisées. J’ai ensuite ajouté les champs nécessaires (nom, email, message, date de création, etc.) à l’entité et mis en place un constructeur pour initialiser automatiquement la date de création lors de l’instanciation.
Section intitulée 2-mettre-a-jour-la-base-de-donnees2. Mettre à jour la base de données
Pour enregistrer cette nouvelle entité dans la base de données, il faut d’abord générer un fichier de migration, puis l’appliquer :
bin/console make:migration
bin/console doctrine:migrations:migrate
À ce stade, l’entité est fonctionnelle et permet l’enregistrement de nouveaux objets en base de données. Bien que cela nécessite également la création d’un FormType, d’un template et d’un contrôleur, ainsi que d’autres fichiers pour la partie front-end, je ne détaillerai pas cette partie dans cet article. L’étape suivante consiste à rendre cette entité accessible via l’interface d’administration.
Section intitulée 3-enregistrer-la-ressource-dans-la-config-sylius3. Enregistrer la ressource dans la config sylius
Il est maintenant nécessaire d’enregistrer l’entité dans la configuration Sylius pour qu’elle puisse être gérée en tant que ressource :
# config/packages/sylius_resource.yml
sylius_resource:
resources:
app.contact: # alias
driver: doctrine/orm
classes:
model: App\Entity\Contact\Contact
repository: App\Repository\ContactRepository
app.contact
correspond à l’alias de la ressource et sera utilisé pour la référencer dans les configurations à venir.
Section intitulée 4-configurer-les-routes-dans-l-admin4. Configurer les routes dans l’admin
Pour afficher les contacts dans le back-office, il faut d’abord configurer les routes nécessaires :
# config/routes.yaml
app_admin_contact:
resource: |
alias: app.contact
section: admin
templates: "@SyliusAdmin\\Crud"
vars:
all:
header: admin.ui.contact.header
subheader: admin.ui.contact.subheader
breadcrumb: admin.ui.contact.header
type: sylius.resource
prefix: /admin
Dans alias
, on va indiquer l’alias de la ressource qu’on a précédemment configurée.
admin.ui.contact.header
et admin.ui.contact.subheader
sont des clés de traduction utilisées dans les templates.
Avec cette configuration, Sylius va créer les routes suivantes :
app_admin_contact_index /admin/contacts/
app_admin_contact_create /admin/contacts/new
app_admin_contact_update /admin/contacts/{id}/edit
app_admin_contact_show /admin/contacts/{id}
app_admin_contact_bulk_delete /admin/contacts/bulk-delete
app_admin_contact_delete /admin/contacts/{id}
En allant sur /admin/contacts/
, on obtient maintenant une erreur 500 avec l’exception :
Neither the property "definition" nor one of the methods "definition()", "getdefinition()"/"isdefinition()"/"hasdefinition()" or "__call()" exist and have public access in class "Pagerfanta\Pagerfanta".
Cela est dû au fait que l’on n’a pas encore indiqué de grid à cette nouvelle configuration. Nous allons donc en créer une.
Section intitulée 5-creer-une-grid-make-grid5. Créer une grid (make:grid)
Une grid est un système de gestion des données d’une entité, permettant de définir la manière dont les informations seront présentées dans le tableau de listing de l’interface d’administration. Elle facilite l’affichage et la manipulation des données, en organisant leur présentation selon des critères que vous pouvez personnaliser pour répondre à vos besoins spécifiques.
On va de nouveau utiliser le MakerBundle de Symfony afin de générer cette grid :
php bin/console make:grid
Là, on doit choisir pour quelle entité on souhaite créer cette grid parmi la liste des entités de notre projet.
Cela générera un fichier PHP dans src/Grid/ContactsGrid.php
. La méthode getName()
retourne le nom de la grid, ici app_contact
. Il suffit ensuite de l’ajouter à la configuration précédente :
# config/routes.yaml
app_admin_contact:
resource: |
alias: app.contact
section: admin
templates: "@SyliusAdmin\\Crud"
+ grid: app_contact
vars:
all:
header: admin.ui.contact.header
subheader: admin.ui.contact.subheader
breadcrumb: admin.ui.contact.header
type: sylius.resource
prefix: /admin
Votre page de listing des contacts dans le back-office est maintenant fonctionnelle. Il ne reste plus qu’à intégrer cette page dans le menu. Pour ajouter l’entrée « Contacts » dans le menu de l’administration, il faut créer un MenuListener.
Section intitulée 6-configurer-le-menulistener6. Configurer le MenuListener
Le menu fonctionne en évènements. Nous allons donc créer une classe que je vais nommer ContactMenuListener
mais que vous pouvez appeler comme vous le souhaitez. Afin que Sylius prenne en compte ce listener dans la création du menu, l’important est de le lier à l’évènement sylius.menu.admin.main
dans la configuration de l’attribute.
Le fichier application/src/Menu/ContactMenuListener.php
ressemblera à ceci :
<?php
namespace App\Menu;
use Sylius\Bundle\UiBundle\Menu\Event\MenuBuilderEvent;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
#[AsEventListener(event: 'sylius.menu.admin.main', method: 'addContactMenuItems')]
final class ContactMenuListener
{
public function addContactMenuItems(MenuBuilderEvent $event): void
{
$menu = $event->getMenu();
$newSubmenu = $menu
// sous-menu
->addChild('app_admin_users')
->setLabel('Données utilisateurs')
;
$newSubmenu
// élément du sous-menu
->addChild('app_admin_users_contact', ['route' => 'app_admin_contact_index'])
->setLabel('Contacts')
->setLabelAttribute('icon', 'envelope outline')
;
}
}
La méthode addChild()
correspond à l’identifiant qu’on donne à l’item.
Pour les icônes, Sylius utilise semantic ui donc vous pouvez choisir l’icône souhaitée.
Ça donne ceci :
Et voici notre listing :
Mais voilà, il s’agit d’un listing de contacts, on ne veut ni les modifier, ni les supprimer, ni les créer. On souhaite uniquement les voir. On va devoir revenir sur notre grid.
Section intitulée 7-personnaliser-la-grid-et-les-actions-disponibles7. Personnaliser la grid et les actions disponibles
Dans le fichier généré, nous avons :
->addActionGroup(
MainActionGroup::create(
CreateAction::create(),
)
)
->addActionGroup(
ItemActionGroup::create(
// ShowAction::create(),
UpdateAction::create(),
DeleteAction::create()
)
)
->addActionGroup(
BulkActionGroup::create(
DeleteAction::create()
)
)
MainActionGroup
est le bouton qu’on a en vert tout en haut, le bouton global ;ItemActionGroup
actions possibles pour chaque item ;BulkActionGroup
est l’action globale qu’on souhaite faire sur les items qu’on aura sélectionné.
Il suffit de modifier les actions de la grid comme suit :
- ->addActionGroup(
- MainActionGroup::create(
- CreateAction::create(),
- )
- )
->addActionGroup(
ItemActionGroup::create(
- // ShowAction::create(),
- UpdateAction::create(),
- DeleteAction::create()
- )
- )
- ->addActionGroup(
- BulkActionGroup::create(
- DeleteAction::create()
+ ShowAction::create(),
)
)
Cela supprime les actions de modification et suppression, et conserve uniquement l’action « afficher » :
Si nous cliquons sur « Afficher », nous obtenons alors :
Unable to find template "@SyliusAdmin/Crud/show.html.twig" (looked into: /var/www/application/templates/bundles/SyliusAdminBundle, /var/www/application/vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/views).
Sylius n’a pas de template configuré pour l’action show (on comprend mieux pourquoi l’action est commentée par défaut dans la génération de la grid).
Note : Le template a été ajouté dans la version 2.0 de Sylius 🎉
Section intitulée 8-creer-un-template-d-affichage-show8. Créer un template d’affichage (show)
Pour gérer l’affichage des contacts dans le back-office, il faut créer un template spécifique. Voici un exemple de fichier application/templates/Admin/Crud/Contact/show.html.twig
:
{% extends '@SyliusAdmin/layout.html.twig' %}
{% set header = configuration.vars.header|default(metadata.applicationName~'.ui.show_'~metadata.name) %}
{% set event_prefix = metadata.applicationName ~ '.admin.' ~ metadata.name ~ '.show' %}
{% set index_url = path(
configuration.vars.index.route.name|default(configuration.getRouteName('index')),
configuration.vars.index.route.parameters|default(configuration.vars.route.parameters|default({}))
)
%}
{% block title %}{{ header|trans }} {{ parent() }}{% endblock %}
{% block content %}
<div class="ui stackable two column grid">
<div class="column">
{# Deux fichiers que j'ai créés #}
{% include 'Admin/Crud/Contact/_header.html.twig' %}
{% include 'Admin/Crud/Contact/_breadcrumb.html.twig' %}
</div>
</div>
<div class="ui segment">
<div class="ui stackable grid">
<div class="three column">
<div class="ui segment sylius-grid-table-wrapper">
<table class="ui very basic celled table">
<tbody>
<tr class="item">
<td class="two wide column">{{ 'admin.ui.show_contact.form.date'|trans}}</td>
<td>{{ resource.createdAt|date('d-m-Y à H:m') }}</td>
</tr>
<tr class="item">
<td>{{ 'admin.ui.show_contact.form.firstname'|trans}}</td>
<td>{{ resource.firstname }}</td>
</tr>
<tr class="item">
<td>{{ 'admin.ui.show_contact.form.lastname'|trans}}</td>
<td>{{ resource.lastname }}</td>
</tr>
<tr class="item">
<td>{{ 'admin.ui.show_contact.form.email'|trans}}</td>
<td>{{ resource.email }}</td>
</tr>
<tr class="item">
<td>{{ 'admin.ui.show_contact.form.phone'|trans}}</td>
<td>{{ resource.phone }}</td>
</tr>
<tr class="item">
<td>{{ 'admin.ui.show_contact.form.message'|trans}}</td>
<td>{{ resource.message }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
{% endblock %}
Pour ce fichier, je me suis appuyée sur application/vendor/sylius/sylius/src/Sylius/Bundle/AdminBundle/Resources/views/Crud/update.html.twig
.
Alors, maintenant, comment on indique qu’il faut utiliser ce template ?
On va devoir créer une nouvelle route
# config/routes.yaml
app_admin_contact_show:
path: /admin/contacts/{id}/show
methods: [GET]
defaults:
_controller: App\Controller\Admin\ContactController::showAction
_sylius:
section: admin
permission: true
redirect: referer
template: "/Admin/Crud/Contact/show.html.twig"
vars:
icon: eye
header: admin.ui.show_contact.header # override key message
breadcrumb: admin.ui.contact.header
On en profite pour supprimer les routes inutiles sur la configuration précédente avec l’option except
:
app_admin_contact:
resource: |
alias: app.contact
section: admin
templates: "@SyliusAdmin\\Crud"
grid: app_contact
except: ['create', 'show', 'update', 'delete']
vars:
all:
header: admin.ui.contact.header
subheader: admin.ui.contact.subheader
breadcrumb: admin.ui.contact.header
type: sylius.resource
prefix: /admin
Et dans la route de l’action show, on doit déclarer un nouveau contrôleur. Rien besoin de mettre dans cette classe à part qu’il étend ResourceController
et on l’ajoute à la config de la ressource :
sylius_resource:
resources:
app.contact: # alias
driver: doctrine/orm
classes:
controller: App\Controller\Admin\ContactController
model: App\Entity\Contact\Contact
repository: App\Repository\ContactRepository
Et voilà :
Section intitulée conclusionConclusion
En suivant ces étapes, vous avez créé une entité personnalisée « Contact », et l’avez intégrée au back-office de Sylius avec une gestion complète via une grid, des routes et une entrée dans le menu d’administration. Cette méthode est assez flexible, vous permettant d’ajouter facilement de nouvelles entités à votre projet Sylius. L’intégration des entités custom dans le back-office de Sylius peut sembler complexe au premier abord, mais grâce à la modularité de Sylius et l’utilisation de bundles comme le SyliusGridBundle, le processus est un peu plus rapide. Vous pouvez désormais étendre votre back-office avec de nouvelles entités en toute simplicité !
Commentaires et discussions
Ces clients ont profité de notre expertise
L’équipe de Finarta a fait appel à JoliCode pour le développement de leur plateforme Web. Basée sur le framework Symfony 2, l’application est un réseau privé de galerie et se veut être une place de communication et de vente d’oeuvres d’art entre ses membres. Pour cela, de nombreuses règles de droits ont été mises en places et une administration poussée…
Groupama Épargne Salariale digitalise son expérience client en leur permettant d’effectuer leurs versements d’épargne salariale en ligne. L’application offre aux entreprises une interface web claire et dynamique, composé d’un tunnel de versement complet : import des salariés via fichier Excel, rappel des contrats souscrits et des plans disponibles, …
Nous avons entrepris une refonte complète du site, initialement développé sur Drupal, dans le but de le consolider et de jeter les bases d’un avenir solide en adoptant Symfony. La plateforme est hautement sophistiquée et propose une pléthore de fonctionnalités, telles que la gestion des abonnements avec Stripe et Paypal, une API pour l’application…