inmanturbo/pipes

Pipes for php with a simple api based on functional composition

v1.1.5 2024-08-14 00:09 UTC

This package is auto-updated.

Last update: 2024-11-14 00:39:43 UTC


README

Latest Version on Packagist GitHub Tests Action Status GitHub Code Style Action Status Total Downloads

Simply put, it takes the output of the last one and pipes it to the next one. Sorta like bash cat ./file | grep -e 'waldo'

Installation

You can install the package via composer:

composer require inmanturbo/pipes

Or just copy or download the functions.php file from this repository.

Usage

pipe()

require __DIR__.'/../vendor/autoload.php';

use function Inmanturbo\Pipes\pipe;

$addOne = fn ($number = 0) => $number + 1;

$five = pipe($addOne) // 1
    ->pipe(fn ($number) => $number + 1) // 2
    ->pipe($addOne) // 3
    ->pipe($addOne) // 4
    ->thenReturn(); // 4

It doesn't delay execution

$fifty = pipe(1);

    while ($fifty->result() < 50) {
        $fifty->pipe(fn ($number) => ++$number);
    }

echo $fifty->result();
// 50
     

You can also pass a class or a class string

use function Inmanturbo\Pipes\pipe;

class Subtract
{
    public function __invoke($number)
    {
        return $number - 1;
    }
}

$addOne = fn ($number = 0) => $number + 1;

$six = pipe($addOne, 1)
    ->pipe($addOne)
    ->pipe($addOne)
    ->pipe($addOne)
    ->then(fn ($number) => ++$number);

$five = pipe($six)
    ->pipe(Subtract::class)
    ->thenReturn();

$three = pipe(new Subtract, $five)
    ->pipe(new Subtract)
    ->thenReturn();

Returning results

results can be returned three ways:

then() or thenReturn() both a take final callback and return the result, or result(), which simply returns the result.

$addOne = fn ($number = 0) => $number + 1;

$six = pipe($addOne, 1)
    ->pipe($addOne)
    ->pipe($addOne)
    ->pipe($addOne)
    ->then(fn ($number) => ++$number);

$sixAgain = pipe($addOne, 1)
    ->pipe($addOne)
    ->pipe($addOne)
    ->pipe($addOne)
    ->thenReturn(fn ($number) => ++$number);

$five = pipe($addOne, 1)
    ->pipe($addOne)
    ->pipe($addOne)
    ->pipe($addOne)
    ->result();

Halting the pipeline

halt()

You can return halt() from a callback to halt the chain. halt takes an optional result as an argument which you can pass as the final result() of the chain. Subsequent calls to ->pipe() will not affect the final result.

    use function Inmanturbo\Pipes\{pipe, halt};

    $fortyFive = pipe(1);

    $count = 1;
    while ($count < 50) {
        $fortyFive->pipe(fn ($number) => $number < 45 ? ++$number : halt($number));

        $count ++;
    }

    echo $fortyFive->result();

    // 45

    echo $fortyFive->pipe(fn ($number) => ++$number)->result();

    // 45

You can also call halt on the pipe itself

    use function Inmanturbo\Pipes\{pipe, halt};

    $fortyFive = pipe(1);

    $count = 1;
    while ($count < 50) {
        
        if (($number = $fortyFive->result()) >= 45) {
            $fortyFive->halt($number);
        }

        $fortyFive->pipe(fn ($number) => ++$number);

        $count ++;
    }

    echo $fortyFive->result();

    // 45

    echo $fortyFive->pipe(fn ($number) => ++$number)->result();

    // 45

resume()

You can resume the piping with resume. pipe()->resume() takes an optional callback and behaves the same as pipe()->pipe() if a callback is passed

use function Inmanturbo\Pipes\{pipe, halt};

$fortySix = pipe(1);

$count = 1;
while ($count < 50) {
    
    if (($number = $fortySix->result()) >= 45) {
        $fortySix->halt($number);
    }

    $fortySix->pipe(fn ($number) => ++$number);

    $count ++;
}

echo $fortySix->result();

// 45

echo $fortySix->resume(fn ($number) => ++$number)->result();

// 46

hop() and Laravel

This package doesn't require laravel to use pipe or hop(), but hop() (higher-order-pipe) is a higher order function intended for working with Laravel's Pipeline helper. This higher-order-function takes a callback which takes a single argument, and wraps the $callback for you in a closure which implements function($next, $passable).

use Illuminate\Pipeline\Pipeline;

use function Inmanturbo\Pipes\hop;

class Add {
    public function add($number)
    {
        return $number +1;
    }
}
class InvokeAdd {
    public function __invoke($number)
    {
        return $number +1;
    }
}

$five = (new Pipeline)->send(1)
    ->pipe(hop(fn($number) => $number +1))
    ->pipe(hop(new InvokeAdd))
    ->pipe(hop(InvokeAdd::class))
    ->pipe(hop(fn($number) => (new Add)->add($number)))
->thenReturn();

// 5

You can optionally pass a single middleware as a second argument to hop(), and it will get called before the first argument, which allows you to determine if the pipeline should halt before the $callback ever gets executed.

$limitThreeMiddleware = function ($number, $next) {
    if($number >= 3) {
        Log::info('Limit hit');
        return $number;
    }

    return $next($number);
};

$five = (new Pipeline)->send(1)
    ->pipe(hop(fn($number) => $number +1, $limitThreeMiddleware))
    ->pipe(hop(new InvokeAdd, $limitThreeMiddleware))
    // Limit hit
    ->pipe(hop(InvokeAdd::class, $limitThreeMiddleware))
    ->pipe(hop(fn($number) => (new Add)->add($number), $limitThreeMiddleware))
->thenReturn();

// 3