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

Polinicles's avatar

Laravel Good Practices with Exceptions and Try&Catch Blocks

Hi there!

I'm building a web app where the customers can purchase many different plans and I'm using Stripe API for the payments. When a customer wants to buy a plan, it has to fill the credit card details and the email too. So, in my RegistrationController, I get all this info.

The thing is, I have to do many things in the post method like:

  • Check if the selected plan exists (maybe somebody could hack the html form source).
  • Create the Stripe Costumer.
  • Create the Stripe Subscription for the Customer I've created.
  • Create the new Eloquent User, sync the chosen plans and add the Stripe info (Stripe id, etc.) to the User.

As I do have to do many steps, I decided to use a Try&Catch block and create custom Exceptions so, if something fails, I'll be able to track where the error happened. The problem is that I end with a messy method in the RegistrationController:

public function postRegistration(RegistrationRequest $request,
                                     StripeCostumer $stripeCustomer,
                                     StripeSubscription $stripeSubscription)
    {
        if ($request['training_plan'])
        {

            if ( ! $this->PlanExists($request['training_plan']))
            {
                \Log::alert('Somebody tried to hack the plan: '. 
                $request['email']);

                return response()->json(
                    ['error' => \Config::get('variables.104')],
                    Response::HTTP_NOT_FOUND);
            }
        }

        try
        {
            $response = $stripeCustomer->createNewStripeCostumer($request);

            $plans = $stripeSubscription->createNewStripeSubscription($response->id, $request);

            $user = $this->userRepo->create($request->all());

            $user->syncUserPlans($plans);

            $this->userRepo->saveStripeInfo($user,$response);

        }
        catch(StripeCustomerNotCreated $e)
        {
            \Log::error('Couldn't create a new Stripe Costumer: '.
                $request['email']);

            return response()->json(
                ['error' => \Config::get('variables.106')],
                Response::HTTP_PAYMENT_REQUIRED);

        }
    catch(StripeSubscriptionNotCreated $e)
    ...
    catch(EloquentUserNotCreated $e)
    ...
    catch(catch(StripeInfoNotSaved $e)
    ...

    event(new UserRegistration($user));

        \Auth::login($user);

        return redirect('/');
    }

I didn't wrote every Catch block (I currently have 4-5) but everytime I throw an exception, I have to:

  • Undo all the previous actions (creating Stripe Customer, Eloquent User, etc.) so in every Catch the logic gets larger.
  • Log the incident.
  • Return the error.

This is the example of a method from a service class to manage the Stripe Customers:

public function createNewStripeCustomer($request)
    {
        $response = Customer::create(array(
            "description" => "Customer for test@example.com",
            "source" => $request->stripeToken,
            "email" => $request->email,
        ));

        if(true)
        {
            return $response;
        }

        throw new StripeCustomerNotCreated();
    }

*If there's any error, I return a JSON like an API. *I have "variables.php" file in the /Config directory where I save all the error messages.

I tried to save the logic of every Exception in the Handler.php file (using a switch loop) but It doesn't work as I expect. Other option is replacing the try&catch block for many if&else but it's still messy.

Any suggestions to make the code efficient? Any good practice to improve my code?

Thanks in advance!

0 likes
1 reply

Please or to participate in this conversation.