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

Gabotronix's avatar

Remove exception clutter from my Controller methods

Hi everybody, I'm tinkering with stripe to make payments through my app, currently I'm using try catch blocks and Stripe own Exception methods to get notified when something goes wrong, sadly the catch blocks are huge as hell and I was wondering if there's a way to move this code outside my controller since the catch blocks all have the same, repeated code over and over, any idea?

This is one of my methods, I have lots of these in my controller so you can guess how cluttered my controller is getting.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Stripe;
use Stripe\Charge;
use Stripe\Customer;
use Stripe\Error\Card;
use Stripe\Error\ApiConnection;
use Stripe\Error\InvalidRequest;
use Stripe\Error\Api;
use Stripe\Error\Base;

class StripeController extends Controller
{
    
    public function customerCheck(Request $request){
        $user = Auth::user();

        if($user->stripeCustomerId){

            try{
                Stripe::setApiKey(config('services.stripe.secret'));
            
                $customerId = Auth::user()->stripeCustomerId;
    
                $customerSources = Customer::retrieve($customerId)->sources->all(array("object" => "card"));
    
                return response()->json([
                    'customerSources' => $customerSources,
                    'message' => 'Elije la forma de pago segura'
                ], 201);
            }
            catch (ApiConnection $e) {//Network problem, perhaps try again.
                return response()->json([
                    'message' => 'Sorry, Network is having trouble. Please try again later.',
                ]);
            } 
            catch (InvalidRequest $e) {//You screwed up in your programming. Shouldn't happen!
                return response()->json([
                    'message' => 'Sorry. One of our programmer forgot to drink their caffein.',
                ]);
            }
            catch (Api $e) {//Stripe's servers are down!
                return response()->json([
                    'message' => 'Sorry our payment processor is down at the moment.',
                ]);
            } 
            catch (Card $e) {//Card was declined.
                return response()->json([
                    'message' => 'Your card is declined. Please try with a different card.',
                ]);
            } 
            catch (\Stripe\Error\Base $e) {// Display a very generic error to the user, maybe send yourself an email
                return response()->json([
                    'message' => 'Algo salio mal, prueba más tarde.',
                ]);   
            }
            catch (Exception $e) {// Something else happened, completely unrelated to Stripe
                return response()->json([
                    'message' => 'Algo salio mal, prueba más tarde',
                ]);
            }

        }
        else if(!$user->customerId){
            return response()->json([
                'user' => $user,
                'message' => 'No hay tarjetas registradas a este nombre'
            ]);
        }
        else if(!$user){
            return response()->json([
                'user' => $user,
                'message' => 'Registrate para poder realizar la compra'
            ]);

        }

        return response()->json([
            'user' => 'It worked!',
        ]);

    }
0 likes
2 replies
manojo123's avatar

You can use the Customer Model and add the method customerCheck with all the logic you want.

Then in controller you can get the customer and only type this

$customer->customerCheck();

you can get the customer by sending in your routes file the customer id in the url like that

Route::get('stripe/{customer}', 'StripeController@customerCheck');

and finnaly receiving the customer as a parameter

public function customerCheck(Customer $customer){

    $customer->customerCheck();
    // ...
}

Something like that

realrandyallen's avatar
Level 44

You could put them in Laravel's exception handler and handle them there:

Controller

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Stripe\Stripe;
use Stripe\Charge;
use Stripe\Customer;

class StripeController extends Controller
{
    
    public function customerCheck(Request $request) {
        $user = Auth::user();

        if (! $user) {
            return response()->json([
                'user' => $user,
                'message' => 'Registrate para poder realizar la compra'
            ]);
        }

        if (! $user->customerId) {
            return response()->json([
                'user' => $user,
                'message' => 'No hay tarjetas registradas a este nombre'
            ]);
        }


        if ($user->stripeCustomerId) {
            Stripe::setApiKey(config('services.stripe.secret'));
               
            $customerSources = Customer::retrieve($user->stripeCustomerId)->sources->all(array("object" => "card"));
    
            return response()->json([
                'customerSources' => $customerSources,
                'message' => 'Elije la forma de pago segura'
            ], 201);
        }

        return response()->json([
            'user' => 'It worked!',
        ]);
    }
}

app/Exceptions/Handler.php

...

use Stripe\Error\Card;
use Stripe\Error\ApiConnection;
use Stripe\Error\InvalidRequest;
use Stripe\Error\Api;
use Stripe\Error\Base;

...

public function render($request, Exception $exception)
{
    if ($exception instanceof ApiConnection) {
        return response()->json([
            'message' => 'Sorry, Network is having trouble. Please try again later.',
        ]);
    }

    if ($exception instanceof InvalidRequest) {
        return response()->json([
            'message' => 'Sorry. One of our programmer forgot to drink their caffein.',
        ]);
    }

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

That gets your exception handling out of the Controller at least, I do agree with @manojow though that the customer check itself shouldn't live in the controller either and should be moved to a Model

Please or to participate in this conversation.