{"id":4004,"date":"2023-11-04T23:13:59","date_gmt":"2023-11-04T23:13:59","guid":{"rendered":"http:\/\/localhost:10003\/how-to-build-a-shopping-cart-with-laravel-and-stripe\/"},"modified":"2023-11-05T05:48:24","modified_gmt":"2023-11-05T05:48:24","slug":"how-to-build-a-shopping-cart-with-laravel-and-stripe","status":"publish","type":"post","link":"http:\/\/localhost:10003\/how-to-build-a-shopping-cart-with-laravel-and-stripe\/","title":{"rendered":"How to Build a Shopping Cart with Laravel and Stripe"},"content":{"rendered":"
In this tutorial, we will learn how to build a shopping cart using Laravel, a popular PHP framework, and Stripe, a powerful payment gateway. By the end of this tutorial, you will have a fully functional shopping cart where users can add products, update quantities, and checkout using Stripe for secure payments.<\/p>\n
To follow along with this tutorial, you will need:<\/p>\n
Let’s start by setting up a new Laravel project. Open your terminal and run the following command:<\/p>\n
composer create-project laravel\/laravel shopping-cart\n<\/code><\/pre>\nThis will create a new Laravel project in a folder named shopping-cart<\/code>.<\/p>\nNext, navigate to the project folder:<\/p>\n
cd shopping-cart\n<\/code><\/pre>\nSetting Up the Database<\/h2>\n
Our shopping cart will require a database to store products, orders, and other related data. Open the .env<\/code> file in the project root directory and update the database connection settings to match your development environment:<\/p>\nDB_CONNECTION=mysql\nDB_HOST=127.0.0.1\nDB_PORT=3306\nDB_DATABASE=shopping_cart\nDB_USERNAME=root\nDB_PASSWORD=\n<\/code><\/pre>\nCreate a new MySQL database named shopping_cart<\/code> in your local development environment.<\/p>\nGenerating Migrations<\/h2>\n
We will use Laravel’s migration feature to create the necessary database tables. Run the following command in your terminal to generate the migration files:<\/p>\n
php artisan make:migration create_products_table\nphp artisan make:migration create_orders_table\nphp artisan make:migration create_order_items_table\n<\/code><\/pre>\nThis will generate three migration files in the database\/migrations<\/code> directory. Open each file and define the table schema as follows.<\/p>\ncreate_products_table.php<\/code><\/h3>\nuse IlluminateDatabaseMigrationsMigration;\nuse IlluminateDatabaseSchemaBlueprint;\nuse IlluminateSupportFacadesSchema;\n\nclass CreateProductsTable extends Migration\n{\n \/**\n * Run the migrations.\n *\n * @return void\n *\/\n public function up()\n {\n Schema::create('products', function (Blueprint $table) {\n $table->id();\n $table->string('name');\n $table->string('description');\n $table->decimal('price', 8, 2);\n $table->timestamps();\n });\n }\n\n \/**\n * Reverse the migrations.\n *\n * @return void\n *\/\n public function down()\n {\n Schema::dropIfExists('products');\n }\n}\n<\/code><\/pre>\ncreate_orders_table.php<\/code><\/h3>\nuse IlluminateDatabaseMigrationsMigration;\nuse IlluminateDatabaseSchemaBlueprint;\nuse IlluminateSupportFacadesSchema;\n\nclass CreateOrdersTable extends Migration\n{\n \/**\n * Run the migrations.\n *\n * @return void\n *\/\n public function up()\n {\n Schema::create('orders', function (Blueprint $table) {\n $table->id();\n $table->unsignedBigInteger('user_id');\n $table->decimal('total', 8, 2);\n $table->timestamps();\n\n $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');\n });\n }\n\n \/**\n * Reverse the migrations.\n *\n * @return void\n *\/\n public function down()\n {\n Schema::dropIfExists('orders');\n }\n}\n<\/code><\/pre>\ncreate_order_items_table.php<\/code><\/h3>\nuse IlluminateDatabaseMigrationsMigration;\nuse IlluminateDatabaseSchemaBlueprint;\nuse IlluminateSupportFacadesSchema;\n\nclass CreateOrderItemsTable extends Migration\n{\n \/**\n * Run the migrations.\n *\n * @return void\n *\/\n public function up()\n {\n Schema::create('order_items', function (Blueprint $table) {\n $table->id();\n $table->unsignedBigInteger('order_id');\n $table->unsignedBigInteger('product_id');\n $table->integer('quantity');\n $table->decimal('price', 8, 2);\n $table->timestamps();\n\n $table->foreign('order_id')->references('id')->on('orders')->onDelete('cascade');\n $table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');\n });\n }\n\n \/**\n * Reverse the migrations.\n *\n * @return void\n *\/\n public function down()\n {\n Schema::dropIfExists('order_items');\n }\n}\n<\/code><\/pre>\nRunning Migrations<\/h2>\n
Now that we have defined the table schemas, let’s run the migrations to create the database tables. Run the following command in your terminal:<\/p>\n
php artisan migrate\n<\/code><\/pre>\nYou should see output similar to the following:<\/p>\n
Migration table created successfully.\nMigrating: 2014_10_12_000000_create_users_table\nMigrated: 2014_10_12_000000_create_users_table\nMigrating: 2014_10_12_100000_create_password_resets_table\nMigrated: 2014_10_12_100000_create_password_resets_table\nMigrating: 2021_10_24_000000_create_products_table\nMigrated: 2021_10_24_000000_create_products_table\nMigrating: 2021_10_24_000001_create_orders_table\nMigrated: 2021_10_24_000001_create_orders_table\nMigrating: 2021_10_24_000002_create_order_items_table\nMigrated: 2021_10_24_000002_create_order_items_table\n<\/code><\/pre>\nCreating Models<\/h2>\n
We will use Laravel’s Eloquent ORM to interact with the database. Run the following commands to generate the necessary models:<\/p>\n
php artisan make:model Product\nphp artisan make:model Order\nphp artisan make:model OrderItem\n<\/code><\/pre>\nOpen each model file in the app\/Models<\/code> directory and define the relationships and attributes as follows.<\/p>\nProduct.php<\/code><\/h3>\nnamespace AppModels;\n\nuse IlluminateDatabaseEloquentFactoriesHasFactory;\nuse IlluminateDatabaseEloquentModel;\n\nclass Product extends Model\n{\n use HasFactory;\n\n protected $fillable = ['name', 'description', 'price'];\n\n public function orderItems()\n {\n return $this->hasMany(OrderItem::class);\n }\n}\n<\/code><\/pre>\nOrder.php<\/code><\/h3>\nnamespace AppModels;\n\nuse IlluminateDatabaseEloquentFactoriesHasFactory;\nuse IlluminateDatabaseEloquentModel;\n\nclass Order extends Model\n{\n use HasFactory;\n\n protected $fillable = ['user_id', 'total'];\n\n public function user()\n {\n return $this->belongsTo(User::class);\n }\n\n public function items()\n {\n return $this->hasMany(OrderItem::class);\n }\n}\n<\/code><\/pre>\nOrderItem.php<\/code><\/h3>\nnamespace AppModels;\n\nuse IlluminateDatabaseEloquentFactoriesHasFactory;\nuse IlluminateDatabaseEloquentModel;\n\nclass OrderItem extends Model\n{\n use HasFactory;\n\n protected $fillable = ['order_id', 'product_id', 'quantity', 'price'];\n\n public function order()\n {\n return $this->belongsTo(Order::class);\n }\n\n public function product()\n {\n return $this->belongsTo(Product::class);\n }\n}\n<\/code><\/pre>\nSetting Up Routes and Controllers<\/h2>\n
Next, let’s create the necessary routes and controllers to handle the shopping cart functionality.<\/p>\n
web.php<\/code><\/h3>\nOpen the routes\/web.php<\/code> file and add the following routes:<\/p>\nuse AppHttpControllersCartController;\nuse AppHttpControllersCheckoutController;\nuse AppHttpControllersProductController;\n\nRoute::get('\/', [ProductController::class, 'index'])->name('products.index');\nRoute::get('\/cart', [CartController::class, 'index'])->name('cart.index');\nRoute::post('\/cart', [CartController::class, 'add'])->name('cart.add');\nRoute::post('\/cart\/update', [CartController::class, 'update'])->name('cart.update');\nRoute::post('\/cart\/remove', [CartController::class, 'remove'])->name('cart.remove');\nRoute::get('\/checkout', [CheckoutController::class, 'index'])->name('checkout.index');\nRoute::post('\/checkout', [CheckoutController::class, 'store'])->name('checkout.store');\n<\/code><\/pre>\nCartController.php<\/code><\/h3>\nIn the app\/Http\/Controllers<\/code> directory, create a new file named CartController.php<\/code> with the following content:<\/p>\nnamespace AppHttpControllers;\n\nuse AppModelsProduct;\nuse GloudemansShoppingcartFacadesCart;\nuse IlluminateHttpRequest;\n\nclass CartController extends Controller\n{\n public function index()\n {\n return view('cart.index');\n }\n\n public function add(Request $request)\n {\n $product = Product::findOrFail($request->product_id);\n\n Cart::add([\n 'id' => $product->id,\n 'name' => $product->name,\n 'price' => $product->price,\n 'quantity' => $request->quantity,\n ]);\n\n return redirect()->route('cart.index')->with('success', 'Product added to cart successfully!');\n }\n\n public function update(Request $request)\n {\n Cart::update($request->rowId, $request->quantity);\n\n return redirect()->route('cart.index')->with('success', 'Cart updated successfully!');\n }\n\n public function remove(Request $request)\n {\n Cart::remove($request->rowId);\n\n return redirect()->route('cart.index')->with('success', 'Product removed from cart successfully!');\n }\n}\n<\/code><\/pre>\nCheckoutController.php<\/code><\/h3>\nIn the app\/Http\/Controllers<\/code> directory, create a new file named CheckoutController.php<\/code> with the following content:<\/p>\nnamespace AppHttpControllers;\n\nuse AppModelsOrder;\nuse AppModelsOrderItem;\nuse IlluminateHttpRequest;\nuse IlluminateSupportFacadesAuth;\nuse StripeCharge;\nuse StripeCustomer;\nuse StripeStripe;\n\nclass CheckoutController extends Controller\n{\n public function index()\n {\n return view('checkout.index');\n }\n\n public function store(Request $request)\n {\n \/\/ Set your Stripe API key\n Stripe::setApiKey(env('STRIPE_SECRET_KEY'));\n\n $customer = Customer::create([\n 'email' => $request->email,\n 'source' => $request->stripeToken,\n ]);\n\n $charge = Charge::create([\n 'customer' => $customer->id,\n 'amount' => Cart::subtotal() * 100,\n 'currency' => 'usd',\n ]);\n\n $order = Order::create([\n 'user_id' => Auth::id(),\n 'total' => Cart::subtotal(),\n ]);\n\n foreach (Cart::content() as $item) {\n OrderItem::create([\n 'order_id' => $order->id,\n 'product_id' => $item->id,\n 'quantity' => $item->qty,\n 'price' => $item->price,\n ]);\n }\n\n Cart::destroy();\n\n return redirect()->route('products.index')->with('success', 'Order placed successfully!');\n }\n}\n<\/code><\/pre>\nCreating Views<\/h2>\n
Now let’s create the necessary views to render the cart, checkout, and product pages.<\/p>\n
cart\/index.blade.php<\/code><\/h3>\nCreate a new file named index.blade.php<\/code> in the resources\/views\/cart<\/code> directory with the following content:<\/p>\n@extends('layouts.app')\n\n@section('content')\n <div class=\"container\">\n @if (session('success'))\n <div class=\"alert alert-success\">{{ session('success') }}<\/div>\n @endif\n\n <h2>Shopping Cart<\/h2>\n\n <table class=\"table table-striped\">\n <thead>\n <tr>\n <th>Product<\/th>\n <th>Quantity<\/th>\n <th>Price<\/th>\n <th>Total<\/th>\n <th>Actions<\/th>\n <\/tr>\n <\/thead>\n <tbody>\n @foreach (Cart::content() as $item)\n <tr>\n <td>{{ $item->name }}<\/td>\n <td>\n <form action=\"{{ route('cart.update') }}\" method=\"POST\" class=\"d-inline-block\">\n @csrf\n <input type=\"hidden\" name=\"rowId\" value=\"{{ $item->rowId }}\">\n <input type=\"number\" name=\"quantity\" value=\"{{ $item->qty }}\">\n <button type=\"submit\" class=\"btn btn-link btn-sm\">Update<\/button>\n <\/form>\n <form action=\"{{ route('cart.remove') }}\" method=\"POST\" class=\"d-inline-block\">\n @csrf\n <input type=\"hidden\" name=\"rowId\" value=\"{{ $item->rowId }}\">\n <button type=\"submit\" class=\"btn btn-link btn-sm\">Remove<\/button>\n <\/form>\n <\/td>\n <td>{{ $item->price }}<\/td>\n <td>{{ $item->subtotal }}<\/td>\n <td><\/td>\n <\/tr>\n @endforeach\n <\/tbody>\n <\/table>\n <\/div>\n@endsection\n<\/code><\/pre>\ncheckout\/index.blade.php<\/code><\/h3>\nCreate a new file named index.blade.php<\/code> in the resources\/views\/checkout<\/code> directory with the following content:<\/p>\n@extends('layouts.app')\n\n@section('content')\n <div class=\"container\">\n <h2>Checkout<\/h2>\n\n <form action=\"{{ route('checkout.store') }}\" method=\"POST\" id=\"payment-form\">\n @csrf\n\n <div class=\"form-group\">\n <label for=\"email\">Email<\/label>\n <input type=\"email\" name=\"email\" id=\"email\" class=\"form-control\" required>\n <\/div>\n\n <div id=\"card-element\" class=\"form-group\">\n <!-- Stripe Elements Placeholder -->\n <\/div>\n\n <button type=\"submit\" class=\"btn btn-primary\">Place Order<\/button>\n <\/form>\n <\/div>\n\n <script src=\"https:\/\/js.stripe.com\/v3\/\"><\/script>\n <script>\n var stripe = Stripe('{{ env('STRIPE_PUBLIC_KEY') }}');\n var elements = stripe.elements();\n\n var style = {\n base: {\n color: '#32325d',\n fontFamily: '\"Helvetica Neue\", Helvetica, sans-serif',\n fontSmoothing: 'antialiased',\n fontSize: '16px',\n '::placeholder': {\n color: '#aab7c4'\n }\n },\n invalid: {\n color: '#fa755a',\n iconColor: '#fa755a'\n }\n };\n\n var cardElement = elements.create('card', { style: style });\n cardElement.mount('#card-element');\n\n var cardForm = document.getElementById('payment-form');\n cardForm.addEventListener('submit', function (event) {\n event.preventDefault();\n\n stripe.createToken(cardElement).then(function (result) {\n if (result.error) {\n var errorElement = document.getElementById('card-errors');\n errorElement.textContent = result.error.message;\n } else {\n stripeTokenHandler(result.token);\n }\n });\n });\n\n function stripeTokenHandler(token) {\n var form = document.getElementById('payment-form');\n var hiddenInput = document.createElement('input');\n hiddenInput.setAttribute('type', 'hidden');\n hiddenInput.setAttribute('name', 'stripeToken');\n hiddenInput.setAttribute('value', token.id);\n form.appendChild(hiddenInput);\n\n form.submit();\n }\n <\/script>\n@endsection\n<\/code><\/pre>\nlayouts\/app.blade.php<\/code><\/h3>\nOpen the resources\/views\/layouts\/app.blade.php<\/code> file and update the content as follows:<\/p>\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>Shopping Cart<\/title>\n <link href=\"{{ asset('css\/app.css') }}\" rel=\"stylesheet\">\n<\/head>\n<body>\n <nav class=\"navbar navbar-expand-lg navbar-light bg-light\">\n <div class=\"container\">\n <a class=\"navbar-brand\" href=\"{{ route('products.index') }}\">Shopping Cart<\/a>\n <ul class=\"navbar-nav ml-auto\">\n <li class=\"nav-item\">\n <a class=\"nav-link\" href=\"{{ route('cart.index') }}\">Cart ({{ Cart::count() }})<\/a>\n <\/li>\n <\/ul>\n <\/div>\n <\/nav>\n\n <div class=\"py-4\">\n @yield('content')\n <\/div>\n\n <script src=\"{{ asset('js\/app.js') }}\"><\/script>\n<\/body>\n<\/html>\n<\/code><\/pre>\nproducts\/index.blade.php<\/code><\/h3>\nCreate a new file named index.blade.php<\/code> in the resources\/views\/products<\/code> directory with the following content:<\/p>\n@extends('layouts.app')\n\n@section('content')\n <div class=\"container\">\n <h2>Products<\/h2>\n\n <div class=\"row\">\n @foreach ($products as $product)\n <div class=\"col-md-4 mb-4\">\n <div class=\"card\">\n <div class=\"card-body\">\n <h5 class=\"card-title\">{{ $product->name }}<\/h5>\n <p class=\"card-text\">{{ $product->description }}<\/p>\n <p class=\"card-text\">${{ $product->price }}<\/p>\n <form action=\"{{ route('cart.add') }}\" method=\"POST\">\n @csrf\n <input type=\"hidden\" name=\"product_id\" value=\"{{ $product->id }}\">\n <div class=\"form-group\">\n <input type=\"number\" name=\"quantity\" value=\"1\" class=\"form-control\" min=\"1\" required>\n <\/div>\n <button type=\"submit\" class=\"btn btn-primary\">Add to Cart<\/button>\n <\/form>\n <\/div>\n <\/div>\n <\/div>\n @endforeach\n <\/div>\n <\/div>\n@endsection\n<\/code><\/pre>\nCreating Products<\/h2>\n
To quickly populate the database with some sample products, open the database\/seeders\/DatabaseSeeder.php<\/code> file and update the run<\/code> method as follows:<\/p>\npublic function run()\n{\n AppModelsProduct::factory(10)->create();\n}\n<\/code><\/pre>\nNext, run the following command to seed the database:<\/p>\n
php artisan db:seed\n<\/code><\/pre>\nStripe Configuration<\/h2>\n
To process payments with Stripe, you need to set your Stripe API key in the .env<\/code> file. Open the .env<\/code> file and add the following line:<\/p>\nSTRIPE_PUBLIC_KEY=\nSTRIPE_SECRET_KEY=\n<\/code><\/pre>\nWrapping Up<\/h2>\n
Congratulations! You have successfully built a shopping cart with Laravel and Stripe. You can now add products to the cart, update quantities, and checkout using Stripe for secure payments.<\/p>\n
To test the shopping cart, start the Laravel development server by running the following command:<\/p>\n
php artisan serve\n<\/code><\/pre>\nOpen your web browser and navigate to http:\/\/localhost:8000` to view the list of products. Add some products to the cart and proceed to the checkout page. Enter your email address and use the test card number<\/code>4242 4242 4242 4242` with any future expiration date and CVC code. After submitting the form, you should see a success message indicating that the order was placed successfully.<\/p>\nFeel free to customize and enhance the shopping cart according to your project requirements. Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"
In this tutorial, we will learn how to build a shopping cart using Laravel, a popular PHP framework, and Stripe, a powerful payment gateway. By the end of this tutorial, you will have a fully functional shopping cart where users can add products, update quantities, and checkout using Stripe for Continue Reading<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_import_markdown_pro_load_document_selector":0,"_import_markdown_pro_submit_text_textarea":"","footnotes":""},"categories":[1],"tags":[797,799,795,798,800,796,794],"yoast_head":"\nHow to Build a Shopping Cart with Laravel and Stripe - Pantherax Blogs<\/title>\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\t\n\t\n