# 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.