# Laravel Idioms

> Laravel Idioms and Patterns

- Skill: `irahardianto/laravel-idioms` (Agent Skill)
- Install (CLI): `npx skillmds@latest add irahardianto/laravel-idioms`
- Raw SKILL.md: https://api.skillmd.com/api/skills/irahardianto/laravel-idioms/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: irahardianto (https://skillmd.com/u/irahardianto)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/irahardianto/laravel-idioms

---


## Laravel Idioms and Patterns

Laravel rewards convention, Eloquent, and expressive syntax. Idiomatic Laravel = DRY, service-oriented, well-tested.

> Scope: Laravel-specific patterns. For PHP: `@.gemini/skills/php-idioms/SKILL.md`.

### Eloquent

1. **Scopes for reusable queries:**
   ```php
   class Task extends Model {
       public function scopeActive(Builder $query): Builder {
           return $query->where('status', 'active');
       }
   }
   // Usage: Task::active()->paginate(25);
   ```

2. **Eager loading** to avoid N+1: `Task::with('user', 'tags')->get()`.
3. **Accessors/Mutators** with `Attribute` cast (Laravel 9+).

### Service Layer

1. **Services for business logic** — controllers stay thin:
   ```php
   class TaskService {
       public function __construct(
           private readonly TaskRepository $repository,
       ) {}

       public function create(CreateTaskRequest $request): Task { ... }
   }
   ```

### Validation

1. **Form Requests for validation** — never validate in controllers:
   ```php
   class CreateTaskRequest extends FormRequest {
       public function rules(): array {
           return [
               'title' => ['required', 'string', 'max:200'],
               'priority' => ['required', Rule::enum(Priority::class)],
           ];
       }
   }
   ```

### Testing

1. **Pest (preferred) or PHPUnit:**
   ```php
   test('creating a task returns 201', function () {
       $response = $this->postJson('/api/tasks', ['title' => 'Test', 'priority' => 'high']);
       $response->assertCreated();
       $this->assertDatabaseHas('tasks', ['title' => 'Test']);
   });
   ```

2. **Factories** for test data. **RefreshDatabase** trait for isolation.

### Formatting and Static Analysis

| Tool | Purpose | Command |
|---|---|---|
| Laravel Pint | Formatting | `./vendor/bin/pint` |
| PHPStan + Larastan | Static analysis | `phpstan analyse` |
| `composer audit` | CVE scanning | `composer audit` |

### Related
- PHP Idioms @.gemini/skills/php-idioms/SKILL.md
- Database Design Principles @.gemini/skills/database-design-principles/SKILL.md

