Could we help you? Please click the banners. We are young and desperately need the money
Laravel is one of the most popular PHP frameworks, known for its elegant syntax and powerful features. At its core, Laravel follows the MVC (Model-View-Controller) architectural pattern, which helps developers organize code in a clean and maintainable way. This blog post will introduce you to Laravel's MVC structure, explain how it works, and provide real-world examples to help beginners understand this essential concept.
MVC stands for Model-View-Controller, a design pattern that separates an application into three interconnected components. This separation helps organize code, making it easier to manage, test, and scale your applications.
The MVC pattern offers several advantages for web development:
Let's explore each component of Laravel's MVC pattern with practical examples.
In Laravel, models are stored in the app/Models directory. A model represents a database table and provides methods to interact with that data. Laravel uses Eloquent ORM (Object-Relational Mapping) to make database operations simple and intuitive.
Example: Creating a Product Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $fillable = ['name', 'description', 'price', 'stock'];
// Relationship: A product belongs to a category
public function category()
{
return $this->belongsTo(Category::class);
}
// Custom method to check if product is in stock
public function isInStock()
{
return $this->stock > 0;
}
// Scope to get only available products
public function scopeAvailable($query)
{
return $query->where('stock', '>', 0);
}
}
This model handles all product-related data operations. You can easily retrieve, create, update, or delete products without writing raw SQL queries.
Controllers are stored in the app/Http/Controllers directory. They handle incoming HTTP requests, process them, and return responses. Controllers use models to retrieve data and pass it to views.
Example: ProductController
<?php
namespace App\Http\Controllers;
use App\Models\Product;
use Illuminate\Http\Request;
class ProductController extends Controller
{
// Display all products
public function index()
{
$products = Product::available()->with('category')->get();
return view('products.index', compact('products'));
}
// Show single product
public function show($id)
{
$product = Product::findOrFail($id);
return view('products.show', compact('product'));
}
// Show form to create new product
public function create()
{
return view('products.create');
}
// Store new product
public function store(Request $request)
{
$validated = $request->validate([
'name' => 'required|max:255',
'description' => 'required',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0'
]);
Product::create($validated);
return redirect()->route('products.index')
->with('success', 'Product created successfully!');
}
// Show form to edit product
public function edit($id)
{
$product = Product::findOrFail($id);
return view('products.edit', compact('product'));
}
// Update product
public function update(Request $request, $id)
{
$product = Product::findOrFail($id);
$validated = $request->validate([
'name' => 'required|max:255',
'description' => 'required',
'price' => 'required|numeric|min:0',
'stock' => 'required|integer|min:0'
]);
$product->update($validated);
return redirect()->route('products.index')
->with('success', 'Product updated successfully!');
}
// Delete product
public function destroy($id)
{
$product = Product::findOrFail($id);
$product->delete();
return redirect()->route('products.index')
->with('success', 'Product deleted successfully!');
}
}
This controller demonstrates CRUD (Create, Read, Update, Delete) operations. Each method has a specific purpose and returns the appropriate view with necessary data.
Views are stored in the resources/views directory. Laravel uses the Blade templating engine, which provides a clean syntax for displaying data and creating reusable layouts.
Example: Product List View (products/index.blade.php)
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Products</h1>
@if(session('success'))
<div class="alert alert-success">
{{ session('success') }}
</div>
@endif
<a href="{{ route('products.create') }}" class="btn btn-primary mb-3">
Add New Product
</a>
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Category</th>
<th>Price</th>
<th>Stock</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@forelse($products as $product)
<tr>
<td>{{ $product->name }}</td>
<td>{{ $product->category->name }}</td>
<td>${{ number_format($product->price, 2) }}</td>
<td>
@if($product->isInStock())
<span class="badge bg-success">{{ $product->stock }} in stock</span>
@else
<span class="badge bg-danger">Out of stock</span>
@endif
</td>
<td>
<a href="{{ route('products.show', $product->id) }}" class="btn btn-sm btn-info">View</a>
<a href="{{ route('products.edit', $product->id) }}" class="btn btn-sm btn-warning">Edit</a>
<form action="{{ route('products.destroy', $product->id) }}" method="POST" style="display:inline">
@csrf
@method('DELETE')
<button type="submit" class="btn btn-sm btn-danger" onclick="return confirm('Are you sure?')">Delete</button>
</form>
</td>
</tr>
@empty
<tr>
<td colspan="5" class="text-center">No products found.</td>
</tr>
@endforelse
</tbody>
</table>
</div>
@endsection
This view displays a list of products in a table format. Blade directives like @foreach, @if, and {{ }} make it easy to work with data and control structures.
Understanding how a request flows through Laravel's MVC structure is crucial. Here's what happens when a user visits /products:
routes/web.php:
Route::get('/products', [ProductController::class, 'index'])->name('products.index');
index method in ProductController.Product model to fetch data from the database.Let's build a simple blog to see MVC in action. We'll create a system to manage blog posts.
php artisan make:model Post -m
This creates a model and migration file. Update the migration:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up()
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->string('author');
$table->boolean('published')->default(false);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('posts');
}
};
Run the migration: php artisan migrate
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['title', 'content', 'author', 'published'];
public function scopePublished($query)
{
return $query->where('published', true);
}
}
php artisan make:controller PostController --resource
The --resource flag creates all CRUD methods automatically.
In routes/web.php:
use App\Http\Controllers\PostController;
Route::resource('posts', PostController::class);
This single line creates all necessary routes for CRUD operations.
Laravel's MVC structure provides a solid foundation for building maintainable web applications. By separating concerns into Models, Views, and Controllers, you create code that's easier to understand, test, and scale. Start with simple CRUD operations like the examples shown here, and gradually explore Laravel's more advanced features. The MVC pattern might seem complex at first, but with practice, it becomes a natural and efficient way to organize your code. Happy coding!