# Context
Pipelines are generally atomic and each pipe is stateless. But in some cases you might want to hold a common state reference as you progress through your pipes. The example below allows the pipes to add error messages into a common message bag which is then validated by the final pipe.
use Illuminate\Support\MessageBag;
class CalculateShipping{
public MessageBag $errors;
public function __construct(
public Checkout $checkout
){
$this->errors = new MessageBag();
}
public function calculate(){
return pipeline($this->checkout)->context($this)->pipe(
GetShippableItems::class,
...,
Pipeline::tap(function(){
$this->checkout->errors->fillFrom($this->errors);
}),
Pipeline::on(
fn () => $this->errors->isEmpty(),
CreateShippingMethods::class,
fn () => collect([]), // return an empty collection
),
);
}
}
...
/**
* @property CalculateShipping $context
*/
class GetShippableItems{
public function handle(Checkout $checkout)
{
/** @var Collection */
$lines = $checkout->lines()->requiresShipping()->get();
if ($lines->isEmpty()) {
$this->context->errors->add('items', 'No items to calculate shipping methods');
}
return $lines;
}
}
...
$checkout = Checkout::find($token);
$shippingMethodCalculator = new CalculateShipping($checkout);
$shippingMethods = $shippingMethodCalculator->calculate();
if (!$shippingMethodCalculator->errors->isEmpty()) {
//
}