Laravel Cashier Stripe Subscription Example

Aug 29, 2022 . Admin

Hello Friends,

Hello all! In this article, we will talk about laravel cashier stripe subscription example. In this article, we will implement a laravel cashier subscription example. step by step explain stripe subscription example laravel. This post will give you simple example of laravel cashier stripe tutorial. So, let's follow few step to create example of laravel cashier stripe example.

You can use this example with laravel 6, laravel 7, laravel 8 and laravel 9 versions.

Whenever we want to develop our own product in IT fields, then we are looking for a subscription-based product. so, we don't have to worry about getting money. It will automatically charge every month or based on the plan. So, if you are working on a laravel project and you need to add a subscription plan to it. Then laravel provides a Cashier package to add these functions. You can create a stripe plan and the user can select a plan, based on the plan stripe will charge automatically. I will give you step by step example here.

In this example, I will show you step-by-step how to implement a stripe subscription using laravel cashier. In this example, we will create Basic and Premium two plans with it's price. The user can choose one of that two plans. based on the plan user will get features. You can see the below preview as well. So let's see the below steps and get it done with your app.

Preview:

Step 1: Install Laravel

This is optional; however, if you have not created the laravel app, then you may go ahead and execute the below command:

composer create-project laravel/laravel example-app
Step 2: Setup Database Configuration

After successfully installing the laravel app then after configuring the database setup. We will open the ".env" file and change the database name, username and password in the env file.

.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=Enter_Your_Database_Name
DB_USERNAME=Enter_Your_Database_Username
DB_PASSWORD=Enter_Your_Database_Password
Step 3: Install Auth Scaffold

Laravel's laravel/ui package provides a quick way to scaffold all of the routes and views you need for authentication using a few simple commands:

composer require laravel/ui

Next, we need to generate auth scaffold with bootstrap, so let's run the below command:

php artisan ui bootstrap --auth

Then, install npm packages using the below command:

npm install

At last, built bootstrap CSS using the below command:

npm run build
Step 4: Install Cashier Package

In this step, we will install laravel/cashier that way we can use stripe API and methods to create subscriptions. so let's run the below command:

composer require laravel/cashier

Next, we need to publish cashier migration for creating tables, so let's run the below command:

php artisan vendor:publish --tag="cashier-migrations"

Then, run the migration command to create a table using the below command:

php artisan migrate
Step 5: Create Stripe Account & Get Stripe API Key and SECRET

This step is a very important step, if you don't have a stripe account then you need to create and if you have then proceeded to get Stripe Key and Secret. So, Let's open below stripe official website using the below link:

1) Open Stripe official website

After login, You need to go on Developers tab and get API keys as like below:


Just, saved that Key and Secret we will use in .env file.

Next, you need to go on Products tab and create following two plans:

1) Basic

2) Premium

You must have to copy Plan ID, that we will store in plans table with seeder.

You can see below screenshot:

Now, just add Stripe Key and Secret add on .env file as below:

.env
STRIPE_KEY=pk_test_MRzwmMVtDyyp1r1q79LGjJ
STRIPE_SECRET=sk_test_eKrHzLozoU4PTjCwhIPdr
Step 6: Configure Cashier

In this step, we will use cashier Laravel\Cashier\Billable class in User model, so let's add it below:

app/Models/User.php
<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Laravel\Cashier\Billable;
  
class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable, Billable;
  
    /**
     * The attributes that are mass assignable.
     *
     * @var array

     */
    protected $fillable = [
        'name',
        'email',
        'password',
    ];
  
    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array

     */
    protected $hidden = [
        'password',
        'remember_token',
    ];
  
    /**
     * The attributes that should be cast.
     *
     * @var array

     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}
Step 7: Create Migration and Model for Plan

Here, we have to create migration for "plans" table using Laravel php artisan command, so first fire bellow command:

php artisan make:migration create_plans_table

After this command you will find one file in the following path "database/migrations" and you have to put the below code in your migration file to create a plans table.

<?php
  
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
  
return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('plans', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('slug');
            $table->string('stripe_plan');
            $table->integer('price');
            $table->string('description');
            $table->timestamps();
        });
    }
  
    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('plans');
    }
};

Now you have to run this migration by the following command:

php artisan migrate

In this step, we will create Plan.php model. let's copy the below code and paste it.

app/Models/Plan.php
<?php
  
namespace App\Models;
  
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
  
class Plan extends Model
{
    use HasFactory;
  
    /**
     * The attributes that are mass assignable.
     *
     * @var array

     */
    protected $fillable = [
        'name',
        'slug',
        'stripe_plan',
        'price',
        'description',
    ];
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function getRouteKeyName()
    {
        return 'slug';
    }
}
Step 8: Create Routes

In this step, we will create three routes for plans, plans show and subscription buy. So, let's add a new route to that file.

routes/web.php
<?php
  
use Illuminate\Support\Facades\Route;
 
use App\Http\Controllers\PlanController;
  
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
  
Route::get('/', function () {
    return view('welcome');
});
 
Auth::routes();
  
Route::get('/home', [App\Http\Controllers\HomeController::class, 'index'])->name('home');
  
Route::middleware("auth")->group(function () {
    Route::get('plans', [PlanController::class, 'index']);
    Route::get('plans/{plan}', [PlanController::class, 'show'])->name("plans.show");
    Route::post('subscription', [PlanController::class, 'subscription'])->name("subscription.create");
});
Step 9: Create Controller File

in the next step, now we have created a new controller as PlanController and write three methods on it like as below, So let's create a controller:

app/Http/Controllers/PlanController.php
<?php
  
namespace App\Http\Controllers;
  
use Illuminate\Http\Request;
use App\Models\Plan;
  
class PlanController extends Controller
{
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function index()
    {
        $plans = Plan::get();
  
        return view("plans", compact("plans"));
    }  
  
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function show(Plan $plan, Request $request)
    {
        $intent = auth()->user()->createSetupIntent();
  
        return view("subscription", compact("plan", "intent"));
    }
    /**
     * Write code on Method
     *
     * @return response()
     */
    public function subscription(Request $request)
    {
        $plan = Plan::find($request->plan);
  
        $subscription = $request->user()->newSubscription($request->plan, $plan->stripe_plan)
                        ->create($request->token);
  
        return view("subscription_success");
    }
}
Step 10: Create Blade File

In this step, we need to create three blade file with plans.blade.php, subscription.blade.php and subscription_success.blade.php, so let's update following code on it:

resources/views/plans.blade.php
@extends('layouts.app')
  
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">Select Plane:</div>
 
                <div class="card-body">
 
                    <div class="row">
                        @foreach($plans as $plan)
                            <div class="col-md-6">
                                <div class="card mb-3">
                                  <div class="card-header"> 
                                        ${{ $plan->price }}/Mo
                                  </div>
                                  <div class="card-body">
                                    <h5 class="card-title">{{ $plan->name }}</h5>
                                    <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
  
                                    <a href="{{ route('plans.show', $plan->slug) }}" class="btn btn-primary pull-right">Choose</a>
  
                                  </div>
                                </div>
                            </div>
                        @endforeach
                    </div>
  
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
resources/views/subscription.blade.php
@extends('layouts.app')
    
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">
                    You will be charged ${{ number_format($plan->price, 2) }} for {{ $plan->name }} Plan
                </div>
  
                <div class="card-body">
  
                    <form id="payment-form" action="{{ route('subscription.create') }}" method="POST">
                        @csrf
                        <input type="hidden" name="plan" id="plan" value="{{ $plan->id }}">
  
                        <div class="row">
                            <div class="col-xl-4 col-lg-4">
                                <div class="form-group">
                                    <label for="">Name</label>
                                    <input type="text" name="name" id="card-holder-name" class="form-control" value="" placeholder="Name on the card">
                                </div>
                            </div>
                        </div>
  
                        <div class="row">
                            <div class="col-xl-4 col-lg-4">
                                <div class="form-group">
                                    <label for="">Card details</label>
                                    <div id="card-element"></div>
                                </div>
                            </div>
                            <div class="col-xl-12 col-lg-12">
                            <hr>
                                <button type="submit" class="btn btn-primary" id="card-button" data-secret="{{ $intent->client_secret }}">Purchase</button>
                            </div>
                        </div>
  
                    </form>
  
                </div>
            </div>
        </div>
    </div>
</div>
  
<script src="https://js.stripe.com/v3/"></script>
<script>
    const stripe = Stripe('{{ env('STRIPE_KEY') }}')
  
    const elements = stripe.elements()
    const cardElement = elements.create('card')
  
    cardElement.mount('#card-element')
  
    const form = document.getElementById('payment-form')
    const cardBtn = document.getElementById('card-button')
    const cardHolderName = document.getElementById('card-holder-name')
  
    form.addEventListener('submit', async (e) => {
        e.preventDefault()
  
        cardBtn.disabled = true
        const { setupIntent, error } = await stripe.confirmCardSetup(
            cardBtn.dataset.secret, {
                payment_method: {
                    card: cardElement,
                    billing_details: {
                        name: cardHolderName.value
                    }   
                }
            }
        )
  
        if(error) {
            cardBtn.disable = false
        } else {
            let token = document.createElement('input')
            token.setAttribute('type', 'hidden')
            token.setAttribute('name', 'token')
            token.setAttribute('value', setupIntent.payment_method)
            form.appendChild(token)
            form.submit();
        }
    })
</script>
@endsection
resources/views/subscription_success.blade.php
@extends('layouts.app')
  
@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
  
                <div class="card-body">
  
                    <div class="alert alert-success">
                        Subscription purchase successfully!
                    </div>
  
                </div>
            </div>
        </div>
    </div>
</div>
@endsection
Step 11: Create Seeder For Plans

In this step, we will create seeder for creating Basic and Premium plans.

Make sure you have to copy your plan ID from stripe website

So, create seeder using bellow command:

php artisan make:seeder PlanSeeder

And put bellow code in PlanSeeder seeder this way:

database/seeders/PlanSeeder.php
<?php
  
namespace Database\Seeders;
  
use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use App\Models\Plan;
  
class PlanSeeder extends Seeder
{
    /**
     * Run the database seeds.
     *
     * @return void
     */
    public function run()
    {
        $plans = [
            [
                'name' => 'Basic', 
                'slug' => 'basic', 
                'stripe_plan' => 'price_1LXOzsGzlk2XAanfTskz9n', 
                'price' => 10, 
                'description' => 'Basic'
            ],
            [
                'name' => 'Premium', 
                'slug' => 'premium', 
                'stripe_plan' => 'price_1LXP23Gzlk2XAanf4zQZdi', 
                'price' => 100, 
                'description' => 'Premium'
            ]
        ];
  
        foreach ($plans as $plan) {
            Plan::create($plan);
        }
    }
}

After this we have to run bellow command for run PermissionTableSeeder seeder:

php artisan db:seed --class=PlanSeeder
Run Laravel App:

All the required steps have been done, now you have to type the given below command and hit enter to run the Laravel app:

php artisan serve

Now, Go to your web browser, type the given URL and view the app output:

http://localhost:8000/login

After, login you need to go on following path:

http://localhost:8000/plans
Output: Plan List

Output: Purchase Plan

Output: Purchase Plan Successfully

Now you can check with following card details:

Name: Test

Number: 4242 4242 4242 4242

CSV: 123

Expiration Month: 12

Expiration Year: 2028

I hope it can help you...

#Laravel