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-query-scopes.md

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

Query Scopes for Reusable Queries

Impact: HIGH (DRY principle for database queries)

Encapsulate reusable query constraints in model scopes for cleaner, more maintainable code.

Bad Example

// Repeated query logic scattered across controllers
class PostController extends Controller
{
    public function index()
    {
        $posts = Post::where('published', true)
            ->where('published_at', '<=', now())
            ->orderBy('published_at', 'desc')
            ->get();

        return view('posts.index', compact('posts'));
    }

    public function featured()
    {
        // Same logic duplicated
        $posts = Post::where('published', true)
            ->where('published_at', '<=', now())
            ->where('is_featured', true)
            ->orderBy('published_at', 'desc')
            ->get();

        return view('posts.featured', compact('posts'));
    }
}

class ApiPostController extends Controller
{
    public function index()
    {
        // Again, duplicated logic
        $posts = Post::where('published', true)
            ->where('published_at', '<=', now())
            ->paginate(20);

        return PostResource::collection($posts);
    }
}

Good Example

// Model with reusable scopes
namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    // Local scope - called as scopePublished, used as published()
    public function scopePublished(Builder $query): Builder
    {
        return $query->where('published', true)
            ->where('published_at', '<=', now());
    }

    public function scopeFeatured(Builder $query): Builder
    {
        return $query->where('is_featured', true);
    }

    public function scopeRecent(Builder $query): Builder
    {
        return $query->orderBy('published_at', 'desc');
    }

    public function scopeByAuthor(Builder $query, User $author): Builder
    {
        return $query->where('author_id', $author->id);
    }

    public function scopeInCategory(Builder $query, int|Category $category): Builder
    {
        $categoryId = $category instanceof Category ? $category->id : $category;
        return $query->where('category_id', $categoryId);
    }

    // Dynamic scope with parameters
    public function scopeCreatedBetween(Builder $query, $start, $end): Builder
    {
        return $query->whereBetween('created_at', [$start, $end]);
    }

    // Scope with optional parameter
    public function scopePopular(Builder $query, int $minViews = 1000): Builder
    {
        return $query->where('views', '>=', $minViews);
    }
}
// Clean controller using scopes
class PostController extends Controller
{
    public function index()
    {
        $posts = Post::published()->recent()->get();

        return view('posts.index', compact('posts'));
    }

    public function featured()
    {
        $posts = Post::published()
            ->featured()
            ->recent()
            ->get();

        return view('posts.featured', compact('posts'));
    }

    public function byAuthor(User $author)
    {
        $posts = Post::published()
            ->byAuthor($author)
            ->recent()
            ->paginate(20);

        return view('posts.by-author', compact('posts', 'author'));
    }
}
// Global scope - automatically applied to all queries
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;

class PublishedScope implements Scope
{
    public function apply(Builder $builder, Model $model): void
    {
        $builder->where('published', true);
    }
}
// Apply global scope in model
class Post extends Model
{
    protected static function booted(): void
    {
        static::addGlobalScope(new PublishedScope);

        // Or inline
        static::addGlobalScope('active', function (Builder $builder) {
            $builder->where('deleted_at', null);
        });
    }
}

// Remove global scope when needed
Post::withoutGlobalScope(PublishedScope::class)->get();
Post::withoutGlobalScope('active')->get();
Post::withoutGlobalScopes()->get(); // Remove all

Why

  • DRY: Query logic defined once, used everywhere
  • Readable: Expressive, chainable method names
  • Maintainable: Changes to query logic happen in one place
  • Testable: Scopes can be unit tested
  • Encapsulation: Query details hidden in the model
  • Chainable: Scopes can be combined fluently

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