rxthunder/skeleton

Fork & Play repository, production grade, of event driven CLI micro framework with Reactive Programming flavors

1.0.0 2020-01-10 14:07 UTC

This package is auto-updated.

Last update: 2024-10-11 00:19:12 UTC


README

License License

About Thunder CLI μFramework

This repository is the scaffold of the Thunder CLI micro-framework.

You can use it and modify the structure to adapt on your needs.

Philosophy

Sometimes you just need a very simple deamon, eventloop based, when you're event programming. A small repository for your boundary, with few dependencies, and don't want to be force to use a library or an other.

All you need is a reaction to an event that has been occurred in your system, externally or internally (pub/sub or saga f.e.).

However, this project is born inside a repository using Reactive Programming by default, RabbitMQ consumers, a router, EventStore projections and events, mysql, Redis connectors, and many more.

Simple but powerful.

What built in

Console Component

The whole concept is based on consoles. Instead of reinvent the wheel, Thunder use Silly micro-framework. A Console class being provided by the framework, allowing classes that extend it to be automatically loaded and usable.

Dependency Injection

Usage of the dependency injection pattern, ease decoupling your code and quality test writing. Symfony DI component has been chosen for it many features improving developer experience.

Configuration Component

This component allows you to use XML, YAML & PHP files. You can access and use them directly into constructors through DI.

Router

This component is central in the project, Command Bus and Event Dispatcher pattern aren't adapted to non acknowledge (nack) messages.

It's pretty straight forward, a Route can be associated to a Controller in a MVC schema. The core provide a base class called Route that allow to automatically load all classes extending it in the Router.

Each route have to define it's constant called PATH. It's used to determine which Route of your application must be invoked.

As we are in an event driven framework, all Route must return an Observable. The different plugins that you will use in your application, are subscribing to your Observable using Observers to determine actions to execute at the end of your event chain.

Installation

composer create-project rxthunder/skeleton name-of-your-project

Usage

Console

At the begining, there is a console. CLI for Command Line Interface.

To start the project you need to execute a PHP file available in the vendors, vendor/bin/thunder.

All commands available will be prompted.

Create a new Route

Create a class extending Th3Mouk\Thunder\Router\Route into /src and it will be automatically added to the router.

You can modify the config/services.php and composer.json autoload if you don't want to use src folder.

Your Route will now be invoked with the corresponding DataModel through the PATH constant.

Extra: Handler concept

I personally use src/route and src/handler structure. The term handler coming from the Command Bus pattern.

An handler here, is a small invokable unit that can be reused in multiple contexts, sagas of events, or here again routes. The main advantage of this, is you can decouple your code and test it correctly, because yes, this handler will be automatically injected in the container, and you can use DI in its constructor 🎉.

An example can be:

// src/Handler/PromptHello.php
namespace App\Handler;

use Rx\Observable;
use RxThunder\Core\Model\DataModel;

class PromptHello
{
    public function __invoke(DataModel $data_model)
    {
        return Observable::of($data_model)
            ->do(function() {
                echo "hello there". PHP_EOL;
            });
    }
}

And finally you can use this unit in your route:

// src/Route/Test.php
namespace App\Route;

use App\Handler\PromptHello;
use Rx\Observable;
use RxThunder\Core\Model\DataModel;
use RxThunder\Core\Router\Route;

class Test extends Route
{
    public const PATH = '/test';

    private $prompt;

    public function __construct(
        PromptHello $prompt
    ) {
        $this->prompt = $prompt;
    }

    public function __invoke(DataModel $data_model): Observable
    {
        return Observable::of($data_model)
            ->do(function () {
                echo "i'm in /test".PHP_EOL;
            })
            ->flatMap($this->prompt)
            ->do(function () {
                echo "passed in /test".PHP_EOL;
            });
    }
}

Start consuming

If you use the RabbitMQ plugin you can start consuming a queue with php console rabbit:listen:broker test (test is the name of the queue to consume)

Each message received by the queue will be transformed into a DataModel and the routing key correspond to the type() of it.

For example a message with /test routing key in RabbitMQ will be consumed by the route with public const PATH = '/test';