Streamlining Data Processing with Laravel's Pipeline Pattern

Streamlining Data Processing with Laravel's Pipeline Pattern

The Pipeline pattern in Laravel provides an elegant way to pass data through a series of operations. This pattern is particularly useful for complex workflows or when you need to apply a sequence of transformations to your data. Let's explore how to implement and leverage the Pipeline pattern in your Laravel applications.

Basic Pipeline Usage

Here's a basic example of using Laravel's pipeline:

use Illuminate\Support\Facades\Pipeline;

$result = Pipeline::send($order)
    ->through([
        ValidateOrder::class,
        ApplyDiscount::class,
        CalculateTax::class,
        ProcessPayment::class,
    ])
    ->then(fn ($order) => $order->complete());

In this example, an $order object is passed through a series of operations before being completed.

Creating Pipeline Steps

Each step in the pipeline should be a class with an __invoke method:

class ValidateOrder
{
    public function __invoke($order, $next)
    {
        // Perform validation logic
        if (!$order->isValid()) {
            throw new InvalidOrderException();
        }

        return $next($order);
    }
}

Passing Additional Parameters

You can pass additional parameters to your pipeline steps:

$result = Pipeline::send($order)
    ->through([
        ValidateOrder::class,
        [ApplyDiscount::class, $discountCode],
        [CalculateTax::class, $taxRate],
        ProcessPayment::class,
    ])
    ->then(fn ($order) => $order->complete());

In your pipeline step:

class ApplyDiscount
{
    public function __invoke($order, $next, $discountCode)
    {
        // Apply discount logic using $discountCode
        return $next($order);
    }
}

Using the Pipeline in Controllers

Implement the pipeline in your controller for clean, modular code:

class OrderController extends Controller
{
    public function store(Request $request)
    {
        $order = new Order($request->all());

        return Pipeline::send($order)
            ->through([
                ValidateOrder::class,
                SaveOrder::class,
                NotifyCustomer::class,
            ])
            ->then(fn ($order) => response()->json($order, 201));
    }
}

Error Handling in Pipelines

Handle exceptions within your pipeline steps:

class ProcessPayment
{
    public function __invoke($order, $next)
    {
        try {
            // Process payment logic
            PaymentGateway::charge($order->total);
        } catch (PaymentFailedException $e) {
            return response()->json(['error' => 'Payment failed'], 400);
        }

        return $next($order);
    }
}

Creating Reusable Pipelines

For frequently used pipelines, create a dedicated class:

class OrderProcessingPipeline
{
    public function __invoke($order)
    {
        return Pipeline::send($order)
            ->through([
                ValidateOrder::class,
                ApplyDiscount::class,
                CalculateTax::class,
                ProcessPayment::class,
            ])
            ->then(fn ($order) => $order->complete());
    }
}

Use it in your controller:

public function store(Request $request, OrderProcessingPipeline $pipeline)
{
    $order = new Order($request->all());
    return $pipeline($order);
}

Conditional Pipeline Steps

Add or remove steps based on conditions:

$steps = [ValidateOrder::class, SaveOrder::class];

if ($request->has('discount_code')) {
    $steps[] = ApplyDiscount::class;
}

$steps[] = ProcessPayment::class;

return Pipeline::send($order)
    ->through($steps)
    ->then(fn ($order) => response()->json($order, 201));

The Pipeline pattern in Laravel offers a clean, modular approach to handling complex workflows. By breaking down your logic into small, focused steps, you can create more maintainable and testable code. This pattern is particularly useful for processes like order processing, user registration, or any scenario where you need to apply a series of operations to your data in a specific order.

If this guide was helpful to you, subscribe to my daily newsletter and give me a follow on X/Twitter. It helps a lot!

Subscribe to Harris Raftopoulos

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe