Laravel Modern Development: Best Practices and Patterns

Laravel remains one of the most popular PHP frameworks. Here are modern development practices for building scalable Laravel applications. 1. Project Structure Recommended Structure app/ ├── Http/ │ ├── Controllers/ │ ├── Middleware/ │ ├── Requests/ │ └── Resources/ ├── Models/ ├── Services/ ├── Repositories/ ├── Events/ ├── Listeners/ └── Jobs/ 2. Eloquent Best Practices Model Relationships // User Model class User extends Model { public function posts() { return $this->hasMany(Post::class); } public function profile() { return $this->hasOne(Profile::class); } public function roles() { return $this->belongsToMany(Role::class); } } Eager Loading // Bad: N+1 problem $users = User::all(); foreach ($users as $user) { echo $user->posts->count(); // Query for each user } // Good: Eager loading $users = User::with('posts')->get(); foreach ($users as $user) { echo $user->posts->count(); // No additional queries } Query Scopes class Post extends Model { public function scopePublished($query) { return $query->where('status', 'published'); } public function scopeRecent($query) { return $query->orderBy('created_at', 'desc'); } } // Usage $posts = Post::published()->recent()->get(); 3. Service Layer Pattern Service Class class UserService { protected $userRepository; protected $emailService; public function __construct( UserRepository $userRepository, EmailService $emailService ) { $this->userRepository = $userRepository; $this->emailService = $emailService; } public function createUser(array $data): User { DB::beginTransaction(); try { $user = $this->userRepository->create($data); $this->emailService->sendWelcomeEmail($user); DB::commit(); return $user; } catch (\Exception $e) { DB::rollBack(); throw $e; } } } 4. Form Requests Validation class CreateUserRequest extends FormRequest { public function rules(): array { return [ 'name' => ['required', 'string', 'max:255'], 'email' => ['required', 'email', 'unique:users,email'], 'password' => ['required', 'string', 'min:8', 'confirmed'], ]; } public function messages(): array { return [ 'email.unique' => 'This email is already registered.', 'password.min' => 'Password must be at least 8 characters.', ]; } } // Controller public function store(CreateUserRequest $request) { $user = $this->userService->createUser($request->validated()); return new UserResource($user); } 5. API Resources Resource Transformation class UserResource extends JsonResource { public function toArray($request): array { return [ 'id' => $this->id, 'name' => $this->name, 'email' => $this->email, 'created_at' => $this->created_at->toIso8601String(), 'posts' => PostResource::collection($this->whenLoaded('posts')), ]; } } 6. Queues and Jobs Job Implementation class SendWelcomeEmail implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; public function __construct( public User $user ) {} public function handle(EmailService $emailService): void { $emailService->sendWelcomeEmail($this->user); } public function failed(\Throwable $exception): void { // Handle failure } } // Dispatch SendWelcomeEmail::dispatch($user); 7. Events and Listeners Event System // Event class UserRegistered { public function __construct( public User $user ) {} } // Listener class SendWelcomeEmail { public function handle(UserRegistered $event): void { Mail::to($event->user->email)->send(new WelcomeMail($event->user)); } } // Dispatch event(new UserRegistered($user)); 8. Caching Cache Implementation // Cache user $user = Cache::remember("user.{$id}", 3600, function () use ($id) { return User::find($id); }); // Cache tags Cache::tags(['users', 'posts'])->put("user.{$id}", $user, 3600); // Clear cache Cache::tags(['users'])->flush(); 9. Database Migrations Migration Best Practices Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('email')->unique(); $table->string('name'); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); $table->timestamps(); $table->softDeletes(); $table->index('email'); }); 10. Testing Feature Tests class UserTest extends TestCase { use RefreshDatabase; public function test_can_create_user(): void { $response = $this->postJson('/api/users', [ 'name' => 'John Doe', 'email' => '[email protected]', 'password' => 'password123', 'password_confirmation' => 'password123', ]); $response->assertStatus(201) ->assertJsonStructure([ 'data' => [ 'id', 'name', 'email', ] ]); $this->assertDatabaseHas('users', [ 'email' => '[email protected]', ]); } } Best Practices Use Service Layer for business logic Form Requests for validation API Resources for data transformation Queues for long-running tasks Events for decoupled actions Eager Loading to avoid N+1 queries Caching for performance Write Tests for critical paths Conclusion Laravel provides powerful tools for building modern applications. Follow these practices to create maintainable, scalable Laravel applications! 🚀

December 10, 2025 · 4192 views

Laravel Queues with Horizon: Reliable Setup

Workers & balancing Define queue priorities; dedicate workers per queue (emails, webhooks, default). Use balance strategies (simple, auto) and cap max processes per supervisor. Reliability Set retry/backoff per job; push non-idempotent tasks carefully. Configure timeout and retry_after (keep retry_after > max job time). Use Redis with persistence; enable horizon:supervisors monitors. Observability Horizon dashboard: throughput, runtime, failures, retries. Alert on rising failures and long runtimes; log payload/context for failed jobs. Prune failed jobs with retention policy; send to DLQ when needed. Deployment Restart Horizon on deploy to pick up code; use horizon:terminate. Ensure supervisor/systemd restarts Horizon if it dies. Checklist Queues prioritized; supervisors sized. Retries/backoff and timeouts set; DLQ plan. Monitoring/alerts configured; failed job retention in place.

January 20, 2025 · 4041 views

Laravel Performance & Caching Playbook (2024)

Low-effort wins php artisan config:cache, route:cache, view:cache; warm on deploy. Enable OPcache with sane limits; preloading for hot classes when applicable. Use queues for emails/webhooks; keep HTTP requests lean. Database hygiene Add missing indexes; avoid N+1 with eager loading; paginate large lists. Use read replicas where safe; cap per-request query count in logs. Measure slow queries; set alarms on p95 query time. HTTP layer Cache responses with tags (Redis) for fast invalidation. Use CDN for static/media; compress and set cache headers. Leverage middleware to short-circuit authenticated user cache when possible. Observability Laravel Telescope or Horizon for queues; metrics on throughput, failures, latency. Log DB/query counts; track opcache hit rate and memory usage. Checklist Config/route/view cached on deploy. OPcache enabled and monitored. DB queries optimized and indexed; N+1 checks in CI. Responses cached where safe; queues handle slow work.

August 14, 2024 · 4550 views

MySQL Optimizer Checklist for PHP Apps

Query hygiene Add composite indexes matching filters/order; avoid leading wildcards. Use EXPLAIN to verify index usage; watch for filesort/temp tables. Prefer keyset pagination over OFFSET for large tables. Config basics Set innodb_buffer_pool_size (50-70% RAM), innodb_log_file_size, innodb_flush_log_at_trx_commit=1 (durable) or 2 (faster). max_connections aligned with app pool size; avoid connection storms. Enable slow query log with sane threshold; sample for tuning. App considerations Reuse connections (pooling); avoid long transactions. Limit selected columns; cap payload sizes; avoid large unbounded IN lists. For read-heavy workloads, add replicas; route reads carefully. Checklist Indexes audited; EXPLAIN reviewed. Buffer pool sized; slow log enabled. Pagination and payloads bounded; connections pooled.

July 28, 2024 · 4179 views

PHP-FPM Tuning Guide

Process manager modes pm=dynamic for most apps; pm=static only when workload is predictable and memory bounded. Key knobs: pm.max_children, pm.start_servers, pm.min_spare_servers, pm.max_spare_servers. Size max_children = (available RAM - OS/webserver/DB) / avg worker RSS. Opcache Enable: opcache.enable=1, opcache.enable_cli=0, opcache.memory_consumption sized for codebase, opcache.interned_strings_buffer, opcache.max_accelerated_files. Avoid opcache.revalidate_freq=0 in prod unless you control deploy restarts; prefer deploy-triggered reloads. Timeouts & queues Keep request_terminate_timeout sane (e.g., 30s-60s); long requests move to queues. Use pm.max_requests to recycle leaky workers (e.g., 500-2000). Watch slowlog to catch blocking I/O or heavy CPU. Observability Export status_path and scrape: active/idle/slow requests, max children reached. Correlate with Nginx/Apache logs for upstream latency and 502/504s. Alert on max children reached, slowlog entries, and rising worker RSS. Checklist Pool sizing validated under load test. Opcache enabled and sized; reload on deploy. Timeouts/queues tuned; slowlog on. Status endpoint protected and scraped.

December 3, 2023 · 4252 views