Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Pipeline Laravel Package

mpociot/pipeline

Lightweight PHP pipeline implementation (based on illuminate/pipeline) without requiring the Illuminate container. Send an object through an array of middleware/handlers and finish with a callback—useful for middleware-style request/command processing.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require mpociot/pipeline
    

    Ensure autoloading is configured in composer.json:

    "autoload": {
        "psr-4": {
            "App\\": "app/",
            "Mpociot\\Pipeline\\": "vendor/mpociot/pipeline/src/"
        }
    }
    
  2. First Use Case: Process a simple object through middleware:

    use Mpociot\Pipeline\Pipeline;
    
    $pipeline = new Pipeline();
    $result = $pipeline
        ->send('initial_data')
        ->through([
            new class {
                public function handle($data, \Closure $next) {
                    return $next($data . '_processed');
                }
            },
            new class {
                public function handle($data, \Closure $next) {
                    return $next($data . '_final');
                }
            }
        ])
        ->then(function ($data) {
            return $data; // 'initial_data_processed_final'
        });
    
  3. Where to Look First:

    • Core Class: vendor/mpociot/pipeline/src/Pipeline.php (main pipeline logic).
    • Middleware Interface: vendor/mpociot/pipeline/src/Pipeline/StageInterface.php (defines handle() method).
    • Examples: Use the README’s basic example as a template for your first pipeline.

Implementation Patterns

Basic Pipeline Workflow

  1. Send Data:

    $pipeline->send($data); // Start with initial payload.
    
  2. Define Middleware: Middleware must implement Mpociot\Pipeline\Pipeline\StageInterface with a handle() method:

    class ValidateMiddleware {
        public function handle($data, \Closure $next) {
            if (!$this->isValid($data)) {
                throw new \InvalidArgumentException('Invalid data');
            }
            return $next($data); // Pass to next middleware.
        }
    }
    
  3. Execute Pipeline:

    $pipeline
        ->send($request)
        ->through([new ValidateMiddleware(), new LogMiddleware()])
        ->then(function ($response) {
            // Final processing.
            return $response;
        });
    

Common Patterns

  • Closure-Based Middleware: Use anonymous functions for one-off logic:

    $pipeline->through([
        function ($data, \Closure $next) {
            return $next($data . '_step1');
        },
        function ($data, \Closure $next) {
            return $next($data . '_step2');
        }
    ]);
    
  • Conditional Pipeline Branching: Dynamically add middleware based on runtime conditions:

    $middleware = [];
    if ($user->hasRole('admin')) {
        $middleware[] = new AdminMiddleware();
    }
    $pipeline->through($middleware);
    
  • Pipeline Composition: Chain pipelines for multi-stage workflows:

    $firstPipeline = (new Pipeline())->send($data)->through([$middleware1]);
    $result = $firstPipeline->then(function ($data) {
        return (new Pipeline())->send($data)->through([$middleware2])->then(...);
    });
    
  • Error Handling: Use catch() to handle exceptions globally:

    $pipeline->then(...)->catch(function (\Exception $e) {
        log::error('Pipeline failed: ' . $e->getMessage());
        return $defaultResponse;
    });
    

Integration Tips

  • Laravel-Like Middleware: Mimic Laravel’s middleware structure for consistency:

    class TransformData {
        public function __invoke($data, \Closure $next) {
            $data = $this->transform($data);
            return $next($data);
        }
    }
    
  • Dependency Injection: Pass dependencies to middleware via constructor:

    class LoggerMiddleware {
        protected $logger;
        public function __construct($logger) {
            $this->logger = $logger;
        }
        public function handle($data, \Closure $next) {
            $this->logger->log('Processing data');
            return $next($data);
        }
    }
    
  • Testing: Mock pipelines for unit tests:

    $mockPipeline = $this->getMockBuilder(Pipeline::class)
        ->disableOriginalConstructor()
        ->onlyMethods(['then'])
        ->getMock();
    

Gotchas and Tips

Pitfalls

  1. Middleware Order Matters: Pipelines execute middleware in the order they’re passed to through(). Reversing order can break logic (e.g., auth before validation).

  2. No Dependency Injection: Unlike Laravel’s pipeline, this package lacks a built-in container. Manually pass dependencies to middleware:

    // Bad: Assumes global $logger.
    $middleware = new LoggerMiddleware();
    
    // Good: Explicit dependency.
    $middleware = new LoggerMiddleware(new MonologLogger());
    
  3. No Pipeline-Wide Exception Handling: Exceptions in middleware halt the pipeline unless caught with catch():

    $pipeline->then(...)->catch(function (\Exception $e) {
        // Handle globally.
    });
    
  4. PHP Version Quirks:

    • PHP 8.x: May require polyfills for array() syntax or named arguments.
    • Closure Binding: Ensure $next closures are bound correctly (use Closure::bind() if needed).
  5. State Management: Avoid storing state in middleware instances (e.g., static properties) unless thread-safe. Pipelines may be reused across requests.

Debugging Tips

  • Log Middleware Execution: Add logging in handle() to trace pipeline flow:

    public function handle($data, \Closure $next) {
        \Log::debug('Middleware called with data: ' . json_encode($data));
        return $next($data);
    }
    
  • Use Xdebug: Step through pipeline execution to identify where data transforms unexpectedly.

  • Validate Middleware: Ensure all middleware return the $next result or throw exceptions (never silently modify data).

Extension Points

  1. Custom Pipeline Classes: Extend Mpociot\Pipeline\Pipeline to add features (e.g., async support):

    class AsyncPipeline extends Pipeline {
        public function asyncThrough(array $middleware) {
            // Implement async logic.
        }
    }
    
  2. Middleware Adapters: Create adapters for other middleware standards (e.g., PSR-15):

    class Psr15ToPipelineAdapter {
        public static function adapt(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Server\MiddlewareInterface $middleware) {
            return new class($middleware) implements Pipeline\StageInterface {
                public function handle($data, \Closure $next) {
                    return $next($data);
                }
            };
        }
    }
    
  3. Pipeline Decorators: Wrap pipelines to add cross-cutting concerns (e.g., timing, retries):

    class TimedPipeline {
        public function __construct(Pipeline $pipeline) {
            $this->pipeline = $pipeline;
        }
        public function send($data) {
            $start = microtime(true);
            $result = $this->pipeline->send($data)->then(...);
            \Log::info('Pipeline executed in ' . (microtime(true) - $start) . 's');
            return $result;
        }
    }
    

Configuration Quirks

  • No Built-in Config: The package is stateless; configure pipelines dynamically via code (no config/pipeline.php).

  • Middleware Caching: Avoid caching pipeline instances with middleware that rely on request-specific state (e.g., session data).

Performance Tips

  • Avoid Closure Overhead: Prefer class-based middleware for complex logic (closures create new scope overhead).

  • Reuse Pipelines: Instantiate pipelines once (e.g., in a service container) and reuse them:

    $pipeline = new Pipeline();
    $pipeline->send($data)->through($middleware);
    
  • Benchmark: Compare pipeline performance against manual chaining for critical paths:

    // Manual (baseline)
    $data = $middleware1->handle($data, function ($d) use ($middleware2) {
        return $middleware2->handle($d, function ($d) { return $d; });
    });
    
    // Pipeline
    $pipeline->send($data)->through([$middleware1, $middleware2])->then(...);
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle