Aller au contenu

tilttek/activity

✅ publié

Ce que vos membres ont fait, enregistré une seule fois, pour que les points, les badges et les quêtes le comptent tous de la même façon.

tilttek/activity tient un journal des gestes des membres : ce membre a fait ce geste, sur cet objet, à ce moment. L'application enregistre chaque geste avec une clé d'idempotence. Un écouteur qui s'exécute deux fois ou une tâche relancée ne le compte donc jamais deux fois. Elle annule un geste défait — une commande remboursée, un commentaire retiré — par une entrée distincte, jamais en réécrivant le journal. Les lecteurs comptent le contenu du journal par membre, verbe, objet et période. Les projections y tiennent leurs propres totaux à jour, puis le rejouent quand une règle change. Effacer un membre supprime ses gestes et l'oublie comme objet des gestes des autres. La bibliothèque n'attribue ni points, ni badges, ni niveaux, et ne conserve jamais un texte écrit par le membre : les paquets qui récompensent les gestes lisent ce journal, et un commentaire est référencé, pas copié.

Elle s'adresse à une application qui récompense ce que font ses membres — un site communautaire, le programme de fidélité d'une boutique, un site de jeux — et qui veut que chaque récompense vienne d'un seul registre, relisible. tilttek/activity-bundle l'intègre à Symfony et garde le journal dans Doctrine DBAL. Une application sans Symfony prend la bibliothèque seule et écrit son propre ActivityLog, ou utilise celui en mémoire.

C'est une bibliothèque PHP simple. Ses seules dépendances sont phil/resource, la référence opaque d'un membre ou d'un objet, et psr/clock, l'horloge qui date chaque entrée. Les membres sont des références que donne l'application, member:44 : la bibliothèque ne lit jamais un nom, un courriel ou un compte.

La conception est petite : une Activity est un fait. Un Journal enregistre, annule, lit et compte des activités par un ActivityLog. Un Filter choisit des activités. Une Projection tient un état dérivé, à laquelle un Projector remet les entrées qu'elle n'a pas vues, avec un point de reprise gardé dans Checkpoints.

État

PartieÉtat
Activity, Verb, VerbPattern, IdempotencyKey, Context : le fait et ses parties validéesImplémenté et testé
Journal : enregistrement unique par clé, annulation unique, verbes déclarés, observateurs avertis des nouvelles entréesImplémenté et testé
ActivityLog et InMemoryActivityLog : ajout, annulation, lecture par un filtre, totaux, effacementImplémenté et testé
Filter : membre, verbes par motif, objet, périodeImplémenté et testé
Projections : Projector avec points de reprise et lots, reconstruction d'une période, LiveProjections, ProjectionsImplémenté et testé
Exceptions sous une seule interface ActivityExceptionImplémenté et testé

Documentation

DocumentCe qu'il couvre
InstallationLes prérequis et l'installation.
Enregistrer l'activitéLes activités, les verbes, les clés, le contexte, les annulations, les verbes déclarés et les observateurs.
Lire et compterLes filtres, les positions, les lectures dans l'ordre et les totaux.
ProjectionsL'état dérivé tenu à jour, les points de reprise, les lots, les reconstructions et les projections en direct.
EffacementCe qu'efface la suppression d'un membre et ce qu'elle garde.
Écrire un journalLe contrat ActivityLog qu'implémente le stockage d'une application.
Points d'extensionCe qu'une application fournit à la bibliothèque : le journal, les projections, les points de reprise, les observateurs, l'horloge.
ExceptionsActivityException et ses exceptions, avec leurs messages.
TestsLes tests de la bibliothèque et son seuil de mutation, et comment tester du code qui enregistre de l'activité.
RéférenceChaque type de la bibliothèque, avec son rôle.

Démarrage rapide

composer require tilttek/activity
use Symfony\Component\Clock\NativeClock;
use Tilttek\Activity\Activity;
use Tilttek\Activity\Filter;
use Tilttek\Activity\Journal;
use Tilttek\Activity\Log\InMemoryActivityLog;
use Phil\Resource\ResourceReference;

$journal = new Journal(new InMemoryActivityLog(), new NativeClock());

$journal->record(Activity::of('game:812:player:44', 'member:44', 'game.played', $playedAt, 'game:812'));
$journal->record(Activity::of('game:812:player:44', 'member:44', 'game.played', $playedAt, 'game:812')); // counted once

$journal->totals(Filter::all()->member(ResourceReference::of('member', '44'))->verbs('game.*'))->count; // 1
$journal->cancel('game:812:player:44');

Prérequis

PHP 8.5 ou plus récent.

Contribuer

Les contributions sont les bienvenues sur le monodépôt de PHIL : lisez le guide de contribution et le code de conduite. 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.