# Laravel Framework Documentation
Laravel is a modern PHP web application framework with expressive, elegant syntax designed for building full-stack web applications and APIs. It provides a comprehensive ecosystem including routing, authentication, database ORM (Eloquent), caching, queuing, real-time event broadcasting, and more. Laravel emphasizes developer experience with clean APIs, extensive documentation, and powerful features like dependency injection, middleware, and service containers that handle complexity behind the scenes.
This documentation covers Laravel 12.x, the latest major version. Laravel follows a "progressive framework" philosophy, meaning it scales from simple websites to enterprise applications. It includes first-party packages for common needs (authentication via Sanctum/Passport, payment processing via Cashier, server monitoring via Telescope) and supports multiple database systems, cache backends, queue drivers, and mail services. Whether building a RESTful API backend or a full-stack application with server-rendered Blade templates, Laravel provides the tools and patterns needed for modern PHP development.
## Routing - Basic Routes
Define HTTP routes that map URLs to closures or controller methods.
```php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
// Basic closure route
Route::get('/greeting', function () {
return 'Hello World';
});
// Route with parameters
Route::get('/user/{id}', function (string $id) {
return 'User '.$id;
});
// Route to controller method
Route::get('/users', [UserController::class, 'index']);
// Multiple HTTP verbs
Route::match(['get', 'post'], '/profile', function () {
// Handles GET and POST
});
// Route with dependency injection
Route::get('/users', function (Request $request) {
$sort = $request->query('sort', 'name');
return User::orderBy($sort)->get();
});
```
## Routing - Named Routes and Groups
Group routes with shared middleware, prefixes, or namespaces.
```php
use Illuminate\Support\Facades\Route;
// Named routes for URL generation
Route::get('/user/profile', [ProfileController::class, 'show'])->name('profile');
// Generate URLs from named routes
$url = route('profile');
return redirect()->route('profile');
// Route groups with middleware
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
Route::get('/settings', [SettingsController::class, 'index']);
});
// Route groups with prefix
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/users', [AdminController::class, 'users'])->name('users'); // admin.users
Route::get('/posts', [AdminController::class, 'posts'])->name('posts'); // admin.posts
});
// API routes with custom prefix
Route::prefix('api/v1')->middleware('auth:sanctum')->group(function () {
Route::get('/user', fn(Request $r) => $r->user());
Route::apiResource('posts', PostController::class);
});
```
## Routing - Route Model Binding
Automatically inject model instances into routes based on route parameters.
```php
use App\Models\User;
use App\Models\Post;
use Illuminate\Support\Facades\Route;
// Implicit binding (by ID)
Route::get('/user/{user}', function (User $user) {
return $user->email; // Auto-fetches User where id = parameter
});
// Implicit binding with custom column
Route::get('/posts/{post:slug}', function (Post $post) {
return $post; // Auto-fetches Post where slug = parameter
});
// In model, customize resolution key
class Post extends Model
{
public function getRouteKeyName(): string
{
return 'slug';
}
}
// Explicit binding registration (bootstrap/app.php or AppServiceProvider)
use Illuminate\Support\Facades\Route;
Route::model('user', User::class);
// With custom resolution logic
Route::bind('user', function (string $value) {
return User::where('name', $value)->firstOrFail();
});
```
## Controllers - Basic Controllers
Organize request handling logic into controller classes.
```php
// Generate controller
// php artisan make:controller UserController
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\View\View;
class UserController extends Controller
{
// Show user profile
public function show(string $id): View
{
return view('user.profile', [
'user' => User::findOrFail($id)
]);
}
// List all users
public function index(Request $request): View
{
$users = User::query()
->when($request->search, fn($q) => $q->where('name', 'like', "%{$request->search}%"))
->paginate(20);
return view('users.index', compact('users'));
}
// Store new user
public function store(Request $request): RedirectResponse
{
$validated = $request->validate([
'name' => 'required|max:255',
'email' => 'required|email|unique:users',
]);
User::create($validated);
return redirect()->route('users.index')->with('success', 'User created!');
}
}
```
## Controllers - Resource Controllers
Generate controllers with CRUD operations following RESTful conventions.
```php
// Generate resource controller
// php artisan make:controller PhotoController --resource
// Register resource routes
Route::resource('photos', PhotoController::class);
// This creates routes for:
// GET /photos - index()
// GET /photos/create - create()
// POST /photos - store()
// GET /photos/{photo} - show()
// GET /photos/{photo}/edit - edit()
// PUT/PATCH /photos/{photo} - update()
// DELETE /photos/{photo} - destroy()
namespace App\Http\Controllers;
use App\Models\Photo;
class PhotoController extends Controller
{
public function index()
{
return Photo::latest()->paginate(15);
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|max:255',
'image' => 'required|image|max:2048',
]);
$path = $request->file('image')->store('photos');
$photo = Photo::create([
'title' => $validated['title'],
'path' => $path,
]);
return redirect()->route('photos.show', $photo);
}
public function destroy(Photo $photo)
{
Storage::delete($photo->path);
$photo->delete();
return redirect()->route('photos.index')->with('success', 'Photo deleted!');
}
}
```
## Middleware - Creating Middleware
Filter HTTP requests entering your application.
```php
// Create middleware
// php artisan make:middleware EnsureTokenIsValid
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
class EnsureTokenIsValid
{
public function handle(Request $request, Closure $next): Response
{
if ($request->input('token') !== 'my-secret-token') {
return redirect('/home')->with('error', 'Invalid token');
}
return $next($request);
}
}
// Middleware that runs AFTER the response
class AfterMiddleware
{
public function handle(Request $request, Closure $next): Response
{
$response = $next($request);
// Log response time, modify headers, etc.
$response->headers->set('X-Response-Time', microtime(true) - LARAVEL_START);
return $response;
}
}
// Terminable middleware (cleanup after response sent)
class StartSession
{
public function handle(Request $request, Closure $next): Response
{
return $next($request);
}
public function terminate(Request $request, Response $response): void
{
// Save session data after response sent to browser
}
}
```
## Middleware - Registering Middleware
Apply middleware globally, to route groups, or individual routes.
```php
// Global middleware (bootstrap/app.php)
use App\Http\Middleware\EnsureTokenIsValid;
->withMiddleware(function (Middleware $middleware) {
$middleware->append(EnsureTokenIsValid::class);
})
// Middleware aliases (bootstrap/app.php)
->withMiddleware(function (Middleware $middleware) {
$middleware->alias([
'subscribed' => EnsureUserIsSubscribed::class,
'admin' => EnsureUserIsAdmin::class,
]);
})
// Apply to specific routes
Route::get('/profile', [ProfileController::class, 'show'])->middleware('auth');
Route::middleware(['auth', 'verified'])->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index']);
});
// Controller-based middleware
class UserController extends Controller implements HasMiddleware
{
public static function middleware(): array
{
return [
'auth',
new Middleware('subscribed', only: ['index']),
new Middleware('admin', except: ['store']),
];
}
}
// Exclude middleware from specific routes
Route::middleware(['auth'])->group(function () {
Route::get('/admin', fn() => 'Admin')->withoutMiddleware(['auth']);
});
```
## Requests - Retrieving Input
Access request data from forms, query strings, and JSON payloads.
```php
use Illuminate\Http\Request;
Route::post('/user', function (Request $request) {
// Get single input
$name = $request->input('name');
$email = $request->input('email', 'default@example.com'); // with default
// Get query parameter
$sort = $request->query('sort', 'name');
// Get all input
$all = $request->all();
$only = $request->only(['name', 'email']);
$except = $request->except(['password']);
// Check if input exists
if ($request->has('name')) {
// Input exists (even if empty string)
}
if ($request->filled('name')) {
// Input exists AND not empty
}
// Boolean input (converts 'yes', 'on', '1', true to boolean)
$archived = $request->boolean('archived');
// Merge additional input
$request->merge(['verified' => true]);
// Old input (after redirect)
$oldName = $request->old('name');
return response()->json(['status' => 'success']);
});
```
## Requests - File Uploads
Handle uploaded files securely.
```php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
Route::post('/upload', function (Request $request) {
// Validate file upload
$request->validate([
'avatar' => 'required|image|max:2048', // max 2MB
'document' => 'required|mimes:pdf,doc,docx|max:10240', // max 10MB
]);
// Get uploaded file
$file = $request->file('avatar');
// Check if file uploaded
if ($request->hasFile('avatar')) {
// File info
$extension = $file->extension();
$size = $file->getSize();
$originalName = $file->getClientOriginalName();
// Store file
$path = $file->store('avatars'); // storage/app/avatars/random-name.jpg
$path = $file->storeAs('avatars', 'user-123.jpg'); // custom name
$path = $file->store('avatars', 's3'); // store on S3
// Store publicly accessible file
$path = $file->storePublicly('avatars', 's3');
// Save path to database
$request->user()->update(['avatar' => $path]);
// Get public URL
$url = Storage::url($path);
return response()->json(['path' => $path, 'url' => $url]);
}
});
```
## Validation - Request Validation
Validate incoming request data with built-in rules.
```php
use Illuminate\Http\Request;
Route::post('/post', function (Request $request) {
// Validate with array rules
$validated = $request->validate([
'title' => ['required', 'unique:posts', 'max:255'],
'body' => ['required', 'min:10'],
'publish_at' => ['nullable', 'date', 'after:today'],
'tags' => ['array', 'min:1'],
'tags.*' => ['string', 'max:50'],
'author.name' => ['required', 'string'],
'author.email' => ['required', 'email'],
]);
// Or pipe-separated rules
$validated = $request->validate([
'title' => 'required|unique:posts|max:255',
'email' => 'required|email',
]);
// Safe to use validated data only
Post::create($validated);
return redirect('/posts');
});
// Display errors in Blade
// @error('title')
//
{{ $message }}
// @enderror
//
// Validate arrays with wildcard
$request->validate([
'users.*.name' => 'required',
'users.*.email' => 'required|email',
]);
```
## Validation - Form Requests
Encapsulate validation logic in dedicated request classes.
```php
// Create form request
// php artisan make:request StorePostRequest
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
// Authorization logic
return $this->user()->can('create', Post::class);
}
public function rules(): array
{
return [
'title' => 'required|unique:posts|max:255',
'body' => 'required|min:10',
'category_id' => 'required|exists:categories,id',
'tags' => 'array|min:1|max:5',
'tags.*' => 'string|distinct|max:50',
];
}
public function messages(): array
{
return [
'title.required' => 'Please provide a title for your post.',
'title.unique' => 'This title is already taken.',
];
}
public function attributes(): array
{
return [
'category_id' => 'category',
];
}
}
// Use in controller
use App\Http\Requests\StorePostRequest;
class PostController extends Controller
{
public function store(StorePostRequest $request)
{
// Already validated
$validated = $request->validated();
// Or get safely
$safe = $request->safe()->only(['title', 'body']);
$safe = $request->safe()->except(['admin_notes']);
Post::create($validated);
return redirect()->route('posts.index');
}
}
```
## Validation - Common Rules
Most frequently used validation rules with examples.
```php
use Illuminate\Validation\Rules\Password;
$request->validate([
// Required and types
'name' => 'required|string|max:255',
'age' => 'required|integer|min:18|max:120',
'price' => 'required|numeric|between:0,9999.99',
'active' => 'required|boolean',
// Strings
'email' => 'required|email:rfc,dns', // validate email format and DNS
'url' => 'required|url|active_url', // active_url checks DNS
'slug' => 'required|alpha_dash|unique:posts,slug',
'username' => 'required|alpha_num|min:3|max:20',
// Dates
'birth_date' => 'required|date|before:today',
'publish_at' => 'nullable|date|after:now',
'event_date' => 'required|date|after:start_date',
// Files
'avatar' => 'required|image|mimes:jpg,jpeg,png|max:2048', // max 2MB
'document' => 'required|file|mimes:pdf,doc,docx|max:10240', // max 10MB
'dimensions' => 'image|dimensions:min_width=100,min_height=100,max_width=2000',
// Arrays
'tags' => 'required|array|min:1|max:5',
'tags.*' => 'string|distinct|max:50',
// Database
'user_id' => 'required|exists:users,id',
'email' => 'required|email|unique:users,email',
'email' => 'required|email|unique:users,email,' . $user->id, // ignore current user
// Password
'password' => ['required', 'confirmed', Password::min(8)->mixedCase()->numbers()->symbols()],
'password_confirmation' => 'required',
]);
```
## Responses - JSON and Views
Return different response types from routes and controllers.
```php
use Illuminate\Support\Facades\View;
// JSON responses
Route::get('/api/user/{id}', function (string $id) {
$user = User::findOrFail($id);
// Basic JSON
return response()->json($user);
// With status code and headers
return response()->json([
'status' => 'success',
'data' => $user,
], 200, ['X-Custom-Header' => 'value']);
// JSONP response
return response()->jsonp('callback', ['name' => 'John']);
});
// View responses
Route::get('/profile', function () {
// Return view
return view('profile', ['user' => Auth::user()]);
// Check if view exists
if (View::exists('profile')) {
return view('profile');
}
// First available view
return view()->first(['custom.profile', 'profile'], $data);
});
// Download responses
Route::get('/download', function () {
return response()->download('/path/to/file.pdf');
return response()->download('/path/to/file.pdf', 'custom-name.pdf');
// Stream download (memory efficient)
return response()->streamDownload(function () {
echo Storage::get('large-file.csv');
}, 'export.csv');
});
// Redirects
return redirect('/home');
return redirect()->route('profile');
return redirect()->back();
return redirect()->away('https://external.com'); // external URL
return redirect()->route('profile')->with('status', 'Profile updated!');
```
## Views - Blade Templates
Use Blade templating engine with clean syntax.
```php
// In routes/web.php
Route::get('/greeting', function () {
return view('greeting', ['name' => 'John', 'items' => [1, 2, 3]]);
});
// In resources/views/greeting.blade.php
// Display data (auto-escaped)
Hello, {{ $name }}
Current time: {{ now()->format('Y-m-d H:i:s') }}
// Raw HTML (dangerous, only for trusted content)
{!! $trustedHtml !!}
// Conditional rendering
@if (count($items) === 1)
I have one item!
@elseif (count($items) > 1)
I have multiple items!
@else
I don't have any items!
@endif
@unless (Auth::check())
You are not signed in.
@endunless
// Loops
@foreach ($items as $item)
{{ $item }}
@endforeach
@forelse ($users as $user)
{{ $user->name }}
@empty
No users found.
@endforelse
// Loop variable
@foreach ($users as $user)
@if ($loop->first)
First iteration
@endif
{{ $loop->iteration }}. {{ $user->name }}
@if ($loop->last)
Last iteration
@endif
@endforeach
```
## Views - Blade Components
Create reusable UI components with slots and props.
```php
// Create component
// php artisan make:component Alert
// app/View/Components/Alert.php
namespace App\View\Components;
use Illuminate\View\Component;
class Alert extends Component
{
public function __construct(
public string $type = 'info',
public string $message = '',
) {}
public function render()
{
return view('components.alert');
}
}
// resources/views/components/alert.blade.php
@if ($message)
{{ $message }}
@else
{{ $slot }}
@endif
// Usage in any Blade file
Error! Something went wrong.
// Anonymous components (no class)
// resources/views/components/button.blade.php
@props(['type' => 'submit', 'color' => 'primary'])
// Usage
Save Changes
```
## Views - Blade Layouts
Create master layouts with sections and inheritance.
```php
// resources/views/layouts/app.blade.php
@yield('title', 'Default Title')
@stack('styles')
@yield('content')
@stack('scripts')
// resources/views/posts/show.blade.php
@extends('layouts.app')
@section('title', 'View Post')
@push('styles')
@endpush
@section('content')
{{ $post->title }}
{{ $post->body }}
@endsection
@push('scripts')
@endpush
// resources/views/partials/navigation.blade.php
```
## Eloquent - Model Basics
Define Eloquent models to interact with database tables.
```php
// Create model with migration
// php artisan make:model Flight -m
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Flight extends Model
{
// Table name (default: plural snake_case of class name)
protected $table = 'my_flights';
// Primary key (default: 'id')
protected $primaryKey = 'flight_id';
// Disable auto-incrementing
public $incrementing = false;
// Primary key type
protected $keyType = 'string';
// Disable timestamps
public $timestamps = false;
// Mass assignment protection
protected $fillable = ['name', 'airline', 'departure_time'];
// Or use guarded
protected $guarded = ['id', 'admin_notes'];
// Cast attributes to native types
protected $casts = [
'departure_time' => 'datetime',
'is_cancelled' => 'boolean',
'metadata' => 'array',
'price' => 'decimal:2',
];
// Default attribute values
protected $attributes = [
'status' => 'scheduled',
];
}
// Usage
$flight = Flight::create([
'name' => 'Flight 123',
'airline' => 'Example Airlines',
]);
$flight = new Flight;
$flight->name = 'Flight 456';
$flight->save();
```
## Eloquent - Retrieving Models
Query and retrieve models from the database.
```php
use App\Models\Flight;
// Retrieve all models
$flights = Flight::all();
// Query builder methods
$flights = Flight::where('active', 1)
->orderBy('departure_time', 'desc')
->take(10)
->get();
// Single model retrieval
$flight = Flight::find(1); // by primary key
$flight = Flight::where('airline', 'Example')->first();
$flight = Flight::findOrFail(1); // throw 404 if not found
$flight = Flight::where('airline', 'Example')->firstOrFail();
// Get single column value
$airline = Flight::where('number', 'FL123')->value('airline');
// Retrieve or create
$flight = Flight::firstOrCreate(
['number' => 'FL123'],
['airline' => 'Example', 'destination' => 'LAX']
);
$flight = Flight::firstOrNew(
['number' => 'FL123'],
['airline' => 'Example']
);
// Aggregates
$count = Flight::count();
$max = Flight::max('price');
$avg = Flight::where('active', 1)->avg('price');
// Chunking results (memory efficient)
Flight::chunk(100, function ($flights) {
foreach ($flights as $flight) {
// Process flight
}
});
// Lazy collections (one at a time)
Flight::lazy()->each(function ($flight) {
// Process one flight at a time
});
```
## Eloquent - Insert, Update, Delete
Create, modify, and remove models.
```php
use App\Models\Flight;
// Insert single model
$flight = new Flight;
$flight->name = 'Flight 123';
$flight->airline = 'Example';
$flight->save();
// Or use create (requires $fillable)
$flight = Flight::create([
'name' => 'Flight 123',
'airline' => 'Example',
]);
// Update model
$flight = Flight::find(1);
$flight->status = 'departed';
$flight->save();
// Or update directly
$flight->update(['status' => 'departed']);
// Mass update
Flight::where('airline', 'Example')
->update(['status' => 'cancelled']);
// Upsert (update or insert)
Flight::upsert([
['number' => 'FL123', 'airline' => 'Example', 'price' => 300],
['number' => 'FL456', 'airline' => 'Example', 'price' => 450],
], ['number'], ['airline', 'price']);
// Delete model
$flight = Flight::find(1);
$flight->delete();
// Delete by key
Flight::destroy(1);
Flight::destroy([1, 2, 3]);
Flight::destroy(1, 2, 3);
// Delete by query
Flight::where('cancelled', 1)->delete();
// Soft deletes (requires use SoftDeletes trait)
$flight->delete(); // Sets deleted_at timestamp
$flight->restore(); // Restore soft-deleted model
$flight->forceDelete(); // Permanently delete
```
## Eloquent - Relationships
Define relationships between models.
```php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\*;
class User extends Model
{
// One to Many
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
// One to One
public function profile(): HasOne
{
return $this->hasOne(Profile::class);
}
// Many to Many
public function roles(): BelongsToMany
{
return $this->belongsToMany(Role::class)
->withPivot('expires_at') // access pivot columns
->withTimestamps(); // add timestamps to pivot
}
// Has Many Through
public function postComments(): HasManyThrough
{
return $this->hasManyThrough(Comment::class, Post::class);
}
}
class Post extends Model
{
// Belongs To (inverse)
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
// Polymorphic
public function comments(): MorphMany
{
return $this->morphMany(Comment::class, 'commentable');
}
}
// Usage
$user = User::find(1);
// Access relationship
$posts = $user->posts;
foreach ($posts as $post) {
echo $post->title;
}
// Eager loading (prevent N+1)
$users = User::with('posts', 'profile')->get();
$users = User::with(['posts' => fn($q) => $q->where('published', 1)])->get();
// Create related model
$post = $user->posts()->create(['title' => 'New Post', 'body' => 'Content']);
// Attach/detach many-to-many
$user->roles()->attach($roleId);
$user->roles()->detach($roleId);
$user->roles()->sync([1, 2, 3]); // sync to exact IDs
```
## Database - Query Builder
Build database queries without writing SQL.
```php
use Illuminate\Support\Facades\DB;
// Basic queries
$users = DB::table('users')->get();
$user = DB::table('users')->where('id', 1)->first();
$email = DB::table('users')->where('name', 'John')->value('email');
// Where clauses
$users = DB::table('users')
->where('active', 1)
->where('votes', '>', 100)
->get();
$users = DB::table('users')
->where('name', 'like', '%John%')
->orWhere('votes', '>', 100)
->get();
// Where between
$users = DB::table('users')
->whereBetween('votes', [1, 100])
->get();
// Where in
$users = DB::table('users')
->whereIn('id', [1, 2, 3])
->get();
// Joins
$users = DB::table('users')
->join('posts', 'users.id', '=', 'posts.user_id')
->select('users.*', 'posts.title')
->get();
// Insert
DB::table('users')->insert([
'name' => 'John',
'email' => 'john@example.com',
]);
$id = DB::table('users')->insertGetId(['name' => 'John']);
// Update
DB::table('users')
->where('id', 1)
->update(['votes' => 1]);
// Delete
DB::table('users')->where('votes', '<', 1)->delete();
// Aggregates
$count = DB::table('users')->count();
$max = DB::table('orders')->max('price');
$avg = DB::table('orders')->avg('price');
```
## Database - Migrations
Create and manage database schema changes.
```php
// Create migration
// php artisan make:migration create_flights_table
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('flights', function (Blueprint $table) {
$table->id();
$table->string('number')->unique();
$table->string('airline');
$table->string('destination');
$table->decimal('price', 8, 2);
$table->dateTime('departure_time');
$table->boolean('is_cancelled')->default(false);
$table->json('metadata')->nullable();
$table->timestamps();
// Indexes
$table->index('airline');
$table->index(['airline', 'destination']);
});
// Foreign keys
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('posts');
Schema::dropIfExists('flights');
}
};
// Run migrations
// php artisan migrate
// php artisan migrate:rollback
// php artisan migrate:fresh --seed
```
## Database - Transactions
Execute queries within database transactions.
```php
use Illuminate\Support\Facades\DB;
// Automatic transaction
DB::transaction(function () {
DB::table('users')->update(['votes' => 1]);
DB::table('posts')->delete();
});
// Manual transaction
DB::beginTransaction();
try {
$user = User::create(['name' => 'John']);
$post = $user->posts()->create(['title' => 'My Post']);
DB::commit();
} catch (\Exception $e) {
DB::rollBack();
throw $e;
}
// Transaction with retries (deadlock handling)
DB::transaction(function () {
// Queries...
}, 5); // Retry up to 5 times
// After commit hooks
DB::afterCommit(function () {
// Execute after transaction commits
ProcessOrder::dispatch($order);
});
// Queue jobs after transaction
$order->save();
ProcessOrder::dispatch($order)->afterCommit();
```
## Authentication - User Authentication
Authenticate users with built-in authentication system.
```php
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
// Manual authentication
public function authenticate(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials)) {
$request->session()->regenerate();
return redirect()->intended('dashboard');
}
return back()->withErrors([
'email' => 'The provided credentials do not match our records.',
]);
}
// With remember me
Auth::attempt($credentials, $remember = true);
// Logout
public function logout(Request $request)
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
// Get authenticated user
$user = Auth::user();
$id = Auth::id();
// Or via Request
$user = $request->user();
// Check authentication
if (Auth::check()) {
// User is authenticated
}
// Protect routes
Route::get('/dashboard', function () {
// Only authenticated users
})->middleware('auth');
// Protect controller
class DashboardController extends Controller
{
public function __construct()
{
$this->middleware('auth');
}
}
```
## Authorization - Gates and Policies
Control user access to resources.
```php
// Define gates in AppServiceProvider
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
Gate::define('admin-only', function (User $user) {
return $user->is_admin;
});
}
// Check gates
if (Gate::allows('update-post', $post)) {
// User can update the post
}
if (Gate::denies('admin-only')) {
abort(403);
}
// Or via User model
if ($request->user()->can('update-post', $post)) {
// User can update
}
// Create policy
// php artisan make:policy PostPolicy --model=Post
namespace App\Policies;
class PostPolicy
{
public function view(User $user, Post $post): bool
{
return $post->published || $user->id === $post->user_id;
}
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
public function delete(User $user, Post $post): bool
{
return $user->id === $post->user_id || $user->is_admin;
}
}
// Use in controllers
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);
// User is authorized, continue...
}
// In Blade
@can('update', $post)
Edit
@endcan
```
## Cache - Storing and Retrieving
Cache expensive operations for improved performance.
```php
use Illuminate\Support\Facades\Cache;
// Store items
Cache::put('key', 'value', $seconds = 600);
Cache::put('key', 'value', now()->addMinutes(10));
// Store forever
Cache::forever('key', 'value');
// Retrieve items
$value = Cache::get('key');
$value = Cache::get('key', 'default'); // with default
// Retrieve and store (if not exists)
$users = Cache::remember('users', 600, function () {
return DB::table('users')->get();
});
// Remember forever
$users = Cache::rememberForever('users', function () {
return DB::table('users')->get();
});
// Flexible cache (stale-while-revalidate)
$users = Cache::flexible('users', [5, 10], function () {
return DB::table('users')->get();
}); // Serve stale for 5 seconds while revalidating, expire after 10
// Check existence
if (Cache::has('key')) {
// Item exists
}
// Remove items
Cache::forget('key');
Cache::flush(); // Clear all cache
// Increment/decrement
Cache::increment('counter');
Cache::increment('counter', 5);
Cache::decrement('counter');
// Cache helper
$value = cache('key');
cache(['key' => 'value'], 600);
```
## Cache - Advanced Usage
Use cache tags, locks, and multiple stores.
```php
use Illuminate\Support\Facades\Cache;
// Multiple cache stores
$value = Cache::store('redis')->get('key');
Cache::store('redis')->put('key', 'value', 600);
$value = Cache::store('file')->remember('users', 600, function () {
return User::all();
});
// Cache tags (Redis/Memcached only)
Cache::tags(['people', 'authors'])->put('John', $john, 600);
Cache::tags(['people', 'artists'])->put('Anne', $anne, 600);
$john = Cache::tags(['people', 'authors'])->get('John');
// Flush tagged cache
Cache::tags(['people', 'authors'])->flush();
// Atomic locks (distributed locking)
$lock = Cache::lock('processing', 10); // Lock for 10 seconds
if ($lock->get()) {
try {
// Process critical section
} finally {
$lock->release();
}
}
// Block until lock available
$lock = Cache::lock('processing', 10);
$lock->block(5); // Wait up to 5 seconds
// Critical section
// Model caching pattern
class User extends Model
{
public static function findCached($id)
{
return Cache::remember("user.{$id}", 3600, function () use ($id) {
return static::find($id);
});
}
}
```
## Queues - Creating Jobs
Defer time-consuming tasks to background jobs.
```php
// Create job
// php artisan make:job ProcessPodcast
namespace App\Jobs;
use App\Models\Podcast;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Queue\Queueable;
class ProcessPodcast implements ShouldQueue
{
use Queueable;
// Job timeout
public $timeout = 120;
// Max attempts before failing
public $tries = 3;
// Delete job if model deleted
public $deleteWhenMissingModels = true;
public function __construct(
public Podcast $podcast,
) {}
public function handle(AudioProcessor $processor): void
{
// Process uploaded podcast
$processor->process($this->podcast);
}
public function failed(\Throwable $exception): void
{
// Handle job failure
Log::error('Podcast processing failed', [
'podcast_id' => $this->podcast->id,
'error' => $exception->getMessage(),
]);
}
}
// Unique job (prevent duplicates)
use Illuminate\Contracts\Queue\ShouldBeUnique;
class UpdateSearchIndex implements ShouldQueue, ShouldBeUnique
{
public $uniqueFor = 3600; // Lock for 1 hour
public function uniqueId(): string
{
return $this->product->id;
}
}
```
## Queues - Dispatching Jobs
Queue jobs for background processing.
```php
use App\Jobs\ProcessPodcast;
use Illuminate\Support\Facades\Bus;
// Dispatch to default queue
ProcessPodcast::dispatch($podcast);
// Dispatch to specific queue
ProcessPodcast::dispatch($podcast)
->onQueue('podcasts');
// Dispatch to specific connection
ProcessPodcast::dispatch($podcast)
->onConnection('redis');
// Delayed dispatch
ProcessPodcast::dispatch($podcast)
->delay(now()->addMinutes(10));
// Conditional dispatch
ProcessPodcast::dispatchIf($condition, $podcast);
ProcessPodcast::dispatchUnless($condition, $podcast);
// Synchronous dispatch (immediate)
ProcessPodcast::dispatchSync($podcast);
// Dispatch after database transaction commits
$podcast->save();
ProcessPodcast::dispatch($podcast)->afterCommit();
// Job chaining
Bus::chain([
new ProcessPodcast($podcast),
new OptimizePodcast($podcast),
new ReleasePodcast($podcast),
])->dispatch();
// Batch jobs
Bus::batch([
new ProcessPodcast($podcast1),
new ProcessPodcast($podcast2),
])->then(function (Batch $batch) {
// All jobs completed successfully
})->catch(function (Batch $batch, \Throwable $e) {
// First failure detected
})->finally(function (Batch $batch) {
// Batch finished executing
})->dispatch();
// Run queue worker
// php artisan queue:work
// php artisan queue:work --queue=high,default
// php artisan queue:work --timeout=60
```
## Mail - Creating Mailables
Send emails with clean API and Markdown support.
```php
// Create mailable
// php artisan make:mail OrderShipped
namespace App\Mail;
use App\Models\Order;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\{Content, Envelope, Address, Attachment};
class OrderShipped extends Mailable
{
public function __construct(public Order $order) {}
public function envelope(): Envelope
{
return new Envelope(
from: new Address('orders@example.com', 'Order System'),
replyTo: [new Address('support@example.com', 'Support')],
subject: 'Order Shipped',
);
}
public function content(): Content
{
return new Content(
view: 'mail.orders.shipped',
with: [
'orderUrl' => $this->order->url,
'trackingNumber' => $this->order->tracking_number,
],
);
}
public function attachments(): array
{
return [
Attachment::fromPath('/path/to/invoice.pdf')
->as('Invoice.pdf')
->withMime('application/pdf'),
];
}
}
// resources/views/mail/orders/shipped.blade.php
Your order has shipped!
Order #{{ $order->id }} has been shipped.
Tracking: {{ $trackingNumber }}
View Order
```
## Mail - Sending Emails
Send mailables to recipients.
```php
use App\Mail\OrderShipped;
use Illuminate\Support\Facades\Mail;
// Send immediately
Mail::to($user)->send(new OrderShipped($order));
// Multiple recipients
Mail::to($user)
->cc($moreUsers)
->bcc($evenMoreUsers)
->send(new OrderShipped($order));
// Send to email address
Mail::to('user@example.com')->send(new OrderShipped($order));
// Queue mail (background)
Mail::to($user)->queue(new OrderShipped($order));
// Delayed queue
Mail::to($user)
->later(now()->addMinutes(10), new OrderShipped($order));
// Queue on specific queue
Mail::to($user)
->queue((new OrderShipped($order))->onQueue('emails'));
// Render mailable preview (for testing)
Route::get('/mailable', function () {
$order = Order::find(1);
return new OrderShipped($order);
});
// Test mail in local environment
// Set MAIL_MAILER=log in .env
// Emails will be written to storage/logs/laravel.log
```
## Mail - Markdown Mailables
Create beautiful emails with Markdown.
```php
// Create markdown mailable
// php artisan make:mail OrderShipped --markdown=mail.orders.shipped
namespace App\Mail;
use Illuminate\Mail\Mailables\Content;
class OrderShipped extends Mailable
{
public function content(): Content
{
return new Content(
markdown: 'mail.orders.shipped',
with: ['url' => $this->order->url],
);
}
}
// resources/views/mail/orders/shipped.blade.php
@component('mail::message')
# Order Shipped
Your order has been shipped!
@component('mail::button', ['url' => $url])
View Order
@endcomponent
@component('mail::panel')
This is a panel. Use it to highlight important information.
@endcomponent
@component('mail::table')
| Item | Price |
| ------------- | ------- |
| Product 1 | $99.00 |
| Product 2 | $49.00 |
@endcomponent
Thanks,
{{ config('app.name') }}
@endcomponent
// Customize Markdown components
// php artisan vendor:publish --tag=laravel-mail
// Edit resources/views/vendor/mail/html/themes/default.css
```
## Notifications - Creating Notifications
Send multi-channel notifications (email, SMS, Slack, database).
```php
// Create notification
// php artisan make:notification InvoicePaid
namespace App\Notifications;
use Illuminate\Notifications\Notification;
use Illuminate\Notifications\Messages\MailMessage;
class InvoicePaid extends Notification
{
public function __construct(public Invoice $invoice) {}
// Delivery channels
public function via($notifiable): array
{
return ['mail', 'database'];
}
// Email channel
public function toMail($notifiable): MailMessage
{
return (new MailMessage)
->subject('Invoice Paid')
->line('Your invoice has been paid!')
->action('View Invoice', url('/invoices/'.$this->invoice->id))
->line('Thank you for your business!');
}
// Database channel
public function toDatabase($notifiable): array
{
return [
'invoice_id' => $this->invoice->id,
'amount' => $this->invoice->amount,
'message' => 'Your invoice has been paid!',
];
}
}
// Add Notifiable trait to User model
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
}
// Database notifications table
// php artisan notifications:table
// php artisan migrate
```
## Notifications - Sending Notifications
Send notifications via the notifiable trait or facade.
```php
use App\Notifications\InvoicePaid;
use Illuminate\Support\Facades\Notification;
// Via Notifiable trait
$user->notify(new InvoicePaid($invoice));
// Via Notification facade (multiple recipients)
Notification::send($users, new InvoicePaid($invoice));
// Queue notification
use Illuminate\Contracts\Queue\ShouldQueue;
class InvoicePaid extends Notification implements ShouldQueue
{
use Queueable;
// Automatically queued
}
// Delayed notification
$user->notify((new InvoicePaid($invoice))->delay(now()->addMinutes(10)));
// Retrieve database notifications
$notifications = $user->notifications;
$unreadNotifications = $user->unreadNotifications;
foreach ($user->unreadNotifications as $notification) {
echo $notification->type; // App\Notifications\InvoicePaid
echo $notification->data['message'];
}
// Mark notifications as read
$user->unreadNotifications->markAsRead();
$notification = $user->notifications()->find($id);
$notification->markAsRead();
// Delete notifications
$user->notifications()->delete();
```
## File Storage - Storing Files
Store and retrieve files across different storage systems.
```php
use Illuminate\Support\Facades\Storage;
use Illuminate\Http\Request;
// Store file content
Storage::put('avatars/1.jpg', $content);
Storage::disk('s3')->put('avatars/1.jpg', $content);
// Store from request
public function store(Request $request)
{
$request->validate([
'avatar' => 'required|image|max:2048',
]);
// Auto-generated name
$path = $request->file('avatar')->store('avatars');
// avatars/random-hash.jpg
// Custom name
$path = $request->file('avatar')->storeAs('avatars', 'user-123.jpg');
// Specific disk
$path = $request->file('avatar')->store('avatars', 's3');
// Store publicly
$path = $request->file('avatar')->storePublicly('avatars', 's3');
// Save to database
$request->user()->update(['avatar' => $path]);
return back()->with('success', 'Avatar uploaded!');
}
// Prepend/append content
Storage::prepend('file.log', 'Prepended Text');
Storage::append('file.log', 'Appended Text');
// Copy/move files
Storage::copy('old/file.jpg', 'new/file.jpg');
Storage::move('old/file.jpg', 'new/file.jpg');
```
## File Storage - Retrieving Files
Retrieve and download files from storage.
```php
use Illuminate\Support\Facades\Storage;
// Check existence
if (Storage::exists('avatars/1.jpg')) {
// File exists
}
if (Storage::disk('s3')->missing('avatars/1.jpg')) {
// File doesn't exist
}
// Get file contents
$contents = Storage::get('file.jpg');
$json = Storage::json('config.json');
// Get file URL
$url = Storage::url('avatars/1.jpg');
// Temporary URL (S3, expires after time)
$url = Storage::temporaryUrl(
'avatars/1.jpg',
now()->addMinutes(5),
['ResponseContentType' => 'image/jpeg']
);
// Download response
return Storage::download('file.pdf');
return Storage::download('file.pdf', 'custom-name.pdf', $headers);
// Stream download (memory efficient)
return response()->streamDownload(function () {
echo Storage::get('large-file.csv');
}, 'export.csv');
// File metadata
$size = Storage::size('file.jpg');
$time = Storage::lastModified('file.jpg');
// Delete files
Storage::delete('file.jpg');
Storage::delete(['file1.jpg', 'file2.jpg']);
// List files in directory
$files = Storage::files('avatars');
$allFiles = Storage::allFiles('avatars'); // recursive
// Public disk symbolic link
// php artisan storage:link
// Access via: asset('storage/file.jpg')
```
## HTTP Client - Making Requests
Make HTTP requests to external APIs.
```php
use Illuminate\Support\Facades\Http;
// GET request
$response = Http::get('https://api.example.com/users');
$users = $response->json();
$status = $response->status();
// POST request
$response = Http::post('https://api.example.com/users', [
'name' => 'Steve',
'email' => 'steve@example.com',
]);
// PUT, PATCH, DELETE
$response = Http::put('https://api.example.com/users/1', $data);
$response = Http::patch('https://api.example.com/users/1', $data);
$response = Http::delete('https://api.example.com/users/1');
// With headers
$response = Http::withHeaders([
'X-First' => 'foo',
'X-Second' => 'bar',
])->post('https://api.example.com/users', $data);
// Authentication
$response = Http::withToken('token')->get('https://api.example.com/user');
$response = Http::withBasicAuth('email@example.com', 'secret')->get('https://...');
// Form data
$response = Http::asForm()->post('https://api.example.com/users', [
'name' => 'Steve',
]);
// Multipart (file upload)
$response = Http::attach('photo', file_get_contents('photo.jpg'), 'photo.jpg')
->post('https://api.example.com/photos');
// JSON
$response = Http::withBody(json_encode($data), 'application/json')
->post('https://...');
```
## HTTP Client - Error Handling and Retries
Handle errors, timeouts, and retry failed requests.
```php
use Illuminate\Support\Facades\Http;
use Illuminate\Http\Client\RequestException;
// Timeout
$response = Http::timeout(3)->get('https://api.example.com/users');
// Retry on failure
$response = Http::retry(3, 100)->post('https://api.example.com/users', $data);
// Retry 3 times, wait 100ms between attempts
// Retry with custom logic
$response = Http::retry(3, 100, function ($exception, $request) {
return $exception instanceof ConnectionException;
})->post('https://...');
// Check response
if ($response->successful()) {
// Status 2xx
}
if ($response->failed()) {
// Status 4xx or 5xx
}
if ($response->clientError()) {
// Status 4xx
}
if ($response->serverError()) {
// Status 5xx
}
// Throw exception on error
try {
$response = Http::post('https://api.example.com/users', $data);
$response->throw(); // Throw if status >= 400
return $response->json();
} catch (RequestException $e) {
Log::error('API request failed', ['error' => $e->getMessage()]);
}
// Conditional throwing
$response->throwIf($condition);
$response->throwUnless($condition);
$response->throwIfStatus(403);
// Response body
$json = $response->json();
$array = $response->json('data.users'); // Get nested data
$object = $response->object();
$string = $response->body();
```
## API Resources - JSON Resources
Transform models into JSON API responses.
```php
// Create resource
// php artisan make:resource UserResource
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
'created_at' => $this->created_at->toDateTimeString(),
'updated_at' => $this->updated_at->toDateTimeString(),
];
}
}
// Use in routes/controllers
use App\Http\Resources\UserResource;
use App\Models\User;
// Single resource
Route::get('/users/{id}', function (string $id) {
return new UserResource(User::findOrFail($id));
});
// Or use toResource() method
Route::get('/users/{id}', function (string $id) {
return User::findOrFail($id)->toResource();
});
// Collection
Route::get('/users', function () {
return UserResource::collection(User::all());
});
// Or use toResourceCollection()
Route::get('/users', function () {
return User::all()->toResourceCollection();
});
// With pagination
Route::get('/users', function () {
return UserResource::collection(User::paginate(15));
});
```
## API Resources - Conditional Attributes
Include/exclude attributes based on conditions.
```php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'name' => $this->name,
'email' => $this->email,
// Include if condition is true
'admin_notes' => $this->when(
$request->user()->isAdmin(),
$this->notes
),
// Include if not null
'bio' => $this->whenNotNull($this->bio),
// Include relationship only if loaded
'posts' => PostResource::collection($this->whenLoaded('posts')),
// Include pivot data if exists
'expires_at' => $this->whenPivotLoaded('role_user', function () {
return $this->pivot->expires_at;
}),
// Merge attributes conditionally
$this->mergeWhen($request->user()->isAdmin(), [
'created_ip' => $this->created_ip,
'last_login_ip' => $this->last_login_ip,
]),
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
];
}
}
// Custom resource collection
use Illuminate\Http\Resources\Json\ResourceCollection;
class UserCollection extends ResourceCollection
{
public function toArray(Request $request): array
{
return [
'data' => $this->collection,
'meta' => [
'total' => $this->collection->count(),
'generated_at' => now(),
],
'links' => [
'self' => route('users.index'),
],
];
}
}
```
## Task Scheduling - Defining Schedules
Schedule recurring tasks with cron-like syntax.
```php
// In app/Console/Kernel.php or routes/console.php
use Illuminate\Support\Facades\Schedule;
// Run every minute
Schedule::command('emails:send')->everyMinute();
// Run every hour
Schedule::command('reports:generate')->hourly();
// Run daily at specific time
Schedule::command('newsletter:send')->dailyAt('13:00');
// Run weekly on Monday at 8am
Schedule::command('reports:weekly')->weeklyOn(1, '8:00');
// Run monthly on first day at midnight
Schedule::command('invoices:process')->monthlyOn(1, '0:00');
// Custom cron expression
Schedule::command('snapshot:create')->cron('0 */4 * * *');
// Run closure
Schedule::call(function () {
DB::table('recent_users')->delete();
})->daily();
// Run job
Schedule::job(new ProcessPodcasts)->everyFiveMinutes();
// Run shell command
Schedule::exec('npm run build')->daily();
// Frequency options
->everyMinute()
->everyTwoMinutes()
->everyFiveMinutes()
->everyTenMinutes()
->everyFifteenMinutes()
->everyThirtyMinutes()
->hourly()
->hourlyAt(17) // 17 minutes past hour
->daily()
->dailyAt('13:00')
->twiceDaily(1, 13) // 1am and 1pm
->weekly()
->monthly()
->quarterly()
->yearly()
// Start scheduler
// php artisan schedule:work
// Or add to crontab: * * * * * cd /path && php artisan schedule:run >> /dev/null 2>&1
```
## Task Scheduling - Advanced Scheduling
Configure schedules with constraints and event handling.
```php
use Illuminate\Support\Facades\Schedule;
// Conditional execution
Schedule::command('emails:send')
->daily()
->when(function () {
return app()->isProduction();
})
->skip(function () {
return DB::table('maintenance_mode')->value('enabled');
});
// Environment-specific
Schedule::command('backups:run')
->daily()
->environments(['production', 'staging']);
// Prevent overlaps (don't run if previous still running)
Schedule::command('reports:generate')
->hourly()
->withoutOverlapping();
// Run on one server (distributed apps)
Schedule::command('reports:generate')
->daily()
->onOneServer();
// Maintenance mode awareness
Schedule::command('emails:send')
->daily()
->evenInMaintenanceMode();
// Before/after callbacks
Schedule::command('emails:send')
->daily()
->before(function () {
Log::info('Starting email send');
})
->after(function () {
Log::info('Finished email send');
})
->onSuccess(function () {
Notification::send($admins, new TaskSucceeded);
})
->onFailure(function () {
Notification::send($admins, new TaskFailed);
});
// Send output to file
Schedule::command('reports:generate')
->daily()
->sendOutputTo('/path/to/file.txt')
->emailOutputTo('admin@example.com');
// Ping URLs (monitoring)
Schedule::command('reports:generate')
->daily()
->pingBefore('http://monitor.app/start')
->thenPing('http://monitor.app/finish');
```
## Integration Summary
Laravel provides a cohesive ecosystem where components integrate seamlessly. Authentication guards protect routes and controllers, which receive validated requests via Form Requests. Controllers query databases using Eloquent ORM, cache expensive operations, queue background jobs, and transform data into JSON via API Resources. File uploads are stored using Storage facade, processed by queued jobs, and user notifications are sent via multi-channel system. All configuration is managed through environment variables, and scheduled tasks automate recurring operations.
The framework follows convention-over-configuration philosophy with sensible defaults. Middleware filters requests globally or per-route. Service container handles dependency injection automatically. Blade templates render views with clean syntax. Migrations version-control database schema. Events and listeners decouple application logic. Logging, error handling, and debugging tools are built-in. Laravel's first-party packages extend functionality: Sanctum for API authentication, Horizon for queue monitoring, Telescope for debugging, Cashier for payment processing, Scout for full-text search, and more. This unified approach enables rapid development of modern web applications with clean, maintainable code following industry best practices.