Good Code
The good version makes authorization visible as a named policy decision before mutation. That rule can be reused by controllers, jobs, or tests.
Lesson 08
Use policies or gates for model-level authorization so access rules are named, reusable, and testable.
<?php
namespace App\Http\Controllers;
use App\Models\Review;
use Illuminate\Support\Facades\Gate;
final class ReviewController
{
public function update(UpdateReviewRequest $request, Review $review)
{
// A named policy decides whether this user may update the review.
Gate::authorize('update', $review);
$review->update($request->validated());
return $review->fresh();
}
}<?php
public function update(Request $request, Review $review)
{
// Inline ownership checks drift when other actions need the same rule.
if ($request->user()->id !== $review->user_id && ! $request->user()->is_admin) {
abort(403);
}
$review->update($request->all());
return $review;
}The good version makes authorization visible as a named policy decision before mutation. That rule can be reused by controllers, jobs, or tests.
The bad version repeats an ownership check inline and mixes authorization with unchecked input writes.