Laravel 11 Tutorial: PHP Framework for Modern Web Apps
Learn: Laravel 11 Tutorial: PHP Framework for Modern Web Apps
Welcome to TopperBlog! 👋
I'm a tech content creator passionate about helping developers level up their careers and master cutting-edge technologies.
🎯 What I Write About:
• AI/ML Engineering & LLMs
• Web3 & Blockchain Development
• System Design & Architecture
• Interview Preparation (FAANG)
• Freelancing & Remote Work
• Modern Tech Stacks (Next.js, React, Rust, TypeScript)
• Performance Optimization & Best Practices
💼 Mission: Sharing practical, actionable insights that accelerate your tech career and maximize your earning potential.
📚 15+ In-Depth Guides covering everything from earning $10k/month as a freelancer to cracking FAANG interviews.
🌐 Let's connect and grow together in this amazing tech journey!
#TechBlogger #SoftwareEngineering #CareerGrowth #WebDevelopment #AIEngineering
Laravel 11 Tutorial: PHP Framework for Modern Web Apps
Why This Stack/Framework Matters
Laravel has revolutionized PHP development by making backend engineering enjoyable and productive. In 2024, Laravel 11 represents the framework's maturity—combining powerful features with elegant syntax that developers genuinely appreciate.
Why choose Laravel 11?
- Developer Experience: Expressive syntax reduces boilerplate code by 40-60% compared to vanilla PHP
- Built-in Features: Authentication, authorization, database migrations, and testing come standard
- Performance: Optimized for modern applications with sub-100ms response times
- Community: 2M+ developers actively contribute packages and solutions
- Job Market: Laravel skills command 15-20% salary premiums in web development
Unlike older PHP frameworks or JavaScript-only stacks, Laravel balances power with simplicity. You're not fighting the framework—you're working with it.
Core Concepts Explained
1. MVC Architecture
Laravel follows Model-View-Controller separation:
- Models: Represent database tables and business logic
- Views: Render HTML templates with data
- Controllers: Handle requests and orchestrate responses
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['title', 'content', 'author_id'];
public function author()
{
return $this->belongsTo(User::class);
}
}
2. Eloquent ORM
Laravel's Object-Relational Mapping eliminates raw SQL for most operations:
// Retrieve all posts
$posts = Post::all();
// Find by ID
$post = Post::find(1);
// Query with conditions
$recent = Post::where('created_at', '>', now()->subDays(7))
->orderBy('created_at', 'desc')
->get();
// Create new record
$post = Post::create([
'title' => 'My First Post',
'content' => 'Hello World',
'author_id' => 1
]);
3. Routing
Define application endpoints in routes/web.php:
use App\Http\Controllers\PostController;
Route::get('/posts', [PostController::class, 'index'])->name('posts.index');
Route::get('/posts/{id}', [PostController::class, 'show'])->name('posts.show');
Route::post('/posts', [PostController::class, 'store'])->name('posts.store');
Route::put('/posts/{id}', [PostController::class, 'update'])->name('posts.update');
Route::delete('/posts/{id}', [PostController::class, 'destroy'])->name('posts.destroy');
4. Middleware
Middleware acts as HTTP request filters:
// app/Http/Middleware/CheckAdmin.php
namespace App\Http\Middleware;
use Closure;
class CheckAdmin
{
public function handle($request, Closure $next)
{
if (!auth()->user()?->is_admin) {
return redirect('/');
}
return $next($request);
}
}
Step-by-Step Setup
Prerequisites
- PHP 8.2+ installed
- Composer package manager
- MySQL or PostgreSQL database
- Terminal/command line access
Installation
Step 1: Create new Laravel project
composer create-project laravel/laravel my-app
cd my-app
Step 2: Configure environment
cp .env.example .env
php artisan key:generate
Edit .env with your database credentials:
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=my_app
DB_USERNAME=root
DB_PASSWORD=
Step 3: Run migrations
php artisan migrate
Step 4: Start development server
php artisan serve
Visit http://localhost:8000 in your browser.
Building Real Example: Blog Application
Let's build a complete blog with posts and comments.
Generate Models and Migrations
php artisan make:model Post -m
php artisan make:model Comment -m
php artisan make:controller PostController --resource
Define Database Schema
database/migrations/create_posts_table.php
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('content');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
database/migrations/create_comments_table.php
Schema::create('comments', function (Blueprint $table) {
$table->id();
$table->text('body');
$table->foreignId('post_id')->constrained()->onDelete('cascade');
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->timestamps();
});
Define Model Relationships
// app/Models/Post.php
class Post extends Model
{
protected $fillable = ['title', 'content', 'user_id'];
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
public function comments()
{
return $this->hasMany(Comment::class);
}
}
// app/Models/Comment.php
class Comment extends Model
{
protected $fillable = ['body', 'post_id', 'user_id'];
public function post()
{
return $this->belongsTo(Post::class);
}
public function author()
{
return $this->belongsTo(User::class, 'user_id');
}
}
Create Controller Logic
// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\Post;
use Illuminate\Http\Request;
class PostController extends Controller
{
public function index()
{
$posts = Post::with('author', 'comments')
->latest()
->paginate(10);
return view('posts.index', compact('posts'));
}
public function show(Post $post)
{
$post->load('author', 'comments.author');
return view('posts.show', compact('post'));
}
public function store(Request $request)
{
$validated = $request->validate([
'title' => 'required|string|max:255',
'content' => 'required|string|min:10',
]);
$post = auth()->user()->posts()->create($validated);
return redirect()->route('posts.show', $post)
->with('success', 'Post created successfully!');
}
}
Create Views
resources/views/posts/index.blade.php
@extends('layouts.app')
@section('content')
<div class="container">
<h1>Blog Posts</h1>
@forelse($posts as $post)
<article class="post-card">
<h2>{{ $post->title }}</h2>
<p class="meta">By {{ $post->author->name }} on {{ $post->created_at->format('M d, Y') }}</p>
<p>{{ Str::limit($post->content, 150) }}</p>
<a href="{{ route('posts.show', $post) }}">Read More →</a>
</article>
@empty
<p>No posts found.</p>
@endforelse
{{ $posts->links() }}
</div>
@endsection
Best Practices
1. Use Eloquent Relationships Properly
// ✅ Good: Eager load to prevent N+1 queries
$posts = Post::with('author', 'comments.author')->get();
// ❌ Bad: Causes N+1 query problem
$posts = Post::all();
foreach ($posts as $post) {
echo $post->author->name; // Extra query per post
}
2. Validate Input Consistently
// Use Form Requests for complex validation
php artisan make:request StorePostRequest
// app/Http/Requests/StorePostRequest.php
public function rules()
{
return [
'title' => 'required|string|max:255|unique:posts',
'content' => 'required|string|min:10',
'tags' => 'array|max:5',
];
}
3. Implement Proper Authentication
// Laravel Breeze provides scaffolding
php artisan breeze:install
// Protect routes
Route::middleware('auth')->group(function () {
Route::post('/posts', [PostController::class, 'store']);
Route::delete('/posts/{id}', [PostController::class, 'destroy']);
});
4. Use Database Transactions
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
$post = Post::create($data);
$post->tags()->attach($tagIds);
// Both operations succeed or both rollback
});
Common Issues & Fixes
Issue 1: "Class not found" Error
Cause: Autoloader not updated after creating new files
Fix:
composer dump-autoload
Issue 2: CSRF Token Mismatch
Cause: Missing CSRF token in forms
Fix:
<form method="POST" action="/posts">
@csrf
<!-- form fields -->
</form>
Issue 3: Slow Queries
Cause: N+1 query problem or missing indexes
Fix:
// Use eager loading
Post::with('author', 'comments')->get();
// Add database indexes
Schema::table('posts', function (Blueprint $table) {
$table->index('user_id');
$table->index('created_at');
});
Issue 4: Permission Denied on Storage
Cause: Incorrect file permissions
Fix:
chmod -R 775 storage bootstrap/cache
Production Tips
1. Optimize for Performance
# Cache configuration
php artisan config:cache
# Cache routes
php artisan route:cache
# Optimize autoloader
composer install --optimize-autoloader --no-dev
2. Set Up Proper Logging
// config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single', 'slack'],
],
]
3. Use Environment Variables
# .env
APP_ENV=production
APP_DEBUG=false
LOG_CHANNEL=stack
CACHE_DRIVER=redis
4. Implement Queue Jobs
// Send emails asynchronously
Mail::to($user)->queue(new WelcomeEmail());
// Process heavy tasks in background
dispatch(new ProcessLargeDataset($data));
5. Database Backups
# Automated backups with Laravel Backup
php artisan backup:run
Resources
Official Documentation
Learning Platforms
- Laracasts (video tutorials)
- Laravel News (community updates)
- Spatie Packages (community tools)
Tools & Packages
- Laravel Tinker (REPL)
- Laravel Debugbar (debugging)
- Laravel Telescope (monitoring)
- Pest (testing framework)
Community
- Laravel Discord
- Stack Overflow
laraveltag - GitHub Discussions
Conclusion
Laravel 11 empowers developers to build modern web applications efficiently. Its elegant syntax, comprehensive features, and supportive community make it the ideal choice for projects ranging from small blogs to enterprise applications. Start with the fundamentals, practice with real projects, and gradually master advanced patterns.
Happy coding! 🚀