Aller au contenu

tilttek/advent-calendar

✅ publié

Un calendrier de l'Avent : une case par jour, une surprise par case, et un jour manqué qui n'est pas perdu.

tilttek/advent-calendar tient des calendriers de l'Avent pour les membres d'un site. Un calendrier a une case pour chaque jour à partir de sa première date — vingt-quatre en décembre, douze, ou tout nombre jusqu'à quatre-vingt-douze — et une surprise par case. Une surprise est une référence à une récompense que l'application accorde : un montant de points, un insigne, un contenu, un code tiré d'une réserve. Les jours se comptent dans le fuseau horaire du calendrier, à travers les changements d'heure. Chaque calendrier déclare combien de temps une case reste ouvrable une fois son jour venu : par défaut jusqu'à la fermeture du calendrier, de sorte qu'un membre qui a manqué un jour ouvre sa case plus tard sans la perdre ; le jour même seulement ; ou pour quelques jours de rattrapage. Aucune case ne s'ouvre avant son jour. L'ouverture est idempotente : la première ouverture est enregistrée et envoyée comme un événement à partir duquel l'application accorde la surprise, et rouvrir la case répond la même ouverture et n'accorde rien deux fois, même quand deux requêtes se font concurrence. Chaque membre voit les cases dans leur état — verrouillée, ouvrable, ouverte, manquée —, et une case non ouverte ne révèle jamais sa surprise. Effacer un membre supprime ses ouvertures.

Il s'adresse à une communauté ou à une boutique qui veut un rituel saisonnier sans pression : rien à acheter, aucune case qui disparaît par défaut, aucun classement de ceux qui ont ouvert en premier. Les récompenses restent dans l'application, qui sait déjà créditer des points ou décerner un insigne ; le calendrier dit seulement quand.

C'est une bibliothèque PHP simple dont les dépendances sont phil/resource, la référence opaque d'un membre, psr/clock, l'horloge où se lisent les jours, et psr/event-dispatcher, qui porte les ouvertures jusqu'à l'application. Les membres sont des références que donne l'application, member:44 : la bibliothèque ne lit jamais un nom, un courriel ni un compte.

La conception est petite : un Calendar tient les Surprise de ses cases, son fuseau horaire, son OpeningPolicy et sa fermeture, et donne à chaque case son OpeningWindow ; AdventCalendar ouvre une case pour un membre, enregistre l'Opening dans un OpeningStore, envoie BoxOpened une seule fois et montre les cases comme des BoxView.

État

PartieÉtat
Calendar : des cases par jour à partir d'une première date, dans un fuseau horaire, fermant à la dernière case ou plus tardImplémenté et testé
Surprise, SurpriseKind : des points, un insigne, un contenu ou un code, comme référencesImplémenté et testé
OpeningPolicy, PolicyKind, OpeningWindow : jusqu'à la fermeture par défaut, le jour même, ou un rattrapage de 1 à 31 joursImplémenté et testé
AdventCalendar : ouvertures idempotentes, cases telles qu'un membre les voit, effacementImplémenté et testé
BoxOpened : la première ouverture annoncée une fois, avec une clé pour un octroi idempotentImplémenté et testé
OpeningStore, InMemoryOpeningStore : les ouvertures, avec le contrat que réussit tout magasinImplémenté et testé
Exceptions sous une seule interface AdventCalendarExceptionImplémenté et testé

Documentation

DocumentContenu
InstallationLes prérequis, l'installation et le branchement de la bibliothèque.
Calendriers et politiquesLes cases, les surprises, les fuseaux horaires, les changements d'heure, les politiques d'ouverture et la fermeture.
Ouvrir les casesOuvrir une fois, accorder la surprise, les cases qu'un membre voit, célébrer et effacer.
Écrire un magasinLe contrat qu'implémente le stockage des ouvertures d'une application.
Points d'extensionCe qu'une application donne à la bibliothèque : le magasin, l'horloge, le répartiteur.
ExceptionsAdventCalendarException et ses exceptions, avec leurs messages.
TestsLes tests de la bibliothèque et son seuil de mutation, et comment tester du code qui ouvre des cases.
RéférenceChaque type de la bibliothèque, avec son rôle.

Démarrage rapide

composer require tilttek/advent-calendar
use Phil\Resource\ResourceReference;
use Symfony\Component\Clock\Clock;
use Tilttek\AdventCalendar\{AdventCalendar, Calendar, Surprise};
use Tilttek\AdventCalendar\Store\InMemoryOpeningStore;

$surprises = [];

for ($day = 1; $day <= 24; ++$day) {
    $surprises[] = 0 === $day % 6 ? Surprise::badge('advent-week') : Surprise::points(10);
}

$calendar = Calendar::of('advent-2026', 'America/Toronto', '2026-12-01', $surprises);
$advent = new AdventCalendar(new InMemoryOpeningStore(), new Clock(), $dispatcher);

$opened = $advent->open($calendar, ResourceReference::of('member', '44'), 3);
$opened->first;        // true the first time: BoxOpened was dispatched
$opened->surprise;     // Surprise::points(10)

Prérequis

PHP 8.5 ou une version plus récente.

Contribuer

Les contributions sont les bienvenues sur le monodépôt de PHIL : lisez le guide de contribution et le code de conduite, en anglais. Signalez une vulnérabilité en privé, comme l'explique la politique de sécurité, jamais dans un ticket public.

Licence

MIT, © Philippe Gamache, doing business as Le Gnome Archiviste; a Tilttek project. Voir LICENSE.