Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Repository Laravel Package

jooservices/laravel-repository

A Laravel repository package that adds a clean data-access layer over Eloquent, helping organize queries, reuse filtering and caching logic, and keep controllers and models lean. Suitable for building testable, maintainable Laravel applications.

View on GitHub
Deep Wiki
Context7

Getting Started

v4.0.0 is a major release driven by a standards alignment ("Align package to JOOservices v4 standards") rather than a feature launch. The changelog is terse, so treat the upgrade as a breaking change until you've read the diff between v3.x and v4.0.0 and confirmed the package's PHP/Laravel support matrix.

Minimum steps:

composer require jooservices/laravel-repository:^4.0
php artisan vendor:publish --tag=repository-config   # if a config file ships
php artisan test

First places to look, in order:

  1. CHANGELOG.md / the compare view .../compare/v3.x...v4.0.0 — the real breaking changes live here, not in the release notes.
  2. composer.json — confirm php and illuminate/* constraints before you touch anything else; a standards bump usually raises both.
  3. src/Contracts/ — the interfaces are the API surface you bind against. If signatures changed, your implementations break before anything else does.
  4. config/repository.php (if present) — cache, pagination, and default-model settings are usually here.
  5. tests/ — the package's own tests are the fastest, most accurate documentation of intended v4 usage.

First use case: one aggregate, one repository. Pick your most-read model, define an interface that returns domain-shaped results (Collection, DTOs, or paginators — not query builders), and wire it in a service provider:

// app/Providers/RepositoryServiceProvider.php
public function register(): void
{
    $this->app->bind(
        \App\Contracts\UserRepositoryInterface::class,
        \App\Repositories\UserRepository::class,
    );
}

Don't retrofit your whole codebase on day one. Get one repository working end-to-end under v4, run it against real queries, then scale out.

Implementation Patterns

Repository per aggregate root, not per table. Join tables and pivot models don't get repositories; they're reached through their aggregate. This is the single biggest driver of whether the pattern helps or becomes ceremony.

Keep Eloquent inside the boundary. The value of the pattern is that Illuminate\Database\Eloquent\Builder never escapes into controllers, jobs, or Blade. If a method returns a builder "for flexibility," you've paid the abstraction cost and kept the coupling.

Criteria for cross-cutting filters. The JOOservices lineage leans on a criteria/filter pattern for reusable query constraints (active-only, tenant-scoped, date-ranged). Prefer criteria over boolean flags accumulating in method signatures:

final class ActiveOnly implements CriterionInterface
{
    public function apply(mixed $query): mixed
    {
        return $query->where('is_active', true);
    }
}

Caching at the repository layer, invalidation at the write method. Read methods (find, all, paginate) are the natural cache seam. Pair every cached read with explicit invalidation inside create/update/delete — not in observers, not in the model. Cache tags keyed by aggregate make this tractable; if the configured store doesn't support tags, fall back to versioned keys.

Transactions belong in services, not repositories. A repository method wrapping DB::transaction() looks tidy but forces nested transactions the moment a service composes two repositories. Let the service own the unit of work.

Pagination as a first-class return type. Decide per method: LengthAwarePaginator for API index endpoints, Collection for internal composition, scalar/?Model for lookups. Encode that in the interface docblocks so callers don't guess.

Testing seam. Bind a fake or an in-memory implementation in tests to exercise service logic without a database; use a real repository with SQLite in-memory against migrations for a thin set of integration tests that actually verify the queries. Both, not either.

Integration points to wire deliberately: form requests → service → repository (not request → repository); API resources consuming repository results; queued jobs resolving interfaces via the container rather than constructing repositories.

Gotchas and Tips

  • The version bump is the story. "Align to v4 standards" almost certainly means tightened typing (return types, mixed/generics in docblocks), possibly renamed namespaces or contracts, and a raised PHP floor. Run a static analyser (PHPStan/Larastan) after upgrading — it will surface the interface drift faster than your test suite will.
  • Watch for silent return-type changes. A repository method that used to return a Collection and now returns an array (or vice versa) won't fail until something calls ->map() on it. Grep your call sites for collection methods before trusting a green build.
  • Criterion statefulness. Criteria objects that accumulate state on the instance leak between calls in long-lived workers (Octane, queue workers). Make criteria stateless or clone them per application.
  • Reusable repositories must reset criteria. If your base repository stores applied criteria for later reuse, forgetting to reset after apply() produces queries that silently carry filters from a previous call — a classic heisenbug that only appears under load.
  • N+1 hides behind good abstractions. A repository all() that returns hydrated models still lazy-loads relations. Either accept eager-load hints as a parameter or expose dedicated methods; don't let the abstraction convince you the problem went away.
  • Don't inject repositories into models. It inverts the dependency and creates resolution loops during boot. Services and controllers only.
  • Debugging: DB::listen() or ->dd() on the query builder inside the repository is fine and fast. Telescope's query panel is better for seeing whether the issue is your query or your cache layer — clear the cache before profiling, or you'll profile a hit.
  • Extension points: override the base repository's protected query-building methods before you fork the class; register custom criteria and cast/hydration strategies through the container so they stay swappable. If you find yourself copying a package class into app/, open an issue instead — that's the signal the extension point is missing.
  • Pin the major version. "jooservices/laravel-repository": "^4.0" — not *, and not dev-main, especially given how little the release notes tell you.
  • Re-verify the support matrix against your Laravel version before rolling this into a shared codebase; a standards alignment often ships alongside a framework-minimum bump, and that constraint propagates to every app that depends on you.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource