Search code examples
phpsubscriptionlaravel-6laravel-cashier

How to create Subscription with Laravel 6 and Cashier 10 with Stripe?


Laravel Developers,

After I submit my payment form, I get a 404 error message. When I check the database there is no update in the subscription document. Any suggestions? I've been at this for a while now and I feel like I'm missing something that should be obvious.

SubscriptionController.php

class SubscriptionController extends Controller
{
    public function create(Request $request, Plan $plan)
    {
        $plan = Plan::findOrFail($request->get('plan'));

        $request->user()
            ->newSubscription('main', $plan->stripe_plan)
            ->create($request->stripeToken);

        return redirect()->route('home')
            ->with('success', 'Your plan subscribed successfully');
    }
}

Here is my Route

 Route::get('/plans', 'PlanController@index')->name('plans.index');
 Route::get('/plan/{plan}', 'PlanController@show')->name('plans.show');

Solution

  • You are using Implicit Binding on your route and controller. i.e. Laravel will automatically inject the model instance that has an ID matching the corresponding value from the request URI. If a matching model instance is not found in the database, a 404 HTTP response will automatically be generated.

    But you're repeating this behavior using findOrFail and calling $request->get('plan') which is null because plan is not in your input request but it's on your route. So the Plan::findOrFail(null) leads to 404 error.

    You can correct your code in 2 ways:

    1. Remove unnecessary line that contains findOrFail and let Laravel handles it for you by Implicit Binding (I recommend this way):

      class SubscriptionController extends Controller
      {
          public function create(Request $request, Plan $plan)
          {
              //$plan = Plan::findOrFail($request->get('plan')); // <= unnecessary
      
              $request->user()
                  ->newSubscription('main', $plan->stripe_plan)
                  ->create($request->stripeToken);
      
              return redirect()->route('home')
                  ->with('success', 'Your plan subscribed successfully');
          }
      }
      
    2. Change your route and controller's method to use $id instead of Implicit Binding and use findOrFail manually (not recommended):

      Route::get('/plan/{id}', 'PlanController@show')->name('plans.show');
      
      class SubscriptionController extends Controller
      {
          public function create(Request $request, $id)
          {
              $plan = Plan::findOrFail($id);
      
              $request->user()
                  ->newSubscription('main', $plan->stripe_plan)
                  ->create($request->stripeToken);
      
              return redirect()->route('home')
                  ->with('success', 'Your plan subscribed successfully');
          }
      }