Un squelette de framework mince basé sur des événements utilisant AMQP et CQRS
Le profil d'installation par défaut n'a aucun exemple. Vous devriez utiliser ce profil si vous savez ce qui se passe et que vous souhaitez commencer par une ardoise propre.
> composer create-project robiningelbrecht/php-slim-skeleton [app-name] --no-install --ignore-platform-reqs --stability=dev
# Build docker containers
> docker-compose up -d --build
# Install dependencies
> docker-compose run --rm php-cli composer installLe profil d'installation complet a un exemple de travail complet.
> composer create-project robiningelbrecht/php-slim-skeleton:dev-master-with-examples [app-name] --no-install --ignore-platform-reqs --stability=dev
# Build docker containers
> docker-compose up -d --build
# Install dependencies
> docker-compose run --rm php-cli composer install
# Initialize example
> docker-compose run --rm php-cli composer example:init
# Start consuming the voting example queue
> docker-compose run --rm php-cli bin/console app:amqp:consume add-vote-command-queue namespace App Controller ;
class UserOverviewRequestHandler
{
public function __construct (
private readonly UserOverviewRepository $ userOverviewRepository ,
) {
}
public function handle (
ServerRequestInterface $ request ,
ResponseInterface $ response ): ResponseInterface
{
$ users = $ this -> userOverviewRepository -> findonyBy ( /*...*/ );
$ response -> getBody ()-> write ( /*...*/ );
return $ response ;
}
} Rendez-vous sur config/routes.php et ajoutez un itinéraire pour votre demande de demande:
return function ( App $ app ) {
// Set default route strategy.
$ routeCollector = $ app -> getRouteCollector ();
$ routeCollector -> setDefaultInvocationStrategy ( new RequestResponseArgs ());
$ app -> get ( ' /user/overview ' , UserOverviewRequestHandler::class. ' :handle ' );
};Documentation complète
L'application de console utilise le composant de console Symfony pour tirer parti des fonctionnalités CLI.
#[AsCommand(name: ' app:user:create ' )]
class CreateUserConsoleCommand extends Command
{
protected function execute ( InputInterface $ input , OutputInterface $ output ): int
{
// ...
return Command:: SUCCESS ;
}
}Documentation complète
Le squelette vous permet d'utiliser des commandes et des gestionnaires de commandes pour effectuer des actions. Ces 2 viennent toujours en paires, lors de la création d'une nouvelle commande dans le modèle d'écriture, un gestionnaire de commandes correspondant doit également être créé.
namespace App Domain WriteModel User CreateUser ;
class CreateUser extends DomainCommand
{
} namespace App Domain WriteModel User CreateUser ;
#[AsCommandHandler]
class CreateUserCommandHandler implements CommandHandler
{
public function __construct (
) {
}
public function handle ( DomainCommand $ command ): void
{
assert ( $ command instanceof CreateUser);
// Do stuff.
}
}Documentation complète
L'idée de ce projet est que tout est ou peut être axé sur l'événement. L'approvisionnement en événement n'est pas fourni par défaut.
class UserWasCreated extends DomainEvent
{
public function __construct (
private UserId $ userId ,
) {
}
public function getUserId (): UserId
{
return $ this -> userId ;
}
} class User extends AggregateRoot
{
private function __construct (
private UserId $ userId ,
) {
}
public static function create (
UserId $ userId ,
): self {
$ user = new self ( $ userId );
$ user -> recordThat ( new UserWasCreated ( $ userId ));
return $ user ;
}
} class UserRepository extends DbalAggregateRootRepository
{
public function add ( User $ user ): void
{
$ this -> connection -> insert ( /*...*/ );
$ this -> publishEvents ( $ user -> getRecordedEvents ());
}
}#[AsEventListener(type: EventListenerType:: PROCESS_MANAGER )]
class UserNotificationManager extends ConventionBasedEventListener
{
public function reactToUserWasCreated ( UserWasCreated $ event ): void
{
// Send out some notifications.
}
}Documentation complète
L'implémentation AMQP choisie pour ce projet est RabbitMQ, mais il peut être facilement passé à la solution AMQP d'Amazon.
#[AsEventListener(type: EventListenerType:: PROCESS_MANAGER )]
class UserCommandQueue extends CommandQueue
{
} class YourService
{
public function __construct (
private readonly UserCommandQueue $ userCommandQueue
) {
}
public function aMethod (): void
{
$ this -> userCommandQueue -> queue ( new CreateUser ( /*...*/ ));
}
} > docker-compose run --rm php-cli bin/console app:amqp:consume user-command-queueDocumentation complète
Pour gérer les migrations de la base de données, le package Doctrine / Migrations est utilisé.
#[Entity]
class User extends AggregateRoot
{
private function __construct (
#[Id, Column(type: ' string ' , unique: true , nullable: false )]
private readonly UserId $ userId ,
#[Column(type: ' string ' , nullable: false )]
private readonly Name $ name ,
) {
}
// ...
}Vous pouvez faire en sorte que la doctrine génére une migration pour vous en comparant l'état actuel de votre schéma de base de données aux informations de cartographie définies à l'aide de l'ORM, puis exécutez cette migration.
> docker-compose run --rm php-cli vendor/bin/doctrine-migrations diff
> docker-compose run --rm php-cli vendor/bin/doctrine-migrations migrateDocumentation complète
Le modèle de moteur de choix pour ce projet est brindille et peut être utilisé pour rendre tout ce qui est lié à HTML.
< h1 >Users</ h1 >
< ul >
{% for user in users %}
< li >{{ user . username | e }}</ li >
{% endfor %}
</ ul > class UserOverviewRequestHandler
{
public function __construct (
private readonly Environment $ twig ,
) {
}
public function handle (
ServerRequestInterface $ request ,
ResponseInterface $ response ): ResponseInterface
{
$ template = $ this -> twig -> load ( ' users.html.twig ' );
$ response -> getBody ()-> write ( $ template -> render ( /*...*/ ));
return $ response ;
}
}Documentation complète
En savoir plus sur ces liens:
Veuillez consulter la contribution pour plus de détails.