Laravel 12 - Simple Guide MVC

8 hours ago 1
ARTICLE AD BOX

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 &copy; {{ 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 &copy; {{ date('Y') }} </div> </body> </html>
Read Entire Article