Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Modern PHP 8.3+ development with strict typing, PHPStan level 9, PSR standards, and Laravel/Symfony support.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/laravel-patterns.md
1# Laravel Patterns23## Service Layer Pattern45```php6<?php78declare(strict_types=1);910namespace App\Services;1112use App\DTOs\CreateUserData;13use App\Models\User;14use App\Repositories\UserRepositoryInterface;15use Illuminate\Support\Facades\Hash;1617final readonly class UserService18{19public function __construct(20private UserRepositoryInterface $userRepository,21private EmailService $emailService,22) {}2324public function createUser(CreateUserData $data): User25{26$user = $this->userRepository->create([27'name' => $data->name,28'email' => $data->email,29'password' => Hash::make($data->password),30]);3132$this->emailService->sendWelcomeEmail($user);3334return $user;35}3637public function suspendUser(int $userId, string $reason): void38{39$user = $this->userRepository->findOrFail($userId);4041$this->userRepository->update($user->id, [42'status' => UserStatus::SUSPENDED,43'suspension_reason' => $reason,44'suspended_at' => now(),45]);4647$this->emailService->sendSuspensionNotice($user, $reason);48}49}50```5152## Repository Pattern5354```php55<?php5657declare(strict_types=1);5859namespace App\Repositories;6061use App\Models\User;62use Illuminate\Database\Eloquent\Collection;6364interface UserRepositoryInterface65{66public function findOrFail(int $id): User;67public function findByEmail(string $email): ?User;68public function create(array $data): User;69public function update(int $id, array $data): User;70public function delete(int $id): void;71public function getActive(): Collection;72}7374final class UserRepository implements UserRepositoryInterface75{76public function findOrFail(int $id): User77{78return User::findOrFail($id);79}8081public function findByEmail(string $email): ?User82{83return User::where('email', $email)->first();84}8586public function create(array $data): User87{88return User::create($data);89}9091public function update(int $id, array $data): User92{93$user = $this->findOrFail($id);94$user->update($data);95return $user->fresh();96}9798public function delete(int $id): void99{100$this->findOrFail($id)->delete();101}102103public function getActive(): Collection104{105return User::where('status', UserStatus::ACTIVE)106->orderBy('created_at', 'desc')107->get();108}109}110```111112## Form Requests with Enums113114```php115<?php116117declare(strict_types=1);118119namespace App\Http\Requests;120121use App\Enums\UserRole;122use Illuminate\Foundation\Http\FormRequest;123use Illuminate\Validation\Rule;124use Illuminate\Validation\Rules\Enum;125use Illuminate\Validation\Rules\Password;126127final class CreateUserRequest extends FormRequest128{129public function authorize(): bool130{131return $this->user()?->can('create', User::class) ?? false;132}133134public function rules(): array135{136return [137'name' => ['required', 'string', 'max:255'],138'email' => ['required', 'email', 'unique:users,email'],139'password' => ['required', Password::min(8)->mixedCase()->numbers()],140'role' => ['required', new Enum(UserRole::class)],141'settings' => ['sometimes', 'array'],142'settings.theme' => ['string', Rule::in(['light', 'dark'])],143];144}145146public function toDto(): CreateUserData147{148return new CreateUserData(149name: $this->validated('name'),150email: $this->validated('email'),151password: $this->validated('password'),152role: UserRole::from($this->validated('role')),153);154}155}156```157158## API Resources159160```php161<?php162163declare(strict_types=1);164165namespace App\Http\Resources;166167use Illuminate\Http\Request;168use Illuminate\Http\Resources\Json\JsonResource;169170/**171* @mixin \App\Models\User172*/173final class UserResource extends JsonResource174{175public function toArray(Request $request): array176{177return [178'id' => $this->id,179'name' => $this->name,180'email' => $this->email,181'status' => $this->status->value,182'role' => $this->role->value,183'created_at' => $this->created_at->toIso8601String(),184185// Conditional relationships186'posts' => PostResource::collection($this->whenLoaded('posts')),187'profile' => new ProfileResource($this->whenLoaded('profile')),188189// Conditional attributes190'is_admin' => $this->when($this->role === UserRole::ADMIN, true),191192// Pivot data193'team_role' => $this->whenPivotLoaded('team_user', fn() =>194$this->pivot->role195),196];197}198}199200final class UserCollection extends ResourceCollection201{202public function toArray(Request $request): array203{204return [205'data' => $this->collection,206'meta' => [207'total' => $this->total(),208'per_page' => $this->perPage(),209],210];211}212}213```214215## Controllers with DTOs216217```php218<?php219220declare(strict_types=1);221222namespace App\Http\Controllers\Api;223224use App\Http\Controllers\Controller;225use App\Http\Requests\CreateUserRequest;226use App\Http\Resources\UserResource;227use App\Services\UserService;228use Illuminate\Http\JsonResponse;229use Illuminate\Http\Resources\Json\AnonymousResourceCollection;230231final class UserController extends Controller232{233public function __construct(234private readonly UserService $userService,235) {}236237public function index(): AnonymousResourceCollection238{239$users = User::with('profile')240->where('status', UserStatus::ACTIVE)241->paginate(20);242243return UserResource::collection($users);244}245246public function store(CreateUserRequest $request): JsonResponse247{248$user = $this->userService->createUser($request->toDto());249250return (new UserResource($user))251->response()252->setStatusCode(201);253}254255public function show(User $user): UserResource256{257$user->load(['posts', 'profile']);258return new UserResource($user);259}260261public function destroy(User $user): JsonResponse262{263$this->authorize('delete', $user);264265$this->userService->deleteUser($user->id);266267return response()->json(null, 204);268}269}270```271272## Jobs & Queues273274```php275<?php276277declare(strict_types=1);278279namespace App\Jobs;280281use App\Models\User;282use App\Services\EmailService;283use Illuminate\Bus\Queueable;284use Illuminate\Contracts\Queue\ShouldQueue;285use Illuminate\Foundation\Bus\Dispatchable;286use Illuminate\Queue\InteractsWithQueue;287use Illuminate\Queue\SerializesModels;288289final class SendWelcomeEmail implements ShouldQueue290{291use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;292293public int $tries = 3;294public int $timeout = 30;295296public function __construct(297private readonly int $userId,298) {}299300public function handle(EmailService $emailService): void301{302$user = User::findOrFail($this->userId);303$emailService->sendWelcomeEmail($user);304}305306public function failed(\Throwable $exception): void307{308\Log::error('Failed to send welcome email', [309'user_id' => $this->userId,310'error' => $exception->getMessage(),311]);312}313}314315// Dispatching jobs316SendWelcomeEmail::dispatch($user->id);317SendWelcomeEmail::dispatch($user->id)->delay(now()->addMinutes(5));318SendWelcomeEmail::dispatch($user->id)->onQueue('emails');319```320321## Event Listeners322323```php324<?php325326declare(strict_types=1);327328namespace App\Events;329330use App\Models\User;331use Illuminate\Foundation\Events\Dispatchable;332use Illuminate\Queue\SerializesModels;333334final readonly class UserRegistered335{336use Dispatchable, SerializesModels;337338public function __construct(339public User $user,340) {}341}342343namespace App\Listeners;344345use App\Events\UserRegistered;346use App\Jobs\SendWelcomeEmail;347use Illuminate\Contracts\Queue\ShouldQueue;348349final class SendWelcomeNotification implements ShouldQueue350{351public function handle(UserRegistered $event): void352{353SendWelcomeEmail::dispatch($event->user->id);354}355}356357// In EventServiceProvider358protected $listen = [359UserRegistered::class => [360SendWelcomeNotification::class,361UpdateUserStatistics::class,362],363];364```365366## Quick Reference367368| Pattern | Purpose | File Location |369|---------|---------|---------------|370| Service | Business logic | `app/Services/` |371| Repository | Data access | `app/Repositories/` |372| Form Request | Validation | `app/Http/Requests/` |373| Resource | API responses | `app/Http/Resources/` |374| Job | Async tasks | `app/Jobs/` |375| Event | Domain events | `app/Events/` |376| DTO | Data transfer | `app/DTOs/` |377| Policy | Authorization | `app/Policies/` |378