Simple Guide with example in building laravel 12 project:
TO BEGIN (Laravel 12):
-download composer https://getcomposer.org/
-php.ini in xampp folder remove ";" in extension=zip -(in cmd):
composer global require laravel/installer
composer create-project laravel/laravel name_of_the_project (in the specific folder) -open folder in VS Code
LOGIN MODULE (in VS Code terminal):
- if npm not recognize:
go to "https://nodejs.org/en" and download
then go to environment variables add to path "C:\Program Files\nodejs\"
In terminal "Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned"
- install laravel breeze:
composer require laravel/breeze --dev
php artisan breeze:install blade
npm install
npm run dev
php artisan migrate (set the .env mysql)
php artisan serve
CRUD MODULE (in VS Code terminal):
- model/controller/migration:
php artisan make:model Product -mcr
-migration [(php artisan migrate) after doing this]:
$table->data_type('name_of_the_attribute', range)->nullable; (do not put nullable if required)
ex.:
public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description')->nullable();
$table->decimal('price', 10, 2);
$table->integer('quantity');
$table->timestamps();
});
}
-model (based on the attributes names to fill):
ex.:
protected $fillable = [
'name',
'description',
'price',
'quantity',
];
-controller (example Product):
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
// Show all products
public function index()
{
$products = Product::all();
return view('products.index', compact('products'));
}
// Show form to create a new product
public function create()
{
return view('products.create');
}
// Save new product to database
public function store(Request $request)
{
$request->validate([
'name' => 'required',
'price' => 'required|numeric',
'quantity' => 'required|integer',
]);
Product::create($request->all());
return redirect()->route('products.index')->with('success', 'Product added successfully!');
}
// Show form to edit a product
public function edit(Product $product)
{
return view('products.edit', compact('product'));
}
// Update product in database
public function update(Request $request, Product $product)
{
$request->validate([
'name' => 'required',
'price' => 'required|numeric',
'quantity' => 'required|integer',
]);
$product->update($request->all());
return redirect()->route('products.index')->with('success', 'Product updated successfully!');
}
// Delete product from database
public function destroy(Product $product)
{
$product->delete();
return redirect()->route('products.index')->with('success', 'Product deleted successfully!');
}
}
- routes (web.php):
<?php
use App\Http\Controllers\ProfileController;
use App\Http\Controllers\ProductController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
Route::middleware('auth')->group(function () {
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');
Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update');
Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy');
// Product CRUD routes
Route::resource('products', ProductController::class);
});
require __DIR__.'/auth.php';
-views blade (/products):
/index.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Products
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg p-6">
{{-- Success Message --}}
@if(session('success'))
<div class="bg-green-100 text-green-800 px-4 py-2 rounded mb-4">
{{ session('success') }}
</div>
@endif
{{-- Add Button --}}
<a href="{{ route('products.create') }}"
class="bg-blue-500 text-white px-4 py-2 rounded mb-4 inline-block">
+ Add Product
</a>
{{-- Products Table --}}
<table class="w-full mt-4 border">
<thead class="bg-gray-100">
<tr>
<th class="border px-4 py-2">#</th>
<th class="border px-4 py-2">Name</th>
<th class="border px-4 py-2">Description</th>
<th class="border px-4 py-2">Price</th>
<th class="border px-4 py-2">Quantity</th>
<th class="border px-4 py-2">Actions</th>
</tr>
</thead>
<tbody>
@foreach($products as $product)
<tr>
<td class="border px-4 py-2">{{ $loop->iteration }}</td>
<td class="border px-4 py-2">{{ $product->name }}</td>
<td class="border px-4 py-2">{{ $product->description }}</td>
<td class="border px-4 py-2">{{ $product->price }}</td>
<td class="border px-4 py-2">{{ $product->quantity }}</td>
<td class="border px-4 py-2">
<a href="{{ route('products.edit', $product->id) }}"
class="bg-yellow-400 text-white px-3 py-1 rounded">Edit</a>
<form action="{{ route('products.destroy', $product->id) }}"
method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit"
class="bg-red-500 text-white px-3 py-1 rounded"
onclick="return confirm('Are you sure?')">
Delete
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
</div>
</x-app-layout>
/create.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Add New Product
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg p-6">
<form action="{{ route('products.store') }}" method="POST">
@csrf
{{-- Name --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Product Name</label>
<input type="text" name="name" value="{{ old('name') }}"
class="w-full border rounded px-3 py-2"
placeholder="Enter product name">
@error('name')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
{{-- Description --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Description</label>
<textarea name="description"
class="w-full border rounded px-3 py-2"
placeholder="Enter description">{{ old('description') }}</textarea>
</div>
{{-- Price --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Price</label>
<input type="number" name="price" value="{{ old('price') }}"
class="w-full border rounded px-3 py-2"
placeholder="Enter price" step="0.01">
@error('price')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
{{-- Quantity --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Quantity</label>
<input type="number" name="quantity" value="{{ old('quantity') }}"
class="w-full border rounded px-3 py-2"
placeholder="Enter quantity">
@error('quantity')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
{{-- Buttons --}}
<div class="flex gap-2">
<button type="submit"
class="bg-blue-500 text-white px-4 py-2 rounded">
Save Product
</button>
<a href="{{ route('products.index') }}"
class="bg-gray-400 text-white px-4 py-2 rounded">
Cancel
</a>
</div>
</form>
</div>
</div>
</div>
</x-app-layout>
/edit.blade.php
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Edit Product
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg p-6">
<form action="{{ route('products.update', $product->id) }}" method="POST">
@csrf
@method('PUT')
{{-- Name --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Product Name</label>
<input type="text" name="name" value="{{ old('name', $product->name) }}"
class="w-full border rounded px-3 py-2">
@error('name')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
{{-- Description --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Description</label>
<textarea name="description"
class="w-full border rounded px-3 py-2">{{ old('description', $product->description) }}</textarea>
</div>
{{-- Price --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Price</label>
<input type="number" name="price" value="{{ old('price', $product->price) }}"
class="w-full border rounded px-3 py-2"
step="0.01">
@error('price')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
{{-- Quantity --}}
<div class="mb-4">
<label class="block text-gray-700 font-bold mb-2">Quantity</label>
<input type="number" name="quantity" value="{{ old('quantity', $product->quantity) }}"
class="w-full border rounded px-3 py-2">
@error('quantity')
<p class="text-red-500 text-sm mt-1">{{ $message }}</p>
@enderror
</div>
{{-- Buttons --}}
<div class="flex gap-2">
<button type="submit"
class="bg-yellow-400 text-white px-4 py-2 rounded">
Update Product
</button>
<a href="{{ route('products.index') }}"
class="bg-gray-400 text-white px-4 py-2 rounded">
Cancel
</a>
</div>
</form>
</div>
</div>
</div>
</x-app-layout>
- layout navigation (Navigation links) part:
<x-nav-link :href="route('products.index')" :active="request()->routeIs('products.*')">
{{ __('Products') }}
</x-nav-link>
EXPORT PDF CSV (In VS Code terminal):
-in php.ini remove the ";" in extension=gd then:
composer require maatwebsite/excel
composer require barryvdh/laravel-dompdf
php artisan make:export ProductsExport --model=Product
-In export file:
<?php
namespace App\Exports;
use App\Models\Product;
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
class ProductsExport implements FromCollection, WithHeadings
{
/**
* @return \Illuminate\Support\Collection
*/
public function collection()
{
return Product::all();
}
public function headings(): array
{
return [
'ID',
'Name',
'Description',
'Price',
'Quantity',
'Created At',
'Updated At',
];
}
}
-In controller head:
namespace App\Http\Controllers;
use App\Models\Product;
use App\Exports\ProductsExport;
use Maatwebsite\Excel\Facades\Excel;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\Request;
-In bottom:
// Export to Excel
public function exportExcel()
{
return Excel::download(new ProductsExport, 'products.xlsx');
}
// Export to CSV
public function exportCsv()
{
return Excel::download(new ProductsExport, 'products.csv', \Maatwebsite\Excel\Excel::CSV);
}
// Export to PDF
public function exportPdf()
{
$products = Product::all();
$pdf = Pdf::loadView('products.pdf', compact('products'));
return $pdf->download('products.pdf');
}
-In routes bottom of the CRUD earlier:
Route::get('products-export-excel', [ProductController::class, 'exportExcel'])->name('products.export.excel');
Route::get('products-export-csv', [ProductController::class, 'exportCsv'])->name('products.export.csv');
Route::get('products-export-pdf', [ProductController::class, 'exportPdf'])->name('products.export.pdf');
});
-In views product folder pdf.blade.php:
<!DOCTYPE html>
<html>
<head>
<title>Products Report</title>
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
}
h2 {
text-align: center;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th {
background-color: #4a90e2;
color: white;
padding: 8px;
text-align: left;
}
td {
border: 1px solid #ddd;
padding: 8px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
.footer {
margin-top: 20px;
text-align: center;
font-size: 10px;
color: gray;
}
</style>
</head>
<body>
<h2>Inventory Products Report</h2>
<p style="text-align:center;">Generated on: {{ date('F d, Y') }}</p>
<table>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
<th>Created At</th>
</tr>
</thead>
<tbody>
@foreach($products as $index => $product)
<tr>
<td>{{ $index + 1 }}</td>
<td>{{ $product->name }}</td>
<td>{{ $product->description }}</td>
<td>{{ $product->price }}</td>
<td>{{ $product->quantity }}</td>
<td>{{ $product->created_at->format('M d, Y') }}</td>
</tr>
@endforeach
</tbody>
</table>
<div class="footer">
Inventory System © {{ date('Y') }}
</div>
</body>
</html>
-In index.blade/php part under ADD BUTTON:
{{-- Export Buttons --}}
<a href="{{ route('products.export.excel') }}"
class="bg-green-500 text-white px-4 py-2 rounded mb-4 inline-block">
Export Excel
</a>
<a href="{{ route('products.export.csv') }}"
class="bg-yellow-500 text-white px-4 py-2 rounded mb-4 inline-block">
Export CSV
</a>
<a href="{{ route('products.export.pdf') }}"
class="bg-red-500 text-white px-4 py-2 rounded mb-4 inline-block">
Export PDF
</a>
IF WANT TO DO COMPUTATION:
- go to model under the protected $fillable:
public function getTotalValueAttribute()
{
return $this->price * $this->quantity;
}
- in export file add:
in headings add 'Total Value',
use Maatwebsite\Excel\Concerns\WithMapping;
class ProductsExport implements FromCollection, WithHeadings, WithMapping
{
public function collection()
{
return Product::all();
}
public function headings(): array
{
return [
'ID',
'Name',
'Description',
'Price',
'Quantity',
'Total Value',
'Created At',
'Updated At',
];
}
public function map($product): array
{
return [
$product->id,
$product->name,
$product->description,
$product->price,
$product->quantity,
$product->total_value, // computed!
$product->created_at,
$product->updated_at,
];
}
}
- in index.php:
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
Products
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-sm sm:rounded-lg p-6">
{{-- Success Message --}}
@if(session('success'))
<div class="bg-green-100 text-green-800 px-4 py-2 rounded mb-4">
{{ session('success') }}
</div>
@endif
{{-- Buttons --}}
<a href="{{ route('products.create') }}"
class="bg-blue-500 text-white px-4 py-2 rounded mb-4 inline-block">
+ Add Product
</a>
<a href="{{ route('products.export.excel') }}"
class="bg-green-500 text-white px-4 py-2 rounded mb-4 inline-block">
Export Excel
</a>
<a href="{{ route('products.export.csv') }}"
class="bg-yellow-500 text-white px-4 py-2 rounded mb-4 inline-block">
Export CSV
</a>
<a href="{{ route('products.export.pdf') }}"
class="bg-red-500 text-white px-4 py-2 rounded mb-4 inline-block">
Export PDF
</a>
{{-- Products Table --}}
<table class="w-full mt-4 border">
<thead class="bg-gray-100">
<tr>
<th class="border px-4 py-2">#</th>
<th class="border px-4 py-2">Name</th>
<th class="border px-4 py-2">Description</th>
<th class="border px-4 py-2">Price</th>
<th class="border px-4 py-2">Quantity</th>
{{-- Total Value Column --}}
<th class="border px-4 py-2">Total Value</th>
<th class="border px-4 py-2">Actions</th>
</tr>
</thead>
<tbody>
@foreach($products as $product)
<tr>
<td class="border px-4 py-2">{{ $loop->iteration }}</td>
<td class="border px-4 py-2">{{ $product->name }}</td>
<td class="border px-4 py-2">{{ $product->description }}</td>
<td class="border px-4 py-2">₱{{ number_format($product->price, 2) }}</td>
<td class="border px-4 py-2">{{ $product->quantity }}</td>
{{-- Computed Total Value --}}
<td class="border px-4 py-2">₱{{ number_format($product->total_value, 2) }}</td>
<td class="border px-4 py-2">
<a href="{{ route('products.edit', $product->id) }}"
class="bg-yellow-400 text-white px-3 py-1 rounded">Edit</a>
<form action="{{ route('products.destroy', $product->id) }}"
method="POST" class="inline">
@csrf
@method('DELETE')
<button type="submit"
class="bg-red-500 text-white px-3 py-1 rounded"
onclick="return confirm('Are you sure?')">
Delete
</button>
</form>
</td>
</tr>
@endforeach
</tbody>
{{-- Grand Total Row --}}
<tfoot>
<tr class="bg-gray-100 font-bold">
<td class="border px-4 py-2" colspan="5"
style="text-align:right;">Grand Total:</td>
<td class="border px-4 py-2">
₱{{ number_format($products->sum(function($p){
return $p->price * $p->quantity;
}), 2) }}
</td>
<td class="border px-4 py-2"></td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
</x-app-layout>
- in pdf.blade.php
<!DOCTYPE html>
<html>
<head>
<title>Products Report</title>
<style>
body {
font-family: Arial, sans-serif;
font-size: 12px;
}
h2 {
text-align: center;
}
p {
text-align: center;
}
table {
width: 100%;
border-collapse: collapse;
margin-top: 20px;
}
th {
background-color: #4a90e2;
color: white;
padding: 8px;
text-align: left;
}
td {
border: 1px solid #ddd;
padding: 8px;
}
tr:nth-child(even) {
background-color: #f2f2f2;
}
.grand-total {
font-weight: bold;
background-color: #e8e8e8;
text-align: right;
}
.footer {
margin-top: 20px;
text-align: center;
font-size: 10px;
color: gray;
}
</style>
</head>
<body>
<h2>Inventory Products Report</h2>
<p>Generated on: {{ date('F d, Y') }}</p>
<table>
<thead>
<tr>
<th>#</th>
<th>Name</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
{{-- Total Value Column --}}
<th>Total Value</th>
<th>Created At</th>
</tr>
</thead>
<tbody>
@foreach($products as $index => $product)
<tr>
<td>{{ $index + 1 }}</td>
<td>{{ $product->name }}</td>
<td>{{ $product->description }}</td>
<td>₱{{ number_format($product->price, 2) }}</td>
<td>{{ $product->quantity }}</td>
{{-- Computed Total Value --}}
<td>₱{{ number_format($product->total_value, 2) }}</td>
<td>{{ $product->created_at->format('M d, Y') }}</td>
</tr>
@endforeach
</tbody>
{{-- Grand Total Row --}}
<tfoot>
<tr>
<td colspan="5" class="grand-total">Grand Total:</td>
<td>₱{{ number_format($products->sum(function($p){
return $p->price * $p->quantity;
}), 2) }}</td>
<td></td>
</tr>
</tfoot>
</table>
<div class="footer">
Inventory System © {{ date('Y') }}
</div>
</body>
</html>