Introduction
Depuis que j’ai commencé à travailler sur ce projet, une question revenait régulièrement dans mon esprit : comment pourrais-je, moi aussi, contribuer à l’écosystème open source ?
L’objectif n’a jamais été de créer un énième clone d’une solution existante. Au contraire, je souhaitais répondre à un besoin que je rencontre régulièrement dans mes projets : l’affichage d’un calendrier.
Lorsque l’on parle de calendrier dans une application web, il est difficile de ne pas penser à FullCalendar. C’est une bibliothèque extrêmement complète et reconnue, que j’apprécie beaucoup. Cependant, au fil de mes projets, je me suis souvent retrouvé face au même constat : pour de nombreux cas d’usage, j’avais simplement besoin d’afficher un calendrier avec quelques événements, sans embarquer toute la complexité et les contraintes qu’une solution aussi riche peut imposer.
C’est de cette réflexion qu’est né UX Calendar Bundle. Un bundle Symfony pensé pour répondre à un besoin simple : afficher un calendrier moderne, léger et facilement intégrable dans une application Symfony.
Dans cet article, je vais revenir sur les choix techniques qui ont guidé son développement, les contraintes rencontrées en cours de route et les compromis qu’il a fallu accepter. Parce qu’après tout, un projet parfait n’existe pas… et c’est probablement ce qui rend l’aventure encore plus intéressante.
Les choix techniques
Lorsqu’on développe un bundle destiné à l’écosystème Symfony, il est important de suivre les évolutions récentes du framework et de s’appuyer sur les outils modernes qu’il met à disposition.
C’est pour cette raison que UX Calendar Bundle est conçu pour être compatible avec Symfony 8. En contrepartie, il nécessite PHP 8.4 au minimum. Ce choix me permet de profiter des dernières fonctionnalités du langage et de maintenir une base de code moderne dès le départ.
Du côté de son architecture, cette première version s’appuie sur plusieurs briques de l’écosystème Symfony que j’apprécie particulièrement :
- AssetMapper pour la gestion des ressources front-end ;
- Stimulus pour l’interactivité côté client ;
- Turbo pour une expérience utilisateur plus fluide.
L’un des objectifs principaux du projet était de rester léger. Je ne voulais pas reproduire la complexité de certaines bibliothèques existantes, mais proposer une solution simple à intégrer dans une application Symfony.
Le bundle embarque ainsi un thème par défaut basé sur Bootstrap et s’intègre naturellement avec l’AssetMapper de l’application hôte. En pratique, il est possible de disposer d’un calendrier fonctionnel en seulement quelques minutes, sans configuration complexe ni dépendances lourdes.
Pour le développement quotidien, j’utilise le dépôt du bundle en parallèle d’un projet Symfony vierge servant de terrain d’expérimentation. Les deux sont reliés via un lien symbolique (symlink), ce qui me permet de visualiser instantanément les modifications apportées au bundle sans avoir à republier ou réinstaller celui-ci à chaque changement.
Enfin, certains choix techniques ont également été réalisés avec une vision plus long terme. L’objectif est de pouvoir, à terme, tirer parti de l’écosystème moderne de Symfony et de FrankenPHP. J’imagine notamment des fonctionnalités de mise à jour en temps réel via Mercure et les Server-Sent Events (SSE), permettant de rafraîchir automatiquement les événements du calendrier sans rechargement de page.
Nous n’en sommes pas encore là, mais l’architecture actuelle a été pensée pour rendre ces évolutions possibles dans les prochaines versions du bundle.
La promesse
Maintenant que nous avons vu les choix techniques, il reste la partie la plus importante : la promesse du bundle.
Lorsque je développe un outil, j’essaie toujours de me poser la même question : qu’est-ce que l’utilisateur gagne réellement ?
Dans le cas d’UX Calendar Bundle, la réponse est simple : pouvoir afficher rapidement un calendrier fonctionnel sans avoir à construire toute l’infrastructure autour.
Étant un grand utilisateur d’EasyAdmin, que je considère comme l’un des meilleurs bundles de l’écosystème Symfony pour la gestion d’un back-office, il me semblait naturel de proposer une intégration dédiée.
Le bundle est donc compatible avec EasyAdmin 4 et EasyAdmin 5 de manière optionnelle. Il ne s’agit pas d’une dépendance obligatoire : le calendrier fonctionne parfaitement sans EasyAdmin, mais si vous l’utilisez déjà dans votre projet, vous pouvez profiter d’une intégration prête à l’emploi.
L’objectif est de réduire au maximum le temps nécessaire pour mettre en place une gestion d’événements.
Dans la majorité des applications, un événement reste finalement un objet assez classique : un titre, une date de début, une date de fin, un statut ou encore une indication « toute la journée ». Pourquoi réinventer cette logique à chaque nouveau projet ?
Le bundle fournit ainsi un CRUD EasyAdmin complet permettant de gérer rapidement les événements depuis votre back-office. Une fois l’événement enregistré, aucune configuration supplémentaire n’est nécessaire : les routes du calendrier sont immédiatement disponibles.
Par exemple :
/events/2026/05
Cette URL affiche directement le calendrier du mois concerné avec les événements enregistrés depuis l’administration.
Autrement dit, le cycle complet devient extrêmement simple :
- Installer le bundle.
- Créer un événement dans EasyAdmin.
- Enregistrer.
- Consulter immédiatement le calendrier.
C’est précisément cette expérience « plug & play » que je souhaitais proposer.
Pour aller plus loin, l’intégration EasyAdmin fournit également plusieurs composants complémentaires :
- un CRUD dédié aux événements ;
- des filtres et outils de recherche ;
- des actions rapides pour ouvrir le calendrier ;
- un widget de tableau de bord affichant des statistiques et événements à venir ;
- un champ personnalisé permettant d’intégrer un mini-calendrier directement dans l’administration.
Bien entendu, cette première version possède encore quelques limites. Certaines fonctionnalités avancées nécessitent par exemple une adaptation lorsque l’on utilise une entité d’événement personnalisée. Mais l’objectif reste le même : offrir une base solide, simple à installer et suffisamment flexible pour évoluer avec les besoins des projets Symfony.
Pour illustrer cette philosophie, voici le résultat obtenu après la création d’un simple événement depuis EasyAdmin.
Quelques clics suffisent pour créer l’événement dans le back-office, puis le calendrier devient immédiatement accessible via les routes fournies par le bundle. Aucun JavaScript complexe à configurer, aucune intégration externe à mettre en place, simplement un calendrier fonctionnel directement exploitable dans une application Symfony.
Dans l’exemple ci-dessous, un événement créé dans l’administration apparaît automatiquement dans la vue mensuelle du calendrier.
C’est probablement l’aspect dont je suis le plus satisfait dans cette première version : la simplicité du parcours. On passe de zéro à un calendrier opérationnel en quelques minutes, tout en conservant la possibilité d’étendre le comportement selon les besoins du projet.
Répondre à des besoins spécifiques sans imposer de contraintes
L’un des principes qui a guidé le développement du bundle est assez simple : je n’aime pas les outils qui enferment les développeurs dans une seule manière de faire.
Trop souvent, certaines solutions deviennent difficiles à adapter dès que l’on sort du cas d’usage prévu initialement. On se retrouve alors à contourner le fonctionnement du composant plutôt qu’à l’utiliser.
Pour cette première version, je voulais prendre la direction inverse.
Bien sûr, le bundle est livré avec une configuration prête à l’emploi permettant de disposer rapidement d’un calendrier fonctionnel. Mais derrière cette simplicité apparente se cache un important niveau de personnalisation.
Les développeurs peuvent ainsi choisir d’utiliser l’entité Event fournie par défaut ou implémenter leurs propres modèles métier grâce aux contrats CalendarEventInterface et CalendarEventRepositoryInterface. Pour faciliter cette approche, un CalendarEventTrait est également disponible afin de réutiliser le mapping Doctrine commun sans repartir de zéro.
L’interface utilisateur n’est pas en reste. Le bundle propose plusieurs modes d’affichage adaptés à différents besoins :
- vue mensuelle ;
- vue hebdomadaire ;
- vue journalière ;
- navigation intégrée entre les différentes périodes ;
- mises à jour dynamiques via Turbo Streams ;
- affichage horaire complet de 0h à 23h ;
- gestion des événements sur une journée entière.
Les opérations classiques sont également prises en charge nativement : création, modification, suppression ou encore exclusion ponctuelle d’occurrences pour les événements récurrents.
J’ai également souhaité laisser une grande liberté concernant l’intégration visuelle. Un thème Bootstrap est fourni par défaut afin d’obtenir rapidement un résultat cohérent, mais d’autres variantes sont disponibles, notamment une intégration adaptée à Tailwind CSS ainsi qu’un mécanisme de détection automatique selon l’environnement utilisé.
Du côté de l’administration, l’intégration EasyAdmin reste totalement optionnelle. Les développeurs qui le souhaitent peuvent profiter d’un CRUD dédié, d’un widget de tableau de bord et d’un champ calendrier personnalisé, tandis que les autres peuvent conserver leur propre système d’administration.
Même la route principale du calendrier reste configurable. Le bundle utilise /events par défaut, mais quelques lignes de configuration suffisent pour adopter une autre convention, comme /calendar.
Finalement, la promesse de cette première version n’est pas seulement de fournir un calendrier fonctionnel. Elle consiste surtout à offrir une base solide qui peut être utilisée immédiatement tout en restant suffisamment ouverte pour s’adapter aux contraintes spécifiques de chaque projet Symfony.
Une interface réactive grâce à Turbo Streams
L’un des aspects que je souhaitais particulièrement soigner était l’expérience utilisateur.
Créer un événement est une chose, mais pouvoir le modifier rapidement sans recharger constamment la page en est une autre.
C’est là que les choix réalisés autour de Turbo prennent tout leur sens.
Lorsqu’un utilisateur clique sur un événement présent dans le calendrier, une fenêtre d’édition s’ouvre directement au-dessus de la vue courante. Les informations de l’événement peuvent être modifiées immédiatement : titre, dates, description, couleur ou encore statut « toute la journée ».
Une fois les modifications enregistrées, le calendrier est automatiquement mis à jour grâce aux Turbo Streams.
Aucun rechargement de page n’est nécessaire.
L’événement est rafraîchi directement dans l’interface, ce qui permet de conserver le contexte de navigation tout en offrant une expérience beaucoup plus fluide.
Dans l’exemple ci-dessous, un événement s’étendant sur plusieurs jours est modifié depuis une fenêtre modale. Après validation, les changements sont instantanément répercutés dans la vue mensuelle du calendrier.
Cette approche s’inscrit parfaitement dans la philosophie du bundle : proposer une expérience moderne basée sur les outils de l’écosystème Symfony sans imposer de dépendances JavaScript complexes ou une architecture front-end lourde.
Et maintenant ?
Publier un bundle Symfony est une première étape. Le maintenir, le faire évoluer et écouter les usages réels en est une autre.
Pour cette première version, UX Calendar Bundle pose les bases : un calendrier fonctionnel, une intégration EasyAdmin optionnelle, des vues mois, semaine et jour, ainsi qu’une architecture suffisamment ouverte pour être personnalisée.
Mais évidemment, le projet ne va pas s’arrêter là.
Parmi les pistes d’évolution, j’aimerais notamment faciliter encore davantage la création d’événements côté applicatif. Par exemple, permettre à un développeur de créer simplement des événements depuis ses propres services métier, comme un stand-up hebdomadaire, une réservation, un rendez-vous client ou un événement sur une journée complète.
L’idée est de rendre le bundle aussi agréable à utiliser dans le code qu’il l’est côté interface.
À terme, j’aimerais également travailler sur une intégration Symfony Flex afin de simplifier encore l’installation et la configuration initiale. L’objectif serait d’offrir une expérience vraiment progressive : installer le bundle, appliquer une recette, configurer les routes, publier les assets et obtenir un calendrier prêt à l’emploi en quelques commandes.
Une autre piste intéressante serait d’utiliser le composant Console de Symfony pour proposer un assistant d’installation interactif. Celui-ci pourrait guider le développeur étape par étape selon ses besoins :
- utiliser l’entité
Eventfournie par défaut ; - configurer une entité personnalisée ;
- activer ou non l’intégration EasyAdmin ;
- choisir le thème visuel ;
- définir la route principale du calendrier.
Ce type d’installation progressive permettrait de garder la philosophie du bundle : simple pour démarrer, mais suffisamment flexible pour les projets plus avancés.
Bien sûr, ces évolutions dépendront aussi des retours de la communauté. Un bundle open source ne vit pas uniquement à travers son code, mais aussi grâce aux usages, aux issues, aux propositions d’amélioration et aux contributions.
C’est probablement la partie la plus intéressante maintenant : voir comment d’autres développeurs Symfony vont s’approprier le projet, le tester, le détourner, le pousser dans ses limites et, je l’espère, contribuer à le faire évoluer.
Créer des événements depuis ses propres services
Même si le bundle fournit une interface complète pour gérer les événements, je tenais également à ce qu’il puisse s’intégrer naturellement dans le code métier d’une application Symfony.
Dans la réalité d’un projet, les événements ne sont pas toujours créés manuellement depuis une interface d’administration.
Ils peuvent être générés automatiquement suite à une réservation, la validation d’une commande, la création d’un rendez-vous ou encore lors de l’exécution d’un traitement planifié.
C’est pourquoi le bundle expose une API simple permettant de manipuler les événements directement depuis vos services Symfony.
Par exemple, imaginons la création automatique d’un stand-up hebdomadaire :
<?php
namespace App\Service;
use JeanSebastienChristophe\CalendarBundle\Entity\Event;
use JeanSebastienChristophe\CalendarBundle\Repository\EventRepository;
class EventManager
{
public function __construct(
private readonly EventRepository $eventRepository
) {
}
public function createWeeklyMeeting(): Event
{
$event = new Event();
$event->setTitle('Stand-up hebdomadaire')
->setStartDate(new \DateTime('next monday 09:00'))
->setEndDate(new \DateTime('next monday 09:30'))
->setColor('#3788d8');
$this->eventRepository->save($event);
return $event;
}
}
Le même principe peut être utilisé pour générer automatiquement des événements sur une journée complète, des échéances de projets, des rendez-vous clients ou tout autre besoin métier spécifique.
Cette approche était importante pour moi dès la première version. Je ne voulais pas créer uniquement un composant d’affichage, mais également une brique réutilisable capable de s’intégrer facilement dans l’écosystème métier d’une application Symfony.
À terme, j’aimerais même aller plus loin en proposant des helpers ou des services dédiés pour simplifier certains cas d’usage fréquents, comme la création d’événements récurrents, la gestion des exclusions de dates ou encore la synchronisation avec des systèmes externes.
L’objectif reste toujours le même : fournir une base solide qui puisse servir aussi bien à un simple calendrier qu’à des applications métier plus ambitieuses.
Une installation en quelques secondes
L’un des objectifs de cette première version était également de proposer une expérience d’installation la plus simple possible.
Grâce à Composer et à la recette Symfony associée au bundle, l’intégration se fait en quelques secondes :
composer require jean-sebastien-christophe/ux-calendar-bundle
Avec Symfony Flex, les bundles Symfony requis sont activés automatiquement. Il reste ensuite quelques étapes à réaliser côté application pour disposer d’un calendrier fonctionnel.
Déclarez les routes du bundle dans config/routes/calendar.yaml :
calendar_bundle:
resource: '@CalendarBundle/src/Controller/'
type: attributeCréez et appliquez la migration Doctrine pour la table des événements :
php bin/console make:migration
php bin/console doctrine:migrations:migrateUne fois ces étapes réalisées, le calendrier est accessible sur /events (ou la route que vous aurez configurée). Les assets CSS sont exposés directement via AssetMapper, sans commande assets:install.
Enfin, copiez le contrôleur Stimulus du bundle dans votre application et enregistrez-le :
cp vendor/jean-sebastien-christophe/ux-calendar-bundle/assets/dist/controllers/calendar_controller.js assets/controllers/// assets/app.js
import CalendarController from './controllers/calendar_controller.js';
const app = startStimulusApp();
app.register('calendar', CalendarController);Une fois ces étapes réalisées, le calendrier est accessible sur /events (ou la route que vous aurez configurée). Les assets CSS sont exposés directement via AssetMapper, sans commande assets:install.
Pour cette première version, j’ai volontairement gardé une installation explicite. Une recette Symfony Flex pour automatiser la déclaration des routes et l’enregistrement du contrôleur fait partie des évolutions prévues — c’est précisément le genre de friction que je souhaite réduire dans les prochaines versions.
Voir apparaître cette sortie dans mon terminal a été un petit moment particulier. C’est probablement le genre de détail qui ne représente pas grand-chose pour les utilisateurs, mais lorsqu’il s’agit de son premier bundle publié, voir son package être téléchargé, installé et configuré automatiquement procure une certaine satisfaction.
C’est à ce moment-là que le projet cesse réellement d’être un dépôt GitHub personnel pour devenir un package utilisable par toute la communauté Symfony.
Conclusion
C’est avec beaucoup de joie, mais aussi une certaine dose de stress, que je propose aujourd’hui ce premier bundle à la communauté Symfony.
Comme tout projet open source, il est loin d’être parfait. Il y a certainement des améliorations à apporter, des bugs à corriger, des fonctionnalités à imaginer et des choix techniques qui évolueront avec le temps. Mais il fallait bien commencer quelque part.
Mon objectif est simple : proposer un outil utile aux développeurs qui souhaitent intégrer rapidement un calendrier dans leurs applications Symfony sans passer des heures à réinventer des fonctionnalités déjà connues.
Au-delà du bundle lui-même, ce projet est aussi une façon de contribuer, à mon échelle, à un écosystème qui m’a énormément apporté au fil des années.
Symfony continue de me surprendre par sa capacité à simplifier le développement moderne. Les composants UX ont clairement participé à renouveler mon intérêt pour le développement front-end. Je me souviens encore de ma découverte de Symfony UX Live Components : voir des interfaces réactives se construire avec une telle simplicité m’avait réellement impressionné. Cette philosophie centrée sur l’expérience développeur (DX) et l’expérience utilisateur (UX) a fortement influencé la conception de ce bundle.
La suite dépendra maintenant de ses utilisateurs.
J’espère que certains y trouveront une base solide pour leurs projets, que d’autres proposeront des idées d’amélioration, et que quelques passionnés auront même envie de contribuer directement au code.
Les retours, les issues, les pull requests et les discussions sont les bienvenus. C’est aussi ça la force de l’open source : faire évoluer un projet grâce aux expériences et aux besoins de toute une communauté.
Et si jamais vous décidez de rejoindre l’aventure pour maintenir ou faire évoluer le bundle, sachez que vous êtes les bienvenus. En revanche, je préfère vous prévenir : vu la liste d’idées que j’ai déjà en tête pour les prochaines versions, il faudra probablement s’accrocher un peu !