What you'll learn
Model data with Eloquent while preserving query awareness. You will evolve schemas, define relationships, eliminate N+1 queries, build realistic factories, and move request validation and authorization into Form Requests.
By the end of this lesson, you'll be able to:
- Create Laravel migrations and Eloquent relationships
- Use eager loading and pagination intentionally
- Validate and authorize input with Form Requests
Core mental model
Professional PHP is less about memorizing APIs and more about choosing a clear boundary for each responsibility. Use this table as a decision guide while reading the examples.
| Concept | What it protects | Decision rule |
|---|---|---|
| Relationship | Expressive related queries | Declare cardinality and still inspect generated SQL. |
| Eager loading | Bounded query count | Load known relations before looping or serializing. |
| Form Request | HTTP input contract | Centralize route authorization and validation. |
Professional workflow
Build the feature in small, verifiable steps. Each step leaves the system in a state you can test.
- Describe the Laravel data boundary boundary: its inputs, outputs, invariants, and expected failures.
- Implement the smallest happy path behind an explicit contract.
- Add validation and translate low-level failures into language the caller understands.
- Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
- Refactor only after behavior is protected by a repeatable check.
Make the boundary visible
Guided code lab
Define schema and model relationship
The foreign key is enforced in SQL; Eloquent exposes the object traversal.
<?php
Schema::create('lessons', function (Blueprint $table): void {
$table->id();
$table->foreignId('course_id')->constrained()->cascadeOnDelete();
$table->string('title', 180);
$table->unsignedInteger('position');
$table->timestamps();
$table->unique(['course_id', 'position']);
});
// In Course.php
public function lessons(): HasMany
{
return $this->hasMany(Lesson::class)->orderBy('position');
}Authorize and validate one command
The controller receives only validated data after the request also checks permission.
<?php
final class StoreCourseRequest extends FormRequest
{
public function authorize(): bool
{
return $this->user()?->can('create', Course::class) ?? false;
}
public function rules(): array
{
return [
'title' => ['required', 'string', 'max:180'],
'slug' => ['required', 'alpha_dash', 'max:190', 'unique:courses,slug'],
'price_cents' => ['required', 'integer', 'min:0'],
];
}
}Production practice
Contract
Treat models as persistence-aware objects and keep multi-model business workflows in actions or services.
Verification
Refresh the database, use factories for intent-revealing data, and assert queries or relations where performance matters.
Operations
Review migration lock risk and enable production query monitoring for slow or unexpectedly repeated SQL.
Common failure mode
Independent workshop
Add modules, lessons, tags, reviews, and publish validation to the Laravel catalog.
Your finished workshop must include:
- Constrained migrations and model relationships
- Factories, seeders, and eager-loaded queries
- Form Requests covering create and update rules
Definition of done
Recap & quick check
Key takeaways
- Database constraints remain essential with an ORM.
- Eloquent relationships are query builders.
- Eager loading prevents N+1 behavior.
- Form Requests combine transport validation and authorization.
Quick check
1. What avoids repeated relation queries?
2. Where can route-level authorization accompany validation?
3. Should Eloquent replace foreign keys?
Keep the workshop: later phases deliberately build on these boundaries, so today's small example can become part of your portfolio architecture.