{"id":27198519,"url":"https://github.com/andydune/pipeline","last_synced_at":"2025-04-09T20:42:20.840Z","repository":{"id":56948176,"uuid":"103917140","full_name":"AndyDune/Pipeline","owner":"AndyDune","description":"This package provides a pipeline pattern implementation. It based on middleware approach.","archived":false,"fork":false,"pushed_at":"2020-05-16T16:15:17.000Z","size":62,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-23T22:37:40.841Z","etag":null,"topics":["middleware","php","pipeline","workflow"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AndyDune.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-09-18T09:07:17.000Z","updated_at":"2024-11-19T19:17:41.000Z","dependencies_parsed_at":"2022-08-21T07:20:52.033Z","dependency_job_id":null,"html_url":"https://github.com/AndyDune/Pipeline","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyDune%2FPipeline","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyDune%2FPipeline/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyDune%2FPipeline/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AndyDune%2FPipeline/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AndyDune","download_url":"https://codeload.github.com/AndyDune/Pipeline/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248110037,"owners_count":21049422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["middleware","php","pipeline","workflow"],"created_at":"2025-04-09T20:42:19.928Z","updated_at":"2025-04-09T20:42:20.827Z","avatar_url":"https://github.com/AndyDune.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AndyDune\\Pipeline\n\n[![Build Status](https://travis-ci.org/AndyDune/Pipeline.svg?branch=master)](https://travis-ci.org/AndyDune/Pipeline)\n[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)\n[![Packagist Version](https://img.shields.io/packagist/v/andydune/pipeline.svg?style=flat-square)](https://packagist.org/packages/andydune/pipeline)\n[![Total Downloads](https://img.shields.io/packagist/dt/andydune/pipeline.svg?style=flat-square)](https://packagist.org/packages/andydune/pipeline)\n\n\nThis package provides a pipeline pattern implementation. It is based on middleware approach.\n\n\nRequirements\n------------\n\nPHP version \u003e= 7.1\n\nFor php 5.6 use version 1:\n```\n\"require\" : {\n     \"andydune/pipeline\": \"1.*\"\n}\n```\n\n\nInstallation\n------------\n\nInstallation using composer:\n\n```\ncomposer require andydune/pipeline \n```\nOr if composer was not installed globally:\n```\nphp composer.phar require andydune/pipeline\n```\nOr edit your `composer.json`:\n```\n\"require\" : {\n     \"andydune/pipeline\": \"^2\"\n}\n\n```\nAnd execute command:\n```\nphp composer.phar update\n```\n\n\n## Usage\n\nOperations in pipeline stages, can be anything that satisfies the `callable`\ntype-hint. So closures and anything that's invokable is good.\n\n```php\nuse AndyDune\\Pipeline\\Pipeline;\n \n$pipeline = new Pipeline();\n\n$stages = [\n    function($contest, $next) {\n        $contest += 100;\n        return $next($contest);    \n    },\n    function($contest, $next) {\n        $contest += 10;\n        return $next($contest);    \n    }\n];\n$result = $pipeline-\u003ethrough($stages)-\u003esend(1)\n-\u003ethen(function ($context) {\n            $context += 1000;\n            return $context;});\n$result // 1111\n```\n\n\n## Types of stages\n\nBasically each stage can be `Closure`:\n```php\n$pipeline = new Pipeline();\n$pipeline-\u003epipe(function ($context, $next) {\n    $context['closure'] = 'was here';\n    return $next($context); \n});\n```\n\nIt can be an instance of class with callable interface:\n```php\n$instance = new class() {\n    public function __invoke($context, $next) \n    {\n        $context['invoke'] = 'was here';\n        return $next($context); \n    }\n}\n\n$pipeline = new Pipeline();\n$pipeline-\u003epipe($instance);\n```\n\nIt can be an instance of class with any method:\n```php\n$instance = new class() {\n    public function doIt($context, $next) \n    {\n        $context['invoke'] = 'was here';\n        return $next($context); \n    }\n}\n\n$pipeline = new Pipeline();\n$pipeline-\u003epipe($instance, 'doIt');\n```\n\nIt can be a class name with method `__invoke` or any method you describe:\n```php\nclass Trim\n{\n    public function __invoke($context, $next) \n    {\n        $context['class_invoke'] = 'was here';\n        return $next($context); \n    }\n}\n\n$pipeline = new Pipeline();\n$pipeline-\u003epipe(Trim::class);\n```\n\nIt can be a class name with any method you describe:\n```php\nclass Trim\n{\n    public function handle($context, $next) \n    {\n        $context['class_invoke'] = 'was here';\n        return $next($context); \n    }\n}\n\n$pipeline = new Pipeline();\n$pipeline-\u003epipe(Trim::class,  'handle');\n```\n\n## Use object for stage without middleware interface\n\nYou can use methods which don't execute $next function. It gets some data and return results.\nThere is special method: 'pipeForContainer'\n\nExample class. \n```php\nnamespace AndyDune\\Pipeline\\Example;\n\nclass Methods\n{\n    // return result - no calling next() \n    public function addBraceLeft($string)\n    {\n        return '(' . $string;\n    }\n\n    // It has middleware interface\n    public function addBraceRight($string, callable $next)\n    {\n        $string =  $string . ')';\n        return $next($string);\n    }\n}\n``` \n\n\n```php\n\n$instance = new Methods();\n\n$pipeline = new Pipeline();\n$pipeline-\u003esend('puh');\n\n$pipeline-\u003epipeForContainer($instance, 'addBraceLeft');\n\n$pipeline-\u003epipe(Methods::class, 'addBraceRight');\n$result = $pipeline-\u003eexecute();\n\n$result == '(puh)';\n``` \n\n\n## Container provider (service provider)\n\nString can de passed as pipeline stage. By default it is a class name. \nIt's make possible by using default provider: `AndyDune\\Pipeline\\PipeIsClassName`  \nYou can set your own provider, with injections you need. Your class must implements interface: `Interop\\Container\\ContainerInterface`\n\nIf was not found stage with your provider system will try to use default provider. There is stack of providers.\n\nUse your provider as parameter for pipeline constructor:\n```php\nuse Interop\\Container\\ContainerInterface;\n\nclass SpecialPipelineContainer implements ContainerInterface\n{\n    /**\n     * @var  \\Rzn\\ObjectBuilder\n     */\n    protected $objectBuilder;\n\n    public function get($name)\n    {\n        /*\n        do anything to build object using $name\n        */\n        return $object;\n    }\n    \n    public function has($name)\n    {\n        /*\n        do anything to check required object can be build  \n        */\n        return $exist;\n    }\n}\n\n$container = new SpecialPipelineContainer();\n$pipeLine = new Pipeline($container);\n\n$pipeLine-\u003epipe('any string to get stage from container');\n\n```\n\n## Additional parameters for stage\n\nSometimes you need to pass any number of additional parameters to pipe stage during description. \nIt needs for test and it very good for more flexibility of stage. It increases reuse of class.\n\nLets look at the example. It is very simple example.\n\nHere is example class for stage:  \n```php\nnamespace AndyDune\\Pipeline\\Example;\nclass PowerOfNumber\n{\n    public function __invoke($data, callable $next, $power = 2)\n    {\n        if (is_array($power)) {\n            array_walk($power, function (\u0026$value, $key) use ($data) {\n                $value = pow($data, $value);\n            });\n            return $next($power);\n        }\n        $data = $this-\u003ehandle($data, $power);\n        return $next($data);\n    }\n    protected function handle($number, $power)\n    {\n        return pow($number, $power);\n    }\n}\n``` \n\nLets use it:\n\n```php\n    use use AndyDune\\Pipeline\\Pipeline;\n    use AndyDune\\Pipeline\\Example;\n    \n    $pipeline = new Pipeline();\n    $pipeline-\u003esend(2);\n    $pipeline-\u003epipe(PowerOfNumber::class);\n    $result = $pipeline-\u003eexecute(); // == 4\n\n    $pipeline = new Pipeline();\n    $pipeline-\u003esend(2);\n    $pipeline-\u003epipe(PowerOfNumber::class, null, 3);\n    $result = $pipeline-\u003eexecute(); // == 8\n    \n    $pipeline = new Pipeline();\n    $pipeline-\u003esend(2);\n    $pipeline-\u003epipe(PowerOfNumber::class, null, 4);\n    $result = $pipeline-\u003eexecute(); // == 16\n```   \n\n## Dependency injection\n\nYou can use default pipeline stage creator with injection into stage objects services or any objects from outside. \n\nThere is injection with interfaces.\n\n```php\n    use use AndyDune\\Pipeline\\Pipeline;\n    \n    $pipeline = new Pipeline();\n    \n    $pipeline-\u003eaddInitializer(function($stageObject) use ($someService) {\n        if ($stageObject instanceof SomeServiceAwareInterface) {\n            $stageObject-\u003esetSomeService($someService)\n        }     \n    });\n    \n    $pipeline-\u003epipe(ClassHaveInterface::class);\n    $result = $pipeline-\u003eexecute();\n``` \n \nThis use method `addInitializer` which receive callable parameter. \n\n\n## Exceptions\n\nPackage has not integrated exception catch support. It is simple for you  to include exception _try-catch_ block into one of pipeline stages.\n```php\n    use AndyDune\\Pipeline\\Pipeline;\n    $pipeline = new Pipeline();\n    $pipeline-\u003esend(['zub' =\u003e 'kovoy']);\n    $pipeline-\u003epipe(function ($context, $next) {\n        try {\n            return $next($context);\n        } catch (Exception $e) {\n            $context['exception'] = 'caught';\n        }\n        return $context;\n    });\n\n    $pipeline-\u003epipe(function ($context, $next) {\n        $context['action'] = 'before_exception';\n        throw new Exception();\n        return $next($context); // it will be never execute\n    });\n     \n    // This stage will never be executed\n    $pipeline-\u003epipe(function ($context, $next) {\n        $context['after_exception'] = 'ignored';\n        return $next($context);\n    });\n\n    $result = $pipeline-\u003eexecute();\n    array_key_exists('zub', $result);       // true\n    array_key_exists('exception', $result); // true\n    array_key_exists('action', $result);    // false\n    array_key_exists('after_exception', $result); // false\n\n```  \n\nThere is a class you may use as stage for your pipeline for catch exception in this package.\n```php\n \n    $pipeline = new Pipeline();\n    $pipeline-\u003esend(['zub' =\u003e 'kovoy']);\n    $pipeline-\u003epipe(AndyDune\\Pipeline\\Stage\\ExceptionCatch::class);\n    $pipeline-\u003epipe(function ($context, $next) {\n        $context['action'] = 'before_exception';\n        throw new Exception('jump');\n    });\n    $result = $pipeline-\u003eexecute();\n    \n    $result instancheof \\Exception // true\n```\n\n## Examples\n\n### Caching\n\nYou have service for retrieve data. And you don't need to change its code. \nJust use it as a stage in the pipeline. \n\n```php\n\n// Description\n$pipeline = new Pipeline();\n$pipeline-\u003epipe(function($key, $next) {\n    /*\n    * Cache adapter with (PSR-16) interface\n    * Ones a have used Symfony Cache Component [https://github.com/symfony/cache] \n    * It's for example\n    */\n    $cache = new FilesystemCache();\n    if ($cache-\u003ehas($key)) {\n        return $cache-\u003eget($key);\n    }\n    $data = $next($catId);\n    $cache-\u003eset($key, $data);\n    return $data;\n});\n$pipeline-\u003epipe(DataRetrieveClass::class, 'getImportantData');\n \n// Execute \n$results = $pipeline-\u003esend($key)-\u003eexecute();\n```\n\n## Usage within Zend FW 3\n\nBy default string as stage for pipeline means name of class. \nIf you create pipeline object without parameters service container implements `AndyDune\\Pipeline\\PipeIsClassName`. It only creates instance of given class and return it.\nIf this package is used as part of of _Zend FW 3_ you can use Zend's services for retrieve instances.\n\nFirst you must install package with composer. \nThen copy file `vendor/andydune/pipeline/config/pipeline.global.php` to `config/autoload/pipeline.global.php`\n\nDescription fot your pipeline in factory:  \n```php\nuse Zend\\ServiceManager\\Factory\\FactoryInterface;\nuse Interop\\Container\\ContainerInterface;\nclass DunhillFactory implements FactoryInterface\n{\n    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)\n    {\n        $pipeline = $container-\u003eget('pipeline');\n        $pipeline-\u003epipe('service name within Zend3');\n        $pipeline-\u003epipe(function($data, $next) {\n            return $next($data); \n        });\n        return $pipeline;\n    }\n}\n```\n\nIf you don't work with Zend services use pipeline directly.         \n\n\n## Analogues\n\n[Laravel pipeline](https://laravel.com/api/5.5/Illuminate/Pipeline.html) - it do very the same I wanted, but I need more tools for testing purpose. And I don't like laraver service manager. it has not common interface. \nMy pipeline may use service managers based on  [container-interop with PSR-11 interfaces](https://github.com/container-interop/container-interop).\n\n[League\\Pipeline](https://github.com/thephpleague/pipeline) - it has good documentation. But has bad feature - poor workflow control. To stop execution it need to use exception. \n\n   \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandydune%2Fpipeline","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandydune%2Fpipeline","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandydune%2Fpipeline/lists"}