مقاله

Interface، Eloquent implementation، caching، testing و وقتی Repository اضافه است — راهنمای عملی نه dogma.

Repository Pattern در Laravel — پیاده‌سازی عمیق و اشتباهات رایج

Repository Pattern در Laravel — پیاده‌سازی عمیق و اشتباهات رایج

Repository لایه دسترسی به داده را از business logic جدا می‌کند. در Laravel بحث داغ است: بعضی می‌گویند Eloquent خودش repository است؛ بعضی برای تست و swap DB یک interface می‌خواهند. حقیقت میان‌دو است — برای پروژه کوچک شاید اضافه؛ برای domain پیچیده و تیم بزرگ ارزش دارد.

ساختار پایه

interface PostRepositoryInterface
{
    public function findBySlug(string $slug): ?Post;
    public function published(): Collection;
    public function create(array $data): Post;
}

class EloquentPostRepository implements PostRepositoryInterface
{
    public function findBySlug(string $slug): ?Post
    {
        return Post::query()->where('slug', $slug)->first();
    }

    public function published(): Collection
    {
        return Post::query()
            ->where('status', 'published')
            ->orderByDesc('published_at')
            ->get();
    }

    public function create(array $data): Post
    {
        return Post::create($data);
    }
}

Binding در ServiceProvider

public function register(): void
{
    $this->app->bind(
        PostRepositoryInterface::class,
        EloquentPostRepository::class
    );
}

Service فقط interface می‌بیند — DIP.

Repository vs Eloquent مستقیم

مستقیم EloquentRepository
سریع CRUDquery پیچیده متمرکز
کمتر فایلmock آسان در unit test
Laravel idiomaticswap implementation (cache، read replica)

QB vs Eloquent.

Scope در Repository نه Controller

public function forAuthor(User $user): Collection
{
    return Post::query()
        ->where('user_id', $user->id)
        ->with('category')
        ->latest()
        ->get();
}

Scopes داخل repo قابل reuse.

Caching در Repository

public function published(): Collection
{
    return Cache::remember('posts.published', 3600, fn () =>
        Post::query()->published()->get()
    );
}

invalidate در Observer — Observer.

تست با Mock

$repo = Mockery::mock(PostRepositoryInterface::class);
$repo->shouldReceive('findBySlug')->with('test')->andReturn($post);
$this->app->instance(PostRepositoryInterface::class, $repo);

Unit test mock.

اشتباهات رایج

  • Repository که فقط Post::all() wrap می‌کند — thin wrapper بی‌فایده
  • God Repository برای همه modelها
  • business logic داخل Repository — باید در Service/Action باشد
  • interface برای هر CRUD ۳ خطی

Generic Repository؟

BaseRepository<T> در PHP کمتر از C# — معمولاً per-aggregate repository واضح‌تر است.

جمع‌بندی

Repository وقتی query و data access پیچیده یا تست‌پذیری مهم است. Action: Action classes. CQRS بعدی در استراتژی.

data layer design