Use Laravel's Pipeline facade to pass objects through sequential pipe classes, keeping complex order processing and data transformations modular.
When an application workflow involves multiple distinct stages (such as validating payment, applying coupons, calculating tax, and generating invoices), stuffing all logic into a single service method creates monolithic, hard-to-test code.
Laravel's Pipeline pattern executes sequential pipes cleanly.
Defining Pipe Classes
Each pipe receives the payload and a $next closure:
namespace App\Pipelines\Orders;
use Closure;
class ApplyDiscountCoupon
{
public function handle(Order $order, Closure $next)
{
if ($order->coupon_code) {
$order->discount = CouponService::calculate($order);
}
return $next($order);
}
}
Executing the Pipeline
use App\Pipelines\Orders\ApplyDiscountCoupon;
use App\Pipelines\Orders\CalculateTax;
use App\Pipelines\Orders\ProcessStripePayment;
use Illuminate\Support\Facades\Pipeline;
$processedOrder = Pipeline::send($order)
->through([
ApplyDiscountCoupon::class,
CalculateTax::class,
ProcessStripePayment::class,
])
->then(fn ($order) => $order->finalize());
Summary
- Deconstructs complex operations into focused, single-responsibility pipe classes.
- Enables easy reordering, adding, or removing of business steps.
- Uses standard middleware-style
handle($passable, Closure $next)signatures.
Related Tips
View all tips →Use Laravel's remember_token as a Revocation Signal
Use Laravel's remember_token as an invalidation signal for saved account-switching state without maintaining a dedicated token or revocation table.
Multi-Tenant Team Scoping with a Reusable BelongsToTeam Model Trait
Automatically assign tenant IDs and restrict Eloquent queries using a reusable BelongsToTeam model trait with model booting and global scopes.