All skills
asyrafhussin avatar

/laravel-best-practices

@ef59186

Laravel 13 conventions and best practices. Use when creating controllers, models, migrations, validation, services, or structuring Laravel applications. Triggers on tasks involving Laravel architecture, Eloquent, database, API development, or PHP patterns.

Use this Skill: https://skilld.dev/gh/asyrafhussin/agent-skills/laravel-best-practices

This session only. Nothing lands on disk.

ruleseloquent-model-events.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Model Events and Observers

Impact: HIGH (Clean lifecycle hooks and side effects)

Use model events and observers to react to model lifecycle changes cleanly.

Bad Example

// Logic scattered in controllers
class UserController extends Controller
{
    public function store(Request $request)
    {
        $user = User::create($request->validated());

        // Side effects in controller
        $user->profile()->create();
        Mail::to($user)->send(new WelcomeEmail($user));
        Log::info('User created', ['user_id' => $user->id]);
        Cache::forget('users-count');

        return redirect()->route('users.show', $user);
    }

    public function destroy(User $user)
    {
        // Manual cleanup
        $user->posts()->delete();
        $user->comments()->delete();
        Storage::delete($user->avatar_path);
        Cache::forget("user-{$user->id}");

        $user->delete();

        return redirect()->route('users.index');
    }
}

Good Example

// Using model events in the model itself
namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class User extends Model
{
    protected static function booted(): void
    {
        // Before creating
        static::creating(function (User $user) {
            $user->uuid = Str::uuid();
            $user->api_token = Str::random(60);
        });

        // After creating
        static::created(function (User $user) {
            $user->profile()->create();
        });

        // Before updating
        static::updating(function (User $user) {
            if ($user->isDirty('email')) {
                $user->email_verified_at = null;
            }
        });

        // Before deleting
        static::deleting(function (User $user) {
            $user->posts()->delete();
            $user->comments()->delete();
        });

        // After deleting
        static::deleted(function (User $user) {
            Storage::delete($user->avatar_path);
        });
    }
}
// Using an Observer for more complex scenarios
namespace App\Observers;

use App\Events\UserRegistered;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Str;

class UserObserver
{
    public function creating(User $user): void
    {
        $user->uuid = Str::uuid();
    }

    public function created(User $user): void
    {
        $user->profile()->create();
        event(new UserRegistered($user));
    }

    public function updating(User $user): void
    {
        if ($user->isDirty('email')) {
            $user->email_verified_at = null;
        }
    }

    public function updated(User $user): void
    {
        Cache::forget("user-{$user->id}");
    }

    public function deleting(User $user): void
    {
        // Cascade soft deletes
        $user->posts()->delete();
    }

    public function deleted(User $user): void
    {
        Storage::delete($user->avatar_path);
        Cache::forget("user-{$user->id}");
        Log::info('User deleted', ['user_id' => $user->id]);
    }

    public function restored(User $user): void
    {
        // Restore related soft deleted records
        $user->posts()->restore();
    }

    public function forceDeleted(User $user): void
    {
        // Permanent deletion cleanup
        $user->posts()->forceDelete();
    }
}
// Register observer in AppServiceProvider
class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        User::observe(UserObserver::class);
    }
}
// Or use the ObservedBy attribute (Laravel 10+)
namespace App\Models;

use App\Observers\UserObserver;
use Illuminate\Database\Eloquent\Attributes\ObservedBy;
use Illuminate\Database\Eloquent\Model;

#[ObservedBy([UserObserver::class])]
class User extends Model
{
    // ...
}
// Clean controller
class UserController extends Controller
{
    public function store(StoreUserRequest $request)
    {
        $user = User::create($request->validated());
        // All side effects handled by observer

        return redirect()->route('users.show', $user);
    }

    public function destroy(User $user)
    {
        $user->delete();
        // Cleanup handled by observer

        return redirect()->route('users.index');
    }
}
// Available model events
// creating, created
// updating, updated
// saving, saved (fires for both create and update)
// deleting, deleted
// restoring, restored (for soft deletes)
// forceDeleting, forceDeleted
// replicating
// retrieved

Why

  • Separation of concerns: Controllers stay focused on HTTP
  • Consistency: Same behavior regardless of how model is created/updated
  • Single responsibility: Observer handles all model lifecycle logic
  • Testable: Can test observer behavior independently
  • DRY: Side effects defined once, triggered automatically
  • Maintainability: Easy to find all model-related logic in one place

Source: SKILL.md on GitHub

No alerts16d5 checks · Risk SAFE
  • Gen Agent Trust Hub16d

    The skill is a comprehensive guide to Laravel 13 best practices, providing safe and standard architectural, database, and security patterns for PHP development. No malicious behavior or security risks were detected.

  • Socket16d

    No alerts

  • Snyk16d

    Risk: LOW · No issues

  • Runlayer6mo

    1/37 files flagged

  • ZeroLeaks5mo

    2 findings · Score: 80/100

Signed by skilld at ef59186. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last month.

Steadyupdated 7 months ago
Other metadata
metadata
{
  "author": "Laravel Community",
  "version": "2.1.0",
  "laravelVersion": "13.x",
  "phpVersion": "8.3+"
}

README badge

README badge for asyrafhussin/agent-skills/laravel-best-practices