Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

vguerrerobosch's avatar

Dispatch event when exception is triggered

I'm guessing I'm not doing the correct approach but here is the case.

I have an order controller like

class OrderController extends Controller
{
    // ...
 
    public function store(OrderRequest $request, Gateway $gateway)
    {

    // 1. handle Cart

    // 2. update or create Customer

    // 3. first or create Address

    // 4. create Order

    // 5. save many Products to Order

    $charge = $gateway->charge($total, $token, $description);

    event(new OrderSucceed($order, $cart, $charge));

    // return json response 201
    
    }

    // ...
}

when charge succeeds I fire the event OrderSucceed that amongst other things changes the order status from pending to processing.

Then I have a Stripe implementation of the interface Gateway like the following.

class StripeGateway implements Gateway
{
    public function __construct()
    {
        Stripe::setApiKey(config('services.stripe.secret'));
    }

    public function charge($amount, $token, $description = null)
    {
        return Charge::create([
            'amount' => (int) $amount * 100,
            'currency' => 'eur',
            'source' => $token,
            'description' => $description,
        ]);
    }
}

When Stripe charge triggers and exception I have in Exceptions Handler

class Handler extends ExceptionHandler
{
    //...

    public function render($request, Exception $exception)
    {
        if ($exception instanceof \Stripe\Error\Card) {

            // event(new OrderFailed($order, $exception));

            return response()->json([
                'message' => $exception->getMessage(),
                'stripCode' => $exception->getStripeCode(),
                'declineCode' => $exception->getDeclineCode(),
            ], $exception->getHttpStatus());
        } elseif ($exception instanceof \Stripe\Error\RateLimit) {
            // Too many requests made to the API too quickly
        } elseif ($exception instanceof \Stripe\Error\InvalidRequest) {
            // Invalid parameters were supplied to Stripe's API
        } elseif ($exception instanceof \Stripe\Error\Authentication) {
            // Authentication with Stripe's API failed
            // (maybe you changed API keys recently)
        } elseif ($exception instanceof \Stripe\Error\ApiConnection) {
            // Network communication with Stripe failed
        } elseif ($exception instanceof \Stripe\Error\Base) {
            // Display a very generic error to the user, and maybe send
            // yourself an email
        }

        return parent::render($request, $exception);
    }
}

The thing is I want to dispatch the OrderFailed event to mark order as paid and record failed payment but I need to have $order available and I don't know where do I have to do it. I'm really struggling with this, probably really simple stuff but I can't figure out...

0 likes
1 reply
Talinon's avatar

I think I would handle this by wrapping your gateway call within a try/catch block within your controller. Something like this:

public function store(OrderRequest $request, Gateway $gateway)
    {

    try {

        $charge = $gateway->charge($total, $token, $description);

        event(new OrderSucceed($order, $cart, $charge));

    } catch (\Stripe\Error\Card $exception) {

        event(new OrderFailed($order, $exception));

    }



    // return json response 201
    
    }

Please or to participate in this conversation.