Download Laravel App
composer create-project --prefer-dist laravel/laravel my-app
C:\xampp\htdocs\laravel>composer create-project --prefer-dist laravel/laravel my-app
Connecting our Database
open .env file root directory.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laraveldb
DB_USERNAME=root
DB_PASSWORD=
Install Auth Scaffold
composer require laravel/ui
C:\xampp\htdocs\laravel\my-app>composer require laravel/ui
generate auth scaffold with bootstrap
php artisan ui bootstrap --auth
C:\xampp\htdocs\laravel\my-app>php artisan ui bootstrap --auth
install npm packages
npm install
C:\xampp\htdocs\laravel\my-app>npm install
built bootstrap CSS
npm run build
C:\xampp\htdocs\laravel\my-app>npm run build
Install Cashier Package
Laravel Cashier (Stripe)
https://laravel.com/docs/9.x/billing
composer require laravel/cashier
C:\xampp\htdocs\laravel\my-app>composer require laravel/cashier
publish cashier migration for creating tables
php artisan vendor:publish --tag="cashier-migrations"
C:\xampp\htdocs\laravel\my-app>php artisan vendor:publish --tag="cashier-migrations"
run the migration
C:\xampp\htdocs\laravel\my-app>php artisan migrate
login stripe account stripe.com test click Developers and get API keys
add API Kyes to .env
STRIPE_KEY=pk_test_secretkeyxxx
STRIPE_SECRET=sk_test_secretkeyxxxx
click Products tab and create plans
BUSINESS PLAN and PREMIUM and copy the API ID
add Cashier to User Model
Laravel\Cashier\Billable
app/Models/User.php
// <?php namespace App\Models; // use Illuminate\Contracts\Auth\MustVerifyEmail; 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<int, string> */ protected $fillable = [ 'name', 'email', 'password', ]; /** * The attributes that should be hidden for serialization. * * @var array<int, string> */ protected $hidden = [ 'password', 'remember_token', ]; /** * The attributes that should be cast. * * @var array<string, string> */ protected $casts = [ 'email_verified_at' => 'datetime', ]; }Model Plan
C:\xampp\htdocs\laravel\my-app>php artisan make:migration create_plans_table
database/migrations/create_plan_table.php
//database/migrations/create_plan_table.php <?php use Illuminate\Database\Migrations\Migration; use Illuminate\Database\Schema\Blueprint; use Illuminate\Support\Facades\Schema; return new class extends Migration { 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(); }); } public function down() { Schema::dropIfExists('plans'); } };run this migration
C:\xampp\htdocs\laravel\my-app>php artisan migrate
create model plan
php artisan make:model Plan
C:\xampp\htdocs\laravel\my-app>php artisan make:model Plan
app/Models/Plan.php
//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; protected $fillable = [ 'name', 'slug', 'stripe_plan', 'price', 'description', ]; public function getRouteKeyName() { return 'slug'; } }Create Controller
C:\xampp\htdocs\laravel\my-app>php artisan make:controller PlanController
app/Http/Controllers/PlanController.php
//app/Http/Controllers/PlanController.php <?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Models\Plan; use Illuminate\Support\Facades\Auth; use App\Models\User; 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"); } }Create Routes laravelproject\routes\web.php
//laravelproject\routes\web.php <?php use Illuminate\Support\Facades\Route; use App\Http\Controllers\PlanController; 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"); });Create View Blade File
resources/views/plans.blade.php
resources/views/subscription.blade.php
resources/views/subscription_success.blade.php
resources/views/plans.blade.php
//resources/views/plans.blade.php @extends('layouts.app') @section('content') <div class="container"> <section> <div class="container py-5"> <header class="text-center mb-5 text-white"> <div class="row"> <div class="col-lg-12 mx-auto"> <h1>Laravel 9 Cashier Stripe Subscription</h1> <h3>PRICING</h3> </div> </div> </header> <div class="row text-center align-items-end"> <div class="col-lg-4 mb-5 mb-lg-0"> <div class="bg-white p-5 rounded-lg shadow"> <h1 class="h6 text-uppercase font-weight-bold mb-4">FREE</h1> <h2 class="h1 font-weight-bold">$0<span class="text-small font-weight-normal ml-2">/ free</span></h2> <div class="custom-separator my-4 mx-auto bg-primary"></div> <ul class="list-unstyled my-5 text-small text-left"> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> Lorem ipsum dolor sit amet</li> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> Sed ut perspiciatis</li> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> At vero eos et accusamus</li> <li class="mb-3 text-muted"> <i class="fa fa-times mr-2"></i> <del>Nam libero tempore</del> </li> <li class="mb-3 text-muted"> <i class="fa fa-times mr-2"></i> <del>Sed ut perspiciatis</del> </li> <li class="mb-3 text-muted"> <i class="fa fa-times mr-2"></i> <del>Sed ut perspiciatis</del> </li> </ul> <a href="#" class="btn btn-primary btn-block shadow rounded-pill">Buy Now</a> </div> </div> @foreach($plans as $plan) <div class="col-lg-4 mb-5 mb-lg-0"> <div class="bg-white p-5 rounded-lg shadow"> <h1 class="h6 text-uppercase font-weight-bold mb-4">{{ $plan->name }}</h1> <h2 class="h1 font-weight-bold">${{ $plan->price }}<span class="text-small font-weight-normal ml-2">/ month</span></h2> <div class="custom-separator my-4 mx-auto bg-primary"></div> <ul class="list-unstyled my-5 text-small text-left font-weight-normal"> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> Lorem ipsum dolor sit amet</li> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> Sed ut perspiciatis</li> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> At vero eos et accusamus</li> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> Nam libero tempore</li> <li class="mb-3"> <i class="fa fa-check mr-2 text-primary"></i> Sed ut perspiciatis</li> <li class="mb-3 text-muted"> <i class="fa fa-times mr-2"></i> <del>Sed ut perspiciatis</del> </li> </ul> <a href="{{ route('plans.show', $plan->slug) }}" class="btn btn-primary btn-block shadow rounded-pill">Buy Now</a> </div> </div> @endforeach </div> </div> </section> </div> @endsectionresources/views/subscription.blade.php
//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> @endsectionresources/views/subscription_success.blade.php
//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> @endsectionadd css to laravel\my-app\resources\view\layouts\app.blade.php
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
<link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css" >
my-app/public/css/app.css
php artisan make:seeder PlanSeeder
C:\xampp\htdocs\laravel\my-app>php artisan make:seeder PlanSeeder
database/seeders/PlanSeeder.php
php artisan db:seed --class=PlanSeeder
C:\xampp\htdocs\laravel\my-app>php artisan db:seed --class=PlanSeeder
check database plan table
Run C:\xampp\htdocs\laravel\my-app>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
http://localhost:8000/login
After, login
http://localhost:8000/plans
//my-app/public/css/app.css body { background: #00B4DB; background: -webkit-linear-gradient(to right, #0083B0, #00B4DB); background: linear-gradient(to right, #0083B0, #00B4DB); color: #514B64; min-height: 100vh; } .rounded-lg { border-radius: 1rem !important; } .text-small { font-size: 0.9rem !important; } .custom-separator { width: 5rem; height: 6px; border-radius: 1rem; } .text-uppercase { letter-spacing: 0.2em; } body { background: #00B4DB; background: -webkit-linear-gradient(to right, #0083B0, #00B4DB); background: linear-gradient(to right, #0083B0, #00B4DB); color: #514B64; min-height: 100vh; }Create Seeder For Plans
php artisan make:seeder PlanSeeder
C:\xampp\htdocs\laravel\my-app>php artisan make:seeder PlanSeeder
database/seeders/PlanSeeder.php
//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 { public function run() { $plans = [ [ 'name' => 'Business Plan', 'slug' => 'business-plan', 'stripe_plan' => 'price_1LmB1SCXbPPKAWayGsb1DAkq', 'price' => 10, 'description' => 'Business Plan' ], [ 'name' => 'Premium', 'slug' => 'premium', 'stripe_plan' => 'price_1LnwbTCXbPPKAWay3ByKpcfq', 'price' => 20, 'description' => 'Premium' ] ]; foreach ($plans as $plan) { Plan::create($plan); } } }run PermissionTableSeeder seeder
php artisan db:seed --class=PlanSeeder
C:\xampp\htdocs\laravel\my-app>php artisan db:seed --class=PlanSeeder
check database plan table
Run C:\xampp\htdocs\laravel\my-app>php artisan serve
Starting Laravel development server: http://127.0.0.1:8000
http://localhost:8000/login
After, login
http://localhost:8000/plans