Getting Started with Laravel: The Complete Developer's Guide
Getting Started with Laravel: The Complete Developer's Guide
Expert Guide by Alaa Amer – Professional Web Developer & Applications Designer
Laravel is the most popular PHP framework for building modern web applications. Learn why Laravel dominates the PHP ecosystem and how to master it.
2️⃣ Laravel Ecosystem Overview
Core Components Architecture:
<?php
/**
* Laravel Request Lifecycle
*
* 1. HTTP Request → 2. Route Resolution → 3. Middleware Stack
* 4. Controller Action → 5. Business Logic → 6. Response
*/
// routes/web.php - Route Definition
Route::get('/users/{user}', [UserController::class, 'show'])
->middleware(['auth', 'verified'])
->name('users.show');
// app/Http/Controllers/UserController.php
class UserController extends Controller
{
public function show(User $user)
{
// Route Model Binding automatically injects User instance
return view('users.show', compact('user'));
}
}
// app/Models/User.php - Eloquent Model
class User extends Authenticatable
{
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['password', 'remember_token'];
public function posts()
{
return $this->hasMany(Post::class);
}
public function profile()
{
return $this->hasOne(Profile::class);
}
}
// resources/views/users/show.blade.php - Blade Template
@extends('layouts.app')
@section('content')
<div class="container">
<h1>{{ $user->name }}</h1>
<p>{{ $user->email }}</p>
@if($user->posts->isNotEmpty())
<h2>Recent Posts</h2>
@foreach($user->posts->take(5) as $post)
<article>
<h3>{{ $post->title }}</h3>
<p>{{ Str::limit($post->content, 150) }}</p>
</article>
@endforeach
@endif
</div>
@endsection
Laravel Package Ecosystem:
<?php
// Essential Laravel packages for professional development
// 1. Spatie Permission - Role & Permission Management
composer require spatie/laravel-permission
// Usage example
$user->assignRole('writer');
$user->givePermissionTo('edit posts');
if ($user->hasRole('admin')) {
// Admin logic
}
// 2. Laravel Sanctum - API Authentication
composer require laravel/sanctum
// Generate API token
$token = $user->createToken('API Token')->plainTextToken;
// 3. Laravel Telescope - Debug Assistant
composer require laravel/telescope --dev
// Access via: /telescope
// 4. Spatie Laravel Backup
composer require spatie/laravel-backup
// Automated backup configuration in config/backup.php
// 5. Laravel Excel - Import/Export
composer require maatwebsite/excel
// Quick export example
return Excel::download(new UsersExport, 'users.xlsx');
4️⃣ Your First Laravel Application: Blog System
Database Design & Migrations:
<?php
// database/migrations/create_posts_table.php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('posts', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->string('slug')->unique();
$table->text('excerpt')->nullable();
$table->longText('content');
$table->string('featured_image')->nullable();
$table->enum('status', ['draft', 'published', 'archived'])->default('draft');
$table->timestamp('published_at')->nullable();
$table->unsignedBigInteger('views_count')->default(0);
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->foreignId('category_id')->constrained()->onDelete('cascade');
$table->json('meta')->nullable(); // For SEO meta data
$table->timestamps();
// Indexes for performance
$table->index(['status', 'published_at']);
$table->index('user_id');
$table->index('category_id');
});
}
public function down(): void
{
Schema::dropIfExists('posts');
}
};
// database/migrations/create_categories_table.php
return new class extends Migration
{
public function up(): void
{
Schema::create('categories', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('slug')->unique();
$table->text('description')->nullable();
$table->string('color', 7)->default('#3B82F6'); // Hex color
$table->string('icon')->nullable();
$table->unsignedInteger('sort_order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists('categories');
}
};
Eloquent Models with Relationships:
<?php
// app/Models/Post.php
namespace App\Models;
use Illuminate\Database\Eloquent\{Model, Factories\HasFactory, SoftDeletes};
use Illuminate\Database\Eloquent\Relations\{BelongsTo, HasMany, BelongsToMany};
class Post extends Model
{
use HasFactory, SoftDeletes;
protected $fillable = [
'title', 'slug', 'excerpt', 'content', 'featured_image',
'status', 'published_at', 'user_id', 'category_id', 'meta'
];
protected $casts = [
'published_at' => 'datetime',
'meta' => 'array',
];
// Relationships
public function author(): BelongsTo
{
return $this->belongsTo(User::class, 'user_id');
}
public function category(): BelongsTo
{
return $this->belongsTo(Category::class);
}
public function tags(): BelongsToMany
{
return $this->belongsToMany(Tag::class);
}
public function comments(): HasMany
{
return $this->hasMany(Comment::class);
}
// Scopes for common queries
public function scopePublished($query)
{
return $query->where('status', 'published')
->where('published_at', '<=', now());
}
public function scopeFeatured($query)
{
return $query->whereNotNull('featured_image');
}
public function scopeByCategory($query, $categorySlug)
{
return $query->whereHas('category', function ($q) use ($categorySlug) {
$q->where('slug', $categorySlug);
});
}
// Accessors & Mutators
public function getExcerptAttribute($value)
{
return $value ?: Str::limit(strip_tags($this->content), 150);
}
public function setTitleAttribute($value)
{
$this->attributes['title'] = $value;
$this->attributes['slug'] = Str::slug($value);
}
// Helper Methods
public function isPublished(): bool
{
return $this->status === 'published' &&
$this->published_at &&
$this->published_at->isPast();
}
public function getReadingTimeAttribute(): int
{
$wordCount = str_word_count(strip_tags($this->content));
return ceil($wordCount / 200); // Average reading speed: 200 words/minute
}
public function getUrlAttribute(): string
{
return route('posts.show', $this->slug);
}
}
// app/Models/Category.php
namespace App\Models;
use Illuminate\Database\Eloquent\{Model, Factories\HasFactory};
use Illuminate\Database\Eloquent\Relations\HasMany;
class Category extends Model
{
use HasFactory;
protected $fillable = [
'name', 'slug', 'description', 'color', 'icon', 'sort_order', 'is_active'
];
protected $casts = [
'is_active' => 'boolean',
];
public function posts(): HasMany
{
return $this->hasMany(Post::class);
}
public function publishedPosts(): HasMany
{
return $this->posts()->published();
}
public function scopeActive($query)
{
return $query->where('is_active', true);
}
public function getPostsCountAttribute(): int
{
return $this->publishedPosts()->count();
}
}
Controllers with Best Practices:
<?php
// app/Http/Controllers/PostController.php
namespace App\Http\Controllers;
use App\Models\{Post, Category};
use Illuminate\Http\Request;
use Illuminate\View\View;
class PostController extends Controller
{
public function index(Request $request): View
{
$query = Post::with(['author:id,name', 'category:id,name,slug'])
->published()
->latest('published_at');
// Search functionality
if ($request->filled('search')) {
$searchTerm = $request->search;
$query->where(function ($q) use ($searchTerm) {
$q->where('title', 'like', "%{$searchTerm}%")
->orWhere('content', 'like', "%{$searchTerm}%");
});
}
// Category filter
if ($request->filled('category')) {
$query->byCategory($request->category);
}
$posts = $query->paginate(12);
$categories = Category::active()
->withCount('publishedPosts')
->orderBy('sort_order')
->get();
return view('posts.index', compact('posts', 'categories'));
}
public function show(Post $post): View
{
// Check if post is published (unless user is the author)
if (!$post->isPublished() && $post->user_id !== auth()->id()) {
abort(404);
}
// Load relationships
$post->load([
'author:id,name,email,avatar',
'category:id,name,slug,color',
'tags:id,name,slug',
'comments' => function ($query) {
$query->with('user:id,name,avatar')
->latest()
->limit(10);
}
]);
// Get related posts
$relatedPosts = Post::published()
->where('category_id', $post->category_id)
->where('id', '!=', $post->id)
->inRandomOrder()
->limit(4)
->get();
// Increment view count (you might want to do this via queues)
$post->increment('views_count');
return view('posts.show', compact('post', 'relatedPosts'));
}
public function create(): View
{
$this->authorize('create', Post::class);
$categories = Category::active()
->orderBy('sort_order')
->get();
return view('posts.create', compact('categories'));
}
public function store(StorePostRequest $request)
{
$validated = $request->validated();
$validated['user_id'] = auth()->id();
// Handle file upload
if ($request->hasFile('featured_image')) {
$validated['featured_image'] = $request->file('featured_image')
->store('posts', 'public');
}
$post = Post::create($validated);
return redirect()
->route('posts.show', $post->slug)
->with('success', 'Post created successfully!');
}
}
// app/Http/Requests/StorePostRequest.php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StorePostRequest extends FormRequest
{
public function authorize(): bool
{
return auth()->check();
}
public function rules(): array
{
return [
'title' => 'required|string|max:255|unique:posts,title',
'excerpt' => 'nullable|string|max:500',
'content' => 'required|string|min:100',
'category_id' => 'required|exists:categories,id',
'featured_image' => 'nullable|image|mimes:jpeg,png,jpg,webp|max:2048',
'status' => 'required|in:draft,published',
'published_at' => 'nullable|date|after_or_equal:now',
'meta.title' => 'nullable|string|max:60',
'meta.description' => 'nullable|string|max:160',
'meta.keywords' => 'nullable|string|max:255',
];
}
public function messages(): array
{
return [
'title.required' => 'Post title is required.',
'title.unique' => 'A post with this title already exists.',
'content.min' => 'Post content must be at least 100 characters.',
'featured_image.image' => 'Featured image must be a valid image file.',
];
}
}
💡 Laravel Best Practices from Day One
- Follow PSR Standards for consistent code
- Use Eloquent Relationships instead of manual joins
- Validate All Input with Form Requests
- Implement Proper Error Handling with try-catch blocks
- Use Laravel's Built-in Security Features (CSRF, XSS protection)
- Write Tests from the beginning
- Cache Frequently Used Data for better performance
Next Steps
Ready to dive deeper? Learn Laravel Installation & Setup for advanced development environments.
📩 Need help getting started with Laravel?
Article Category
Getting Started with Laravel: The Complete Developer's Guide
Comprehensive guide to Laravel framework - from installation to building your first application with modern PHP development practices and best practices.
Consultation & Communication
Direct communication via WhatsApp or phone to understand your project needs precisely.
Planning & Scheduling
Creating clear work plan with specific timeline for each project phase.
Development & Coding
Building projects with latest technologies ensuring high performance and security.
Testing & Delivery
Comprehensive testing and thorough review before final project delivery.