Laravel Tutorial
Laravel is a modern PHP framework for building clean, maintainable web applications. It gives you routing, controllers, Blade views, database migrations, Eloquent models, validation, authentication, queues, testing tools, and deployment-friendly structure.
What is Laravel?
Laravel helps you organize a PHP app using MVC: models hold data rules, views render HTML, and controllers handle request logic. It is a strong next step after learning PHP basics.
- Routing: map URLs to closures, controllers, or API endpoints.
- Blade: write reusable templates with layouts, sections, and components.
- Eloquent: work with database tables using PHP classes.
- Migrations: version-control database schema changes.
- Artisan: run framework commands from the terminal.
Setup
You need PHP, Composer, and a database such as MySQL or SQLite. A local development stack such as XAMPP works well for practicing.
# Create a new Laravel project
composer create-project laravel/laravel blog-app
cd blog-app
# Start the local development server
php artisan serve
# Create a controller, model, and migration
php artisan make:controller PostController
php artisan make:model Post -m
# Run migrations
php artisan migrate
Project Structure
Laravel projects are organized by responsibility. You do not need to memorize every folder on day one, but these are the files you will touch most often.
app/
Http/Controllers/ # controller classes
Models/ # Eloquent models
database/
migrations/ # table schema changes
seeders/ # sample data
resources/
views/ # Blade templates
routes/
web.php # browser routes
api.php # API routes
public/
index.php # front controller
.env # local configuration
Routes
Routes define how URLs respond. Browser pages usually go in routes/web.php. JSON API endpoints usually go in routes/api.php.
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
Route::get('/', function () {
return view('welcome');
});
Route::get('/posts', [PostController::class, 'index']);
Route::get('/posts/{post}', [PostController::class, 'show']);
Route::post('/posts', [PostController::class, 'store']);
// Named route
Route::get('/dashboard', function () {
return view('dashboard');
})->name('dashboard');
Blade Templates
Blade is Laravel's template engine. It lets you create layouts, escape output by default, loop over data, and reuse partials.
<!-- resources/views/layouts/app.blade.php -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>@yield('title', 'Laravel App')</title>
</head>
<body>
<main>
@yield('content')
</main>
</body>
</html>
<!-- resources/views/posts/index.blade.php -->
@extends('layouts.app')
@section('title', 'Posts')
@section('content')
<h1>Posts</h1>
@foreach ($posts as $post)
<article>
<h2>{{ $post->title }}</h2>
<p>{{ $post->excerpt }}</p>
</article>
@endforeach
@endsection
Controllers
Controllers keep route files clean by moving request handling into classes.
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
$posts = Post::latest()->get();
return view('posts.index', [
'posts' => $posts,
]);
}
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
}
Requests
Use the request object to read form fields, query parameters, uploaded files, and authenticated users.
public function store(Request $request)
{
$title = $request->input('title');
$published = $request->boolean('published');
$search = $request->query('search');
return response()->json([
'title' => $title,
'published' => $published,
'search' => $search,
]);
}
Validation
Validation protects your app from bad input. Keep rules close to form handling, or extract them into form request classes for larger apps.
public function store(Request $request)
{
$validated = $request->validate([
'title' => ['required', 'string', 'max:120'],
'body' => ['required', 'string'],
'published_at' => ['nullable', 'date'],
]);
Post::create($validated);
return redirect()->route('posts.index')
->with('status', 'Post created.');
}
Migrations
Migrations describe database structure in code. This makes schema changes repeatable across development, staging, and production.
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration {
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->timestamp('published_at')->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
Eloquent ORM
Eloquent maps database rows to model objects. Define fillable fields, query records, create rows, and update data using expressive PHP methods.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['title', 'body', 'published_at'];
}
// Common queries
$posts = Post::latest()->get();
$post = Post::findOrFail($id);
Post::create([
'title' => 'Getting Started with Laravel',
'body' => 'Laravel makes PHP apps easier to structure.',
]);
$post->update(['title' => 'Updated title']);
$post->delete();
Relationships
Relationships connect models. A user can have many posts, and each post belongs to one user.
// app/Models/User.php
public function posts()
{
return $this->hasMany(Post::class);
}
// app/Models/Post.php
public function user()
{
return $this->belongsTo(User::class);
}
// Use relationships
$user = User::with('posts')->findOrFail(1);
foreach ($user->posts as $post) {
echo $post->title;
}
Seeders
Seeders add sample data so your app has content while you build features.
php artisan make:seeder PostSeeder
// database/seeders/PostSeeder.php
public function run(): void
{
Post::create([
'title' => 'First Laravel Post',
'body' => 'This post was created by a seeder.',
]);
}
php artisan db:seed --class=PostSeeder
Authentication
Laravel can protect routes and read the currently signed-in user. Starter kits can scaffold login and registration flows, but the core idea is simple: guard routes with auth middleware.
Route::middleware('auth')->group(function () {
Route::get('/dashboard', DashboardController::class)
->name('dashboard');
Route::resource('posts', PostController::class);
});
public function dashboard(Request $request)
{
$user = $request->user();
return view('dashboard', compact('user'));
}
Middleware
Middleware runs before or after a request. Use it for authentication, authorization, rate limiting, localization, and request checks.
public function handle($request, Closure $next)
{
if (! $request->user()?->is_admin) {
abort(403);
}
return $next($request);
}
Route::middleware(['auth', 'admin'])->group(function () {
Route::get('/admin', AdminController::class);
});
APIs
Laravel can return JSON for front-end apps, mobile apps, and third-party integrations.
Route::get('/api/posts', function () {
return Post::latest()
->select('id', 'title', 'created_at')
->paginate(10);
});
Route::post('/api/posts', function (Request $request) {
$post = Post::create($request->validate([
'title' => ['required', 'max:120'],
'body' => ['required'],
]));
return response()->json($post, 201);
});
Queues and Jobs
Jobs move slow work out of the request cycle. Examples include sending mail, processing images, syncing APIs, and generating reports.
php artisan make:job SendWelcomeEmail
SendWelcomeEmail::dispatch($user);
// Run queued jobs locally
php artisan queue:work
Testing
Laravel supports feature tests for HTTP behavior and unit tests for small isolated logic.
public function test_home_page_loads(): void
{
$response = $this->get('/');
$response->assertStatus(200);
}
public function test_post_can_be_created(): void
{
$response = $this->post('/posts', [
'title' => 'Test Post',
'body' => 'This is a test.',
]);
$response->assertRedirect('/posts');
$this->assertDatabaseHas('posts', ['title' => 'Test Post']);
}
Deployment Checklist
Before deploying a Laravel app, make sure production configuration and performance settings are ready.
- Set
APP_ENV=productionandAPP_DEBUG=false. - Configure database, mail, cache, queue, and storage values in
.env. - Run
composer install --no-dev --optimize-autoloader. - Run migrations with
php artisan migrate --force. - Cache config, routes, and views when appropriate.
- Point the web server document root to the
publicdirectory.