Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example

Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example

In this post we will give you information about Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example. Hear we will give you detail about Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with exampleAnd how to use it also give you demo for it if it is necessary.

Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example

In this tutorial, You will know how to configure Stripe with Laravel 5.4 and register subscription based user using the Laravel 5.4 Cashier package.

Laravel is the best back-end technology to easily configure stripe payment system.


Install Laravel 5.4 & Cashier using Composer

In the first step, you will have to setup your Laravel application in your working directory.

Now i will run the following command to install Laravel :

composer create-project --prefer-dist laravel/laravel blog

Above command will create a fresh laravel application. Now we need to configure laravel/cashier package for Stripe in our composer.json file :


Composer

.....
"require": {
        .....
        "laravel/cashier": "~7.0"
    },
    ......

Now run composer update command.


Service Provider (config/app.php)

Now we need to register service provider LaravelCashierCashierServiceProvider in config/app.php file to the providers array.

....
'providers' => [
    ....,
    LaravelCashierCashierServiceProvider::class,
]
    .....


Create the migrations

By default, you will get a migration file to create a users table so we will need some more columns to the users table and create a new subscriptions table for holding the information of the customer’s subscription.

Create a new migration file by using artisan command and add following line of code in that file :


Schema::table('users', function ($table) {
    $table->string('stripe_id')->nullable();
    $table->string('card_brand')->nullable();
    $table->string('card_last_four')->nullable();
    $table->timestamp('trial_ends_at')->nullable();
});

Schema::create('subscriptions', function ($table) {
    $table->increments('id');
    $table->integer('user_id');
    $table->string('name');
    $table->string('stripe_id');
    $table->string('stripe_plan');
    $table->integer('quantity');
    $table->timestamp('trial_ends_at')->nullable();
    $table->timestamp('ends_at')->nullable();
    $table->timestamps();
});


Now you are ready to migrate the database by running following command :

php artisan migrate


Create Stripe Plan

Now to get started with Stripe, we need to create an account first. Once you have created your stripe account then click Plans under Subscriptions.

I have created a diamond plan for testing, you can create your own subscription plan.

Now we need to get Stripe API access key to configure Stripe in Laravel and you can get keys from clicking on the API.

Now i will add the stripe key and secret in config/services.php file.

 'stripe' => [
        'model' => AppUser::class,
        'key' =>'your_stripe_key',
        'secret' => 'your_stripe_secret',
    ],

Finally i need to add the Billable Trait on User Model.


app/User.php

use LaravelCashierBillable;

class User extends Authenticatable
{
    use Billable;
}



Add Routes

I assume that you have set up the stripe configuration successfully.

Ok let’s start with Laravel routes to register a subscription based user.

  1. Route::get('subscription',['as'=>'subscription','uses'=>'HomeController@subscription']);
  2. Route::post('subscription',['as'=>'post-subscription','uses'=>'HomeController@postSubscription']);
Route::get('subscription', ['as'=>'subscription','uses'=>'HomeController@subscription']);
Route::post('subscription', ['as'=>'post-subscription','uses'=>'HomeController@postSubscription']);


Add Controller

In this step, we will create a HomeController.php in following directory app/Http/Controllers.

  1. <?php
  2. namespace AppHttpControllers;
  3. use IlluminateHttpRequest;
  4. use AppUser;
  5. class HomeController extends Controller {
  6.     public functionsubscription(){
  7.         returnview('subscription');
  8.     }
  9.     public functionpostSubscription(Request $request){
  10.         $user=new User;
  11.      $user->name =$request->name;    
  12.      $user->email =$request->email;
  13.      $user->password =bcrypt($request->password);
  14.      $user->save();
  15.      $user->newSubscription('main',$request->subscription)->create($request->token);
  16.      if($user->subscribed('main')){
  17.             returnresponse()->json(['msg'=>'Successfully subscribed']);
  18.         }
  19.         returnresponse()->json(['msg'=>'Oops there is something error with your input']);
  20.          
  21.     }
  22. }
<?php
namespace AppHttpControllers;

use IlluminateHttpRequest;
use AppUser;

class HomeController extends Controller {

    public function subscription(){
        return view('subscription');
    }

    public function postSubscription(Request $request){
        $user = new User;
        $user->name  = $request->name;        
        $user->email = $request->email;
        $user->password = bcrypt($request->password);
        $user->save();
        $user->newSubscription('main',$request->subscription)->create($request->token);
        if ($user->subscribed('main')) {
            return response()->json(['msg'=>'Successfully subscribed']);
        }
        return response()->json(['msg'=>'Oops there is something error with your input']);
            
    }

}

In above code within postSubscription method, i add a user first then subscribe the user with selected plan.

You will notice that we are getting a token as parameter in “create” method, This token is generated from sensitive card data and you will see in the next step that how it will generate.


Subscription Page

In this step, we will create a file where users will fill their details, to subscribe a plan for the application.

  1. <!DOCTYPEhtml>
  2. <htmllang="en">
  3. <head>
  4. <metacharset="utf-8">
  5. <metahttp-equiv="X-UA-Compatible"content="IE=edge">
  6. <metaname="viewport"content="width=device-width, initial-scale=1">
  7. <title>Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example</title>
  8. <!-- Styles -->
  9. <linkhref="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"rel="stylesheet">
  10. <linkrel="stylesheet"href="http://formvalidation.io/vendor/formvalidation/css/formValidation.min.css">
  11. <scriptsrc="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
  12. <scriptsrc="http://formvalidation.io/vendor/formvalidation/js/formValidation.min.js"></script>
  13. <scriptsrc="http://formvalidation.io/vendor/formvalidation/js/framework/bootstrap.min.js"></script>
  14. </head>
  15. <body>
  16. <divclass="row">
  17. <formid="paymentForm"class="form-horizontal">
  18. <inputtype="hidden"name="_token"value="{{csrf_token()}}">
  19. <divclass="form-group">
  20. <labelclass="col-xs-3 control-label">Subscription Plan</label>
  21. <divclass="col-xs-5">
  22. <selectname="subscription"class="form-control">
  23. <optionvalue="diamond">Diamond ($20.00/month)</option>
  24. </select>
  25. </div>
  26. </div>
  27. <divclass="form-group">
  28. <labelclass="col-xs-3 control-label">Name</label>
  29. <divclass="col-xs-5">
  30. <inputtype="text"class="form-control"name="name"/>
  31. </div>
  32. </div>
  33. <divclass="form-group">
  34. <labelclass="col-xs-3 control-label">Email</label>
  35. <divclass="col-xs-5">
  36. <inputtype="email"class="form-control"name="email"/>
  37. </div>
  38. </div>
  39. <divclass="form-group">
  40. <labelclass="col-xs-3 control-label">Password</label>
  41. <divclass="col-xs-5">
  42. <inputtype="password"class="form-control"name="password"/>
  43. </div>
  44. </div>
  45. <divclass="form-group">
  46. <labelclass="col-xs-3 control-label">Credit card number</label>
  47. <divclass="col-xs-5">
  48. <inputtype="text"class="form-control"data-stripe="number"/>
  49. </div>
  50. </div>
  51. <divclass="form-group">
  52. <labelclass="col-xs-3 control-label">Expiration</label>
  53. <divclass="col-xs-3">
  54. <inputtype="text"class="form-control"placeholder="Month"data-stripe="exp-month"/>
  55. </div>
  56. <divclass="col-xs-2">
  57. <inputtype="text"class="form-control"placeholder="Year"data-stripe="exp-year"/>
  58. </div>
  59. </div>
  60. <divclass="form-group">
  61. <labelclass="col-xs-3 control-label">CVV</label>
  62. <divclass="col-xs-2">
  63. <inputtype="text"class="form-control"data-stripe="cvc"/>
  64. </div>
  65. </div>
  66. <divclass="form-group">
  67. <divclass="col-xs-9 col-xs-offset-3">
  68. <buttontype="submit"class="btn btn-primary">Sign Up</button>
  69. </div>
  70. </div>
  71. <inputtype="hidden"name="token"value=""/>
  72. </form>
  73. </div>
  74. <scriptsrc="https://js.stripe.com/v2/"></script>
  75. <script>
  76. $(document).ready(function() {
  77. // Change the key to your one
  78. Stripe.setPublishableKey('your_stripe_key');
  79. $('#paymentForm')
  80. .formValidation({
  81. framework: 'bootstrap',
  82. icon: {
  83. valid: 'glyphicon glyphicon-ok',
  84. invalid: 'glyphicon glyphicon-remove',
  85. validating: 'glyphicon glyphicon-refresh'
  86. },
  87. fields: {
  88. name: {
  89. validators: {
  90. notEmpty: {
  91. message: 'The name is required'
  92. }
  93. }
  94. },
  95. email: {
  96. validators: {
  97. notEmpty: {
  98. message: 'The email is required'
  99. }
  100. }
  101. },
  102. password: {
  103. validators: {
  104. notEmpty: {
  105. message: 'The password is required'
  106. }
  107. }
  108. },
  109. ccNumber: {
  110. selector: '[data-stripe="number"]',
  111. validators: {
  112. notEmpty: {
  113. message: 'The credit card number is required'
  114. },
  115. creditCard: {
  116. message: 'The credit card number is not valid'
  117. }
  118. }
  119. },
  120. expMonth: {
  121. selector: '[data-stripe="exp-month"]',
  122. row: '.col-xs-3',
  123. validators: {
  124. notEmpty: {
  125. message: 'The expiration month is required'
  126. },
  127. digits: {
  128. message: 'The expiration month can contain digits only'
  129. },
  130. callback: {
  131. message: 'Expired',
  132. callback: function(value, validator) {
  133. value = parseInt(value, 10);
  134. var year = validator.getFieldElements('expYear').val(),
  135. currentMonth = new Date().getMonth() + 1,
  136. currentYear = new Date().getFullYear();
  137. if (value < 0 || value > 12) {
  138. return false;
  139. }
  140. if (year == '') {
  141. return true;
  142. }
  143. year = parseInt(year, 10);
  144. if (year > currentYear || (year == currentYear && value >= currentMonth)) {
  145. validator.updateStatus('expYear', 'VALID');
  146. return true;
  147. } else {
  148. return false;
  149. }
  150. }
  151. }
  152. }
  153. },
  154. expYear: {
  155. selector: '[data-stripe="exp-year"]',
  156. row: '.col-xs-3',
  157. validators: {
  158. notEmpty: {
  159. message: 'The expiration year is required'
  160. },
  161. digits: {
  162. message: 'The expiration year can contain digits only'
  163. },
  164. callback: {
  165. message: 'Expired',
  166. callback: function(value, validator) {
  167. value = parseInt(value, 10);
  168. var month = validator.getFieldElements('expMonth').val(),
  169. currentMonth = new Date().getMonth() + 1,
  170. currentYear = new Date().getFullYear();
  171. if (value < currentYear || value > currentYear + 100) {
  172. return false;
  173. }
  174. if (month == '') {
  175. return false;
  176. }
  177. month = parseInt(month, 10);
  178. if (value > currentYear || (value == currentYear && month >= currentMonth)) {
  179. validator.updateStatus('expMonth', 'VALID');
  180. return true;
  181. } else {
  182. return false;
  183. }
  184. }
  185. }
  186. }
  187. },
  188. cvvNumber: {
  189. selector: '[data-stripe="cvc"]',
  190. validators: {
  191. notEmpty: {
  192. message: 'The CVV number is required'
  193. },
  194. cvv: {
  195. message: 'The value is not a valid CVV',
  196. creditCardField: 'ccNumber'
  197. }
  198. }
  199. }
  200. }
  201. })
  202. .on('success.form.fv', function(e) {
  203. e.preventDefault();
  204. var $form = $(e.target);
  205. // Reset the token first
  206. $form.find('[name="token"]').val('');
  207. Stripe.card.createToken($form, function(status, response) {
  208. if (response.error) {
  209. alert(response.error.message);
  210. } else {
  211. // Set the token value
  212. $form.find('[name="token"]').val(response.id);
  213. // Or using Ajax
  214. $.ajax({
  215. // You need to change the url option to your back-end endpoint
  216. url: "{{route('post-subscription')}}",
  217. data: $form.serialize(),
  218. method: 'POST',
  219. dataType: 'json'
  220. }).success(function(data) {
  221. alert(data.msg);
  222. // Reset the form
  223. $form.formValidation('resetForm', true);
  224. });
  225. }
  226. });
  227. });
  228. });
  229. </script>
  230. </body>
  231. </html>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example</title>
    <!-- Styles -->
    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <link rel="stylesheet" href="http://formvalidation.io/vendor/formvalidation/css/formValidation.min.css">

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
    <script src="http://formvalidation.io/vendor/formvalidation/js/formValidation.min.js"></script>
    <script src="http://formvalidation.io/vendor/formvalidation/js/framework/bootstrap.min.js"></script>
</head>
<body>
<div >

<form id="paymentForm" >
    <input type="hidden" name="_token" value="{{csrf_token()}}">
    <div >
        <label >Subscription Plan</label>
        <div >
            <select name="subscription" >
                <option value="diamond">Diamond ($20.00/month)</option>
            </select>
        </div>
    </div>
    <div >
        <label >Name</label>
        <div >
            <input type="text"  name="name" />
        </div>
    </div>

    <div >
        <label >Email</label>
        <div >
            <input type="email"  name="email" />
        </div>
    </div>

    <div >
        <label >Password</label>
        <div >
            <input type="password"  name="password" />
        </div>
    </div>

    <div >
        <label >Credit card number</label>
        <div >
            <input type="text"  data-stripe="number" />
        </div>
    </div>

    <div >
        <label >Expiration</label>
        <div >
            <input type="text"  placeholder="Month" data-stripe="exp-month" />
        </div>
        <div >
            <input type="text"  placeholder="Year" data-stripe="exp-year" />
        </div>
    </div>

    <div >
        <label >CVV</label>
        <div >
            <input type="text"  data-stripe="cvc" />
        </div>
    </div>

    <div >
        <div >
            <button type="submit" >Sign Up</button>
        </div>
    </div>

    <input type="hidden" name="token" value="" />
</form>
</div>
<script src="https://js.stripe.com/v2/"></script>

<script>
$(document).ready(function() {
    // Change the key to your one
    Stripe.setPublishableKey('pk_test_8FVTOTZ9myqpA4p1zTADRMhp');

    $('#paymentForm')
        .formValidation({
            framework: 'bootstrap',
            icon: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                name: {
                    validators: {
                        notEmpty: {
                            message: 'The name is required'
                        }
                    }
                },
                email: {
                    validators: {
                        notEmpty: {
                            message: 'The email is required'
                        }
                    }
                },
                password: {
                    validators: {
                        notEmpty: {
                            message: 'The password is required'
                        }
                    }
                },
                ccNumber: {
                    selector: '[data-stripe="number"]',
                    validators: {
                        notEmpty: {
                            message: 'The credit card number is required'
                        },
                        creditCard: {
                            message: 'The credit card number is not valid'
                        }
                    }
                },
                expMonth: {
                    selector: '[data-stripe="exp-month"]',
                    row: '.col-xs-3',
                    validators: {
                        notEmpty: {
                            message: 'The expiration month is required'
                        },
                        digits: {
                            message: 'The expiration month can contain digits only'
                        },
                        callback: {
                            message: 'Expired',
                            callback: function(value, validator) {
                                value = parseInt(value, 10);
                                var year         = validator.getFieldElements('expYear').val(),
                                    currentMonth = new Date().getMonth() + 1,
                                    currentYear  = new Date().getFullYear();
                                if (value < 0 || value > 12) {
                                    return false;
                                }
                                if (year == '') {
                                    return true;
                                }
                                year = parseInt(year, 10);
                                if (year > currentYear || (year == currentYear && value >= currentMonth)) {
                                    validator.updateStatus('expYear', 'VALID');
                                    return true;
                                } else {
                                    return false;
                                }
                            }
                        }
                    }
                },
                expYear: {
                    selector: '[data-stripe="exp-year"]',
                    row: '.col-xs-3',
                    validators: {
                        notEmpty: {
                            message: 'The expiration year is required'
                        },
                        digits: {
                            message: 'The expiration year can contain digits only'
                        },
                        callback: {
                            message: 'Expired',
                            callback: function(value, validator) {
                                value = parseInt(value, 10);
                                var month        = validator.getFieldElements('expMonth').val(),
                                    currentMonth = new Date().getMonth() + 1,
                                    currentYear  = new Date().getFullYear();
                                if (value < currentYear || value > currentYear + 100) {
                                    return false;
                                }
                                if (month == '') {
                                    return false;
                                }
                                month = parseInt(month, 10);
                                if (value > currentYear || (value == currentYear && month >= currentMonth)) {
                                    validator.updateStatus('expMonth', 'VALID');
                                    return true;
                                } else {
                                    return false;
                                }
                            }
                        }
                    }
                },
                cvvNumber: {
                    selector: '[data-stripe="cvc"]',
                    validators: {
                        notEmpty: {
                            message: 'The CVV number is required'
                        },
                        cvv: {
                            message: 'The value is not a valid CVV',
                            creditCardField: 'ccNumber'
                        }
                    }
                }
            }
        })
        .on('success.form.fv', function(e) {
            e.preventDefault();
            var $form = $(e.target);
            // Reset the token first
            $form.find('[name="token"]').val('');
            Stripe.card.createToken($form, function(status, response) {
                if (response.error) {
                    alert(response.error.message);
                } else {                  
                    // Set the token value
                    $form.find('[name="token"]').val(response.id);                 
                    // Or using Ajax
                    $.ajax({
                        // You need to change the url option to your back-end endpoint
                        url: "{{route('post-subscription')}}",
                        data: $form.serialize(),
                        method: 'POST',
                        dataType: 'json'
                    }).success(function(data) {
                        alert(data.msg);                        
                        // Reset the form
                        $form.formValidation('resetForm', true);
                    });
                }
            });
        });
});
</script>
</body>
</html>

Using stripe, we do not need to save sensitive card data, we pass these details to the Stripe server and stripe server will return a token if we do not get any error.

Click here to download this project from github: GitHub

Label :

PHP

Laravel PHP Framework

How To

MVC

Web Development

Hope this code and post will helped you for implement Monthly Subscription App using Stripe, Cashier and Laravel 5.4 with example. if you need any help or any feedback give it in comment section or you have good idea about this post you can give it comment section. Your comment will help us for help you more and improve us. we will give you this type of more interesting post in featured also so, For more interesting post and code Keep reading our blogs

For More Info See :: laravel And github

Leave a Comment

Your email address will not be published. Required fields are marked *

6  +    =  16

We're accepting well-written guest posts and this is a great opportunity to collaborate : Contact US