When working with complex query builders or fluent APIs in Laravel, proper formatting makes a huge difference in code maintainability. Breaking long inline chains into multi-line structures with consistent indentation helps future developers (including you) understand the flow at a glance.
Before: Hard to Read
Single-line method chains are difficult to parse:
$data = Model::fromSub(array_reduce([$query1, $query2, $query3], fn($sub, $q) => $sub ? $sub->union($q->toBase()) : $q->toBase()), 'items')->with('relation1', 'relation2')->get();
After: Much Better
The same logic with proper line breaks:
$data = Model::fromSub(
array_reduce(
[$query1, $query2, $query3],
fn($sub, $q) => $sub
? $sub->union($q->toBase())
: $q->toBase()
),
'items'
)
->with('relation1', 'relation2')
->get();
Key Formatting Principles
1. One logical step per line
// Bad
$users = User::with('posts')->where('active', true)->orderBy('name')->get();
// Good
$users = User::with('posts')
->where('active', true)
->orderBy('name')
->get();
2. Indent nested structures consistently
$results = Report::query()
->select([
'reports.*',
DB::raw('COUNT(comments.id) as comment_count'),
])
->leftJoin('comments', function ($join) {
$join->on('comments.report_id', '=', 'reports.id')
->where('comments.approved', true);
})
->groupBy('reports.id')
->having('comment_count', '>', 5)
->get();
3. Align related parameters vertically
$data = Task::with([
'project',
'assignee.department',
'comments.author',
'attachments',
])
->whereIn('status', [
'pending',
'in_progress',
'review',
])
->get();
4. Break closures into multiple lines when they contain logic
// Single-line is fine for simple closures
$ids = $collection->map(fn($item) => $item->id);
// Multi-line for complex logic
$formatted = $collection->map(function ($item) {
return [
'id' => $item->id,
'name' => $item->name,
'status' => $item->getStatusLabel(),
];
});
Real-World Example
Extract complex nested structures to variables for clarity:
// Extract the union query for readability
$unionQuery = array_reduce(
[
Report::where('type', 'daily'),
Report::where('type', 'weekly'),
Report::where('type', 'monthly'),
],
fn($sub, $query) => $sub
? $sub->union($query->toBase())
: $query->toBase()
);
// Now the main query is much clearer
$results = Report::withTrashed()
->fromSub($unionQuery, 'reports')
->with([
'author',
'department',
'approvals.user',
])
->orderByDesc('created_at')
->paginate(50);
Your IDE’s auto-formatter may not always get this right — sometimes manual formatting wins for clarity. The goal is to make the code’s intent obvious at a glance.
Leave a Reply