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

Baserepo Laravel Package

jsdecena/baserepo

A Laravel repository-pattern package that provides reusable base repository and contract classes for cleaner CRUD, query filtering, pagination, and model interaction.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require jsdecena/baserepo

The package has no service provider or config to publish — it is a thin abstraction layer, so installing it is the whole setup. Check the Jsdecena\Baserepo\BaseRepository source first; it is small and reading it (~100 lines) answers most questions faster than the README.

First use case — a CRUD repository for one model

namespace App\Repositories;

use App\Models\Post;
use Jsdecena\Baserepo\BaseRepository;

class PostRepository extends BaseRepository
{
    public function __construct(Post $post)
    {
        parent::__construct($post);
        $this->model = $post;
    }
}

Then inject it anywhere Laravel resolves dependencies:

class PostController extends Controller
{
    public function __construct(PostRepository $posts)
    {
        $this->posts = $posts;
    }

    public function show($id)
    {
        return $this->posts->find($id);
    }
}

Where to look first

  1. src/BaseRepository.php — the actual CRUD surface (all, find, findBy, create, update, delete, getModel).
  2. src/Traits/Searchable.php — search() implementation and the $searchable property.
  3. src/Traits/Cacheable.php — cache-wrapped reads and how keys are built.
  4. Test folder in the repo — the only reliable spec for signatures.

If the code you inherit still works today, you are almost certainly on Laravel ≤ 6/7 conventions and PHP ≤ 7.x; plan a review before dropping it into a Laravel 10/11 app (see Gotchas).

Implementation Patterns

Standard CRUD repository per aggregate root

One repository per Eloquent model, injected into a controller, job, or command. Keep the repository thin — the package does not add query builders or scopes, so anything sophisticated belongs in the model or a dedicated query object.

$post = $this->posts->create($request->validated());
$post = $this->posts->find($id);
$this->posts->update($request->validated());
$this->posts->delete();

Searchable trait for admin/list endpoints

use Jsdecena\Baserepo\BaseRepository;
use Jsdecena\Baserepo\Traits\Searchable;

class PostRepository extends BaseRepository
{
    use Searchable;

    protected $searchable = ['title', 'body'];
}

search($term) produces a WHERE ... OR ... LIKE query across $searchable. This is fine for small admin tables and small tables; it is not a substitute for Laravel Scout on large datasets.

Cacheable trait for hot reads

use Jsdecena\Baserepo\Traits\Cacheable;

class PostRepository extends BaseRepository
{
    use Cacheable;
}

Wrap read-only listing/detail methods with cache and invalidate in create/update/delete. Because the trait overrides methods like all() and find() from BaseRepository, cache invalidation has to be wired explicitly in your write paths (see Gotchas).

Interface + service provider binding

Define an interface (PostRepositoryInterface) and bind the concrete class in a dedicated RepositoryServiceProvider. This is the pattern the package is designed around and gives you test doubles without touching Eloquent.

$this->app->bind(PostRepositoryInterface::class, PostRepository::class);

Compose repositories for cross-model workflows

Because BaseRepository only wraps one model, keep multi-model orchestration in a service class. Example: an OnboardUserService that calls UserRepository::create and ProfileRepository::create inside a transaction — do not push cross-model logic into a single repository.

Return models, not query builders

findBy($field, $value) returns the first match; chain further Eloquent calls on the returned model, not on the repository. If you find yourself wanting a fluent interface, add explicit methods to your repository instead of leaking $this->model out.

Gotchas and Tips

It is effectively unmaintained. Last release was September 2019. There is no Laravel 8/9/10/11 tag and no PHP 8 type-hint update. It will usually still run because it delegates to Eloquent, but expect to fork or vendor-edit for newer PHP if you hit #[ReturnTypeWillChange] or strict typing issues. Budget a review for any project past Laravel 7.

find() mutates $this->model. Many of the base methods reassign $this->model to the fetched entity, so the repository is stateful after a call. Chaining two find() calls or reusing an injected repository within a long-running request/loop can produce surprising results. Safest pattern: inject per-request, call one method, and don't reuse the resolver across iterations in queued jobs.

Trait methods override base methods. Cacheable::all() / Cacheable::find() shadow BaseRepository::all() / find(). If you enable caching on a repository and call all() expecting fresh data (e.g. right after a write in the same request), you will get the cached version unless you invalidate. Put cache-busting in your update/delete wrappers, not in the base class.

Trait order matters for Searchable + Cacheable together. Both traits may define overlapping helpers. Declare them deliberately (use Cacheable, Searchable;) and confirm in a test which one wins for any shared method name before relying on it.

$searchable must be declared on the repository, not the model. The trait reads the repository property. Forgetting it silently produces an empty search. Add a feature test with a known term to catch this.

No built-in validation or exception handling. find() returns null if not found (Eloquent's find), and create() will throw whatever Eloquent throws. If you need "not found" exceptions or form-request validation, add them in your repository method overrides:

public function findOrFail($id)
{
    return $this->find($id) ?? throw new ModelNotFoundException;
}

No soft-delete awareness out of the box. all() uses get(), so soft-deleted rows are excluded as usual — but findBy and custom methods need to know whether you want withTrashed(). Wrap explicitly.

Better to extend than edit the vendor directory. If you need behavior changes (typed properties, PHP 8 compatibility, cache tags), create an App\Repositories\BaseRepository that extends the package class or copy the base class in. Composer will overwrite vendor/jsdecena/baserepo/ on composer update.

Debugging tip: when a call behaves differently than Eloquent would, dump $this->model->toSql() inside the method (or getModel() from outside) — the package adds no query manipulation except in the traits, so the query is always the underlying Eloquent state.

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.
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment