← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Repository Pattern

general PHP 5.0+ Intermediate
debt(d7/e7/b7/t5)
d7 Detectability Operational debt — how invisible misuse is to your safety net

Closest to 'only careful code review or runtime testing' (d7). phpstan/psalm cannot detect missing repository abstraction — scattered Eloquent/Doctrine calls in controllers are valid code that only architecture review catches.

e7 Effort Remediation debt — work required to fix once spotted

Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix sounds simple (define interface, implement it), but retrofitting repositories means touching every controller/service that currently calls the ORM directly — cross-cutting across the codebase.

b7 Burden Structural debt — long-term weight of choosing wrong

Closest to 'strong gravitational pull' (b7). applies_to spans web/cli/queue and the pattern shapes the domain/infrastructure boundary; once adopted, every new data access decision is shaped by it. Not b9 because it can coexist with direct ORM access in places.

t5 Trap Cognitive debt — how counter-intuitive correct behaviour is

Closest to 'notable trap most devs eventually learn' (t5). Per misconception, devs think a repository is just a DB wrapper and leak ORM methods (whereHas, paginate) into the interface — a well-documented gotcha but not catastrophic.

About DEBT scoring →

Also Known As

repository data repository repository abstraction

TL;DR

Abstracts the data persistence layer behind an interface, decoupling domain logic from database implementation details.

Explanation

The Repository pattern provides a collection-like interface for accessing domain objects, hiding the underlying data source (SQL, NoSQL, API, file system). Business logic works against the interface (UserRepositoryInterface) without knowing about SQL. This enables testing with in-memory or mock repositories without a database, swapping storage technologies, and enforcing that all data access goes through a defined contract. In PHP, repositories are typically injected via DI and type-hinted to their interface, not their concrete implementation.

Diagram

flowchart LR
    subgraph Application Layer
        UC[Use Case /<br/>Service]
    end
    subgraph Domain Layer
        ENT[Domain Entity<br/>Order, User]
        REPO_INT[Repository<br/>Interface]
    end
    subgraph Infrastructure Layer
        REPO_IMPL[Repository<br/>Implementation]
        ORM[ORM / PDO]
        DB[(Database)]
    end
    UC --> REPO_INT
    REPO_INT -.->|implemented by| REPO_IMPL
    REPO_IMPL --> ORM --> DB
    ENT -.->|returned by| REPO_INT
style ENT fill:#6e40c9,color:#fff
style REPO_INT fill:#1f6feb,color:#fff
style REPO_IMPL fill:#238636,color:#fff

Common Misconception

A repository is just a class that wraps database calls. A repository abstracts the entire persistence mechanism — code using a repository should not know or care whether data comes from MySQL, Redis, or an API. This makes repositories trivially swappable in tests.

Why It Matters

The repository pattern decouples business logic from data access — you can swap MySQL for PostgreSQL, add a caching layer, or mock the repository in tests without touching a single line of domain code.

Common Mistakes

  • Leaking ORM-specific methods (whereHas, with, paginate) into the repository interface — the interface should speak domain language.
  • Creating a generic repository base class that exposes every possible query — defeats the purpose of hiding persistence details.
  • Putting business logic inside the repository — it should only handle reading and writing, not rules.
  • Skipping repositories entirely in Laravel because Eloquent "is good enough" — fine for small apps, painful at scale.

Avoid When

  • Simple CRUD applications with no domain logic — a repository over an ORM that already abstracts the DB is double abstraction.
  • The repository becomes a query dumping ground with 50+ methods — use query objects or specifications instead.
  • You only have one data source and no plans to change it — the abstraction adds complexity for no gain.
  • Microservices that own a single table — an ORM directly in the service is often sufficient.

When To Use

  • Domain-driven design where you want to keep persistence logic out of domain entities.
  • Applications that need to switch or support multiple data sources (DB + cache + API).
  • Code that requires thorough unit testing — repositories can be replaced with in-memory fakes.
  • Complex query logic that should be centralised and named rather than scattered across service classes.

Code Examples

✗ Vulnerable
// Controller talks directly to Eloquent everywhere
class OrderController {
    public function index() {
        return Order::where('status', 'paid')
            ->with('user', 'items')
            ->orderByDesc('created_at')
            ->paginate(20);
    }
}
✓ Fixed
// Controller uses repository interface
class OrderController {
    public function __construct(private OrderRepositoryInterface $orders) {}
    public function index() {
        return $this->orders->findPaid(limit: 20);
    }
}

Added 13 Mar 2026
Edited 25 Mar 2026
Views 27
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 2 pings T 0 pings F 0 pings S 1 ping S 0 pings M 0 pings T 1 ping W 0 pings T 1 ping F 0 pings S 1 ping S 1 ping M 0 pings T 0 pings W 1 ping T 0 pings F 1 ping S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T 0 pings F
No pings yet today
No pings yesterday
Amazonbot 7 Perplexity 7 Google 4 Ahrefs 2 Unknown AI 2 ChatGPT 2 Bing 1
crawler 21 crawler_json 4
DEV INTEL Tools & Severity
🟡 Medium ⚙ Fix effort: Medium
⚡ Quick Fix
Define a repository interface in the domain layer with methods like findById, save, delete — implement it in the infrastructure layer with Doctrine/Eloquent
📦 Applies To
PHP 5.0+ web cli queue-worker laravel symfony doctrine
🔗 Prerequisites
🔍 Detection Hints
Eloquent or Doctrine calls scattered across controllers services — no centralised data access layer
Auto-detectable: ✗ No phpstan psalm
⚠ Related Problems
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: Class Tests: Update

✓ schema.org compliant