/pipolino

A immutable dispatcher to process values in sequence.

Primary LanguagePHPMIT LicenseMIT

Pipolino

Build Status Scrutinizer Code Quality Code Coverage Packagist license php

The package provides dispatcher that can be used to process one or more values in sequence. It is a combination of thephpleague/pipeline and PSR-7 middleware dispatcher (eg. Relay).

Installation

composer require phuria/pipolino

Usage

$pipolino = (new Pipolino())
    ->addStage(function(callable $next, $payload) {
        return $next($payload * 2); // 20 * 2
    })
    ->addStage(function (callable $next, $payload) {
        return $next($payload + 1); // 40 + 1
    })
    ->addStage(function (callable $next, $payload) {
        return $next($payload / 10); // 41 / 10
    });

echo $pipolino->process(20); //output: 4.1

Immutable

Pipolino are implemented as immutable. Any change on object (eg. add new stage) creates new object.

Stage objects

Object can be used as a stage. It must have only implemented __invoke method.

class CacheStage
{
    private $cache;
    
    public function __construct(CacheInterface $cache)
    {
        $this->cache = $cache;
    }
    
    public function __invoke(callable $next, $result, array $criteria)
    {
        $hash = sha1(serialize($criteria));
        
        if ($this->cache->has($hash)) {
            return $this->cache->get($hash);
        }
        
        $result = $next($result, $criteria);
        $this->cache->set($hash, $result, 3600);
        
        return $result;
    }
}

Many arguments

Pipolino (in contrast to pipeline) accepts any number of arguments to process.

$pipolino = (new Pipolino)
    ->addStage(function (callable $next, $result, array $options) {
        if (null === $result) {
            return $options['onNull'];
        }
    
        return $next($result, $context);
    })
    ->addStage(function (callable $next, $result, array $options) {
        $formatted = $next(number_format($result, 2).' '.$options['currency'])
    
        // Can be replaced with: "return $forrmated;",
        // however, should call $next().
        return $next($formatted, $options); 
    });

$options = ['onNull' => '-', 'currency' => 'USD'];

echo $pipolino->process(null, $options); // output: -
echo $pipolino->process(10, $options); // output: 10.00 USD

Pipolino composite

Each pipolino can be used as stage. This allows for easy re-use pipolino.

$loadingProcess = (new Pipolino())
    ->add(new CheckCache())
    ->add(new LoadFromDB());
    
$showProcces = (new Pipolino())
    ->add(new JsonFormat())
    ->add($loadingProccess)
    ->add(new NullResult());

Default stage

Default stage is last stage in pipolino, and does not accept $next callable as first argument. If you need to alter behavior of default stage (return first argument) call Pipolino::withDefaultStage() method.

$pipolino = (new Pipolino)
    ->addStage(function (callable $net, $i) {
        if (is_string($i)) {
            $i = (int) $i;
        }
        
        return $next($i);
    })
    ->addStage(function (callable $next, $i) {
        if (is_int($i)) {
            return $i % 2 ? 'even' : 'odd';
        }
        
        return $next($i);
    })
    ->withDefaultStage(function () {
        throw new \Exception('Unable to guess type.');
    });
    
echo $pipolino->process(2); // output: even
echo $pipolino->process('4'); // output: even
echo $pipolino->proccess(2.50); // throws exception