We continue our journey of building the Invoicing app in Laravel 9. In order to continue here, you need to go through last couple of articles where we defined models, migrations and invoice template. Following are the links to those previous articles which are prerequisite before proceeding ahead in this article:
- Invoicing app in Laravel 9 – migrations and models
- Invoicing app in Laravel 9 – invoice template using dompdf
So, let’s continue from where we left in the article enlisted above. In this tutorial we’ll create Laravel 9 CRUD (Create, Read, Update, Delete) operations for Customer and Item models with classic Blade views utilizing Bootstrap 5 along with jQuery for interactivity.
Without further ado, let’s enter following command inside project’s parent (app) folder in order to install laravel/ui package:
composer require laravel/ui
Then enter following command to install laravel/ui package along with authentication scaffolding:
php artisan ui bootstrap --auth
Next, enter following commands to install node modules and compile UI assets:
npm install && npm run build
In order to incorporate jQuery, open resources/views/layouts/app.blade.php and insert following script tag inside <head>:
//...
<head>
//...
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.3/dist/jquery.min.js"></script>
</head>
Next, we’ll create controllers and views for Customer and Item models. So, execute following command in parent folder in order to create CustomerController.php:
php artisan make:controller CustomerController --model=Customer --resource
Similarly, execute following command to create ItemController.php:
php artisan make:controller ItemController --model=Item --resource
Then, open app/Http/Controllers/CustomerController.php and amend it as follows in order to define basic CRUD functions:
<?php
namespace App\Http\Controllers;
use App\Models\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
public function index()
{
$customers = Customer::all();
return view('customers.index', compact('customers'));
}
public function create()
{
return view('customers.create');
}
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string',
'email' => 'nullable|string',
'phone' => 'nullable|string',
'address' => 'nullable|string',
]);
$item = Customer::create($validated);
return redirect('customers')->with('success', 'Customer created.');
}
public function show(Customer $customer)
{
}
public function edit(Customer $customer)
{
return view('customers.edit', compact('customer'));
}
public function update(Request $request, Customer $customer)
{
$validated = $request->validate([
'name' => 'required|string',
'email' => 'nullable|string',
'phone' => 'nullable|string',
'address' => 'nullable|string',
]);
$customer->update($validated);
return redirect('customers')->with('success', 'Customer updated.');
}
public function destroy(Customer $customer)
{
$customer->delete();
return back()->with('success', 'Customer deleted.');
}
}
Similarly, open app/Http/Controllers/ItemController.php and amend it as follows;
<?php
namespace App\Http\Controllers;
use App\Models\Item;
use Illuminate\Http\Request;
class ItemController extends Controller
{
public function index()
{
$items = Item::all();
return view('items.index', compact('items'));
}
public function create()
{
return view('items.create');
}
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|string',
'unit' => 'nullable|string',
'description' => 'nullable|string',
'sale_rate' => 'required|decimal:0,2',
'purchase_rate' => 'required|decimal:0,2',
'quantity' => 'required|numeric',
]);
$item = Item::create($validated);
return redirect('items')->with('success', 'Item created.');
}
public function show(Item $item)
{
}
public function edit(Item $item)
{
return view('items.edit', compact('item'));
}
public function update(Request $request, Item $item)
{
$validated = $request->validate([
'name' => 'required|string',
'unit' => 'nullable|string',
'description' => 'nullable|string',
'sale_rate' => 'required|decimal:0,2',
'purchase_rate' => 'required|decimal:0,2',
'quantity' => 'required|numeric',
]);
$item->update($validated);
return redirect('items')->with('success', 'Item updated.');
}
public function destroy(Item $item)
{
$item->delete();
return back()->with('success', 'Item deleted.');
}
}
In order to define routes, open routes/web.php and put the following lines at the upper side of it:
//...
use App\Http\Controllers\CustomerController;
use App\Http\Controllers\ItemController;
//...
And then, insert following routes down somewhere into this routes/web.php:
//...
Route::resource('customers', CustomerController::class)->middleware(['auth']);
Route::resource('items', ItemController::class)->middleware(['auth']);
We’re done with the controllers and routing. Now let’s create views using Blade templates.
First, create folders customers and items inside resources/views folder. Being in parent folder, you may execute following command to create these folders:
mkdir resources/views/{customers,items}
Now create following three files inside each of the above created folders:
- index.blade.php
- create.blade.php
- edit.blade.php
You can execute following command inside parent folder to create these files in one go:
touch resources/views/{customers,items}/{index,create,edit}.blade.php
Go inside resources/views/customers folder and insert following code into index.blade.php;
@extends('layouts.app')
@section('content')
<div class="row">
<div class="m-2">
<div class="p-2">
<h2>Customers</h2>
</div>
<div class="p-2">
<a class="btn btn-primary" href="{{ route('customers.create') }}">Create New Customer</a>
</div>
</div>
</div>
@if ($message = session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ $message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Email</th>
<th>Phone</th>
<th>Address</th>
<th class="d-flex justify-content-center">Actions</th>
</tr>
@foreach ($customers as $customer)
<tr>
<td>{{ $customer->name }}</td>
<td>{{ $customer->email }}</td>
<td>{{ $customer->phone }}</td>
<td>{{ $customer->address }}</td>
<td class="d-flex justify-content-around">
<a class="btn btn-sm btn-secondary" href="{{ route('customers.edit', $customer->id) }}">Edit</a>
<form action="{{ route('customers.destroy', $customer->id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
@endforeach
</table>
@endsection
Then, insert following code into create.blade.php;
@extends('layouts.app')
@section('content')
<div class="card m-4">
<div class="card-header">
<h4>Create Customer</h4>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="post" action="{{ route('customers.store') }}">
@csrf
<div class="row p-2">
<div class="col-md-6">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control form-control-sm" name="name"/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control form-control-sm" name="email"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="phone">Phone</label>
<input type="text" class="form-control form-control-sm" name="phone"/>
</div>
<div class="form-group">
<label for="address">Address</label>
<input type="text" class="form-control form-control-sm" name="address"/>
</div>
</div>
</div>
<button type="submit" class="btn btn-sm btn-secondary m-2">Add Customer</button>
</form>
</div>
</div>
@endsection
And then, insert following code into edit.blade.php;
@extends('layouts.app')
@section('content')
<div class="card m-4">
<div class="card-header">
<h4>Edit Customer</h4>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('customers.update', $customer->id) }}" method="POST">
@csrf
@method('PUT')
<div class="row p-2">
<div class="col-md-6">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control form-control-sm" name="name" value="{{ $customer->name }}"/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input type="text" class="form-control form-control-sm" name="email" value="{{ $customer->email }}"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="phone">Phone</label>
<input type="text" class="form-control form-control-sm" name="phone" value="{{ $customer->phone }}"/>
</div>
<div class="form-group">
<label for="address">Address</label>
<input type="text" class="form-control form-control-sm" name="address" value="{{ $customer->address }}"/>
</div>
</div>
</div>
<button type="submit" class="btn btn-sm btn-secondary m-2">Submit</button>
</form>
</div>
</div>
@endsection
Similarly, go inside resources/views/items folder and insert following code into index.blade.php;
@extends('layouts.app')
@section('content')
<div class="row">
<div class="m-2">
<div class="p-2">
<h2>Stock Items</h2>
</div>
<div class="p-2">
<a class="btn btn-primary" href="{{ route('items.create') }}">Create New Item</a>
</div>
</div>
</div>
@if ($message = session('success'))
<div class="alert alert-success alert-dismissible fade show" role="alert">
{{ $message }}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
@endif
<table class="table table-hover">
<tr>
<th>Name</th>
<th>Unit</th>
<th>Description</th>
<th>Sale Rate</th>
<th>Purchase Rate</th>
<th>Quantity</th>
<th class="d-flex justify-content-center">Actions</th>
</tr>
@foreach ($items as $item)
<tr>
<td>{{ $item->name }}</td>
<td>{{ $item->unit }}</td>
<td>{{ $item->description }}</td>
<td>{{ $item->sale_rate }}</td>
<td>{{ $item->purchase_rate }}</td>
<td>{{ $item->quantity }}</td>
<td class="d-flex justify-content-around">
<a class="btn btn-sm btn-secondary" href="{{ route('items.edit', $item->id) }}">Edit</a>
<form action="{{ route('items.destroy', $item->id) }}" method="POST">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
</form>
</td>
</tr>
@endforeach
</table>
@endsection
Then, insert following code into create.blade.php:
@extends('layouts.app')
@section('content')
<div class="card m-4">
<div class="card-header">
<h4>Create Item</h4>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="post" action="{{ route('items.store') }}">
@csrf
<div class="row p-2">
<div class="col-md-6">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control form-control-sm" name="name"/>
</div>
<div class="form-group">
<label for="unit">Unit</label>
<input type="text" class="form-control form-control-sm" name="unit"/>
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" class="form-control form-control-sm" name="description"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="sale_rate">Sale Rate</label>
<input type="text" class="form-control form-control-sm" name="sale_rate"/>
</div>
<div class="form-group">
<label for="purchase_rate">Purchase Rate</label>
<input type="text" class="form-control form-control-sm" name="purchase_rate"/>
</div>
<div class="form-group">
<label for="quantity">Quantity</label>
<input type="text" class="form-control form-control-sm" name="quantity"/>
</div>
</div>
</div>
<button type="submit" class="btn btn-sm btn-secondary m-2">Add Item</button>
</form>
</div>
</div>
@endsection
And then, insert following code into edit.blade.php:
@extends('layouts.app')
@section('content')
<div class="card m-4">
<div class="card-header">
<h4>Edit Item</h4>
</div>
<div class="card-body">
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form action="{{ route('items.update', $item->id) }}" method="POST">
@csrf
@method('PUT')
<div class="row p-2">
<div class="col-md-6">
<div class="form-group">
<label for="name">Name</label>
<input type="text" class="form-control form-control-sm" name="name" value="{{ $item->name }}"/>
</div>
<div class="form-group">
<label for="unit">Unit</label>
<input type="text" class="form-control form-control-sm" name="unit" value="{{ $item->unit }}"/>
</div>
<div class="form-group">
<label for="description">Description</label>
<input type="text" class="form-control form-control-sm" name="description" value="{{ $item->description }}"/>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="sale_rate">Sale Rate</label>
<input type="text" class="form-control form-control-sm" name="sale_rate" value="{{ $item->sale_rate }}"/>
</div>
<div class="form-group">
<label for="purchase_rate">Purchase Rate</label>
<input type="text" class="form-control form-control-sm" name="purchase_rate" value="{{ $item->purchase_rate }}"/>
</div>
<div class="form-group">
<label for="quantity">Quantity</label>
<input type="text" class="form-control form-control-sm" name="quantity" value="{{ $item->quantity }}"/>
</div>
</div>
</div>
<button type="submit" class="btn btn-sm btn-secondary m-2">Submit</button>
</form>
</div>
</div>
@endsection
Views are done! Here, you may enter following command to start PHP dev server:
php artisan serv
And then enter following URL in the browser and test CRUD operations (don’t forget to create a user login first):
http://localhost:8000/items
We’ll continue in Part 2 with the controller and views for Invoice model, and that’s where the real action will begin…
3 thoughts on “Invoicing app in Laravel 9 using Bootstrap and jQuery – Part 1”