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

Repository Laravel Package

znck/repository

A Laravel repository package that abstracts data access behind clean interfaces, keeping controllers thin and your code testable. Swap Eloquent-backed implementations, add caching, and bind repositories through the container without rewriting business logic.

View on GitHub
Deep Wiki
Context7

Getting Started

This release marks the package's transition from a self-contained model-binding API to Laravel Scout as the search backend. If you are picking it up fresh, start here:

  1. Install the package and Scout together. Scout is now a peer requirement rather than an optional nicety:

    composer require laravel/scout
    php artisan vendor:publish --provider="Laravel\Scout\ScoutServiceProvider"
    
  2. Publish the package config and read it top to bottom before touching code. The driver and index-name settings are the two knobs you will actually change; everything else is usually fine at defaults.

  3. Set your Scout driver in .env. For local development, SCOUT_DRIVER=database gets you working search with zero infrastructure. Switch to meilisearch, typesense, or algolia only when you need relevance tuning or faceting — don't pay that operational cost on day one.

  4. First use case: make one existing Eloquent model searchable (Searchable trait + toSearchableArray()), import it, and wire a single controller endpoint. Resist the urge to make every model searchable in the first PR.

Where to look first when something misbehaves, in order: the package's config file, its service provider bindings (that's where the engine is resolved), and the package's own test suite — the test suite is the most reliable documentation of the supported API surface in a 0.x package.

Implementation Patterns

Migrating away from model(). This is the dominant workflow for anyone upgrading. The old pattern bound the package to a specific Eloquent model in configuration; the new pattern pushes that responsibility onto Scout's searchable() entry point. Concretely, calls that looked like a configured singleton now become explicit per-model queries:

// Before (v0.2.x)
$results = Package::model(Product::class)->search($term);

// After (v0.3.x)
$results = Product::search($term)->get();

The important architectural shift is that the model is now chosen at the call site, not at boot. That is a net win — it means one application can search products, articles, and users through the same package without reconfiguring a global — but it also means any code that relied on a configured default model must now pass one explicitly.

Wrap search in a dedicated action or query object. Search logic metastasizes. Put Model::search($term)->where(...)->paginate() behind a single class per domain so that swapping drivers or adding filters is a one-file change:

final class SearchProducts
{
    public function __invoke(string $term, array $filters = []): LengthAwarePaginator
    {
        return Product::search($term)
            ->when($filters['category'] ?? null, fn ($q, $c) => $q->where('category_id', $c))
            ->paginate(24)
            ->withQueryString();
    }
}

Keep toSearchableArray() deliberately narrow. Index only what you filter or display in results. A bloated searchable array slows imports and, on hosted engines, inflates cost. A common pattern is to index a flattened projection plus a url field so the results view needs no extra queries.

Use Scout::fake() in feature tests. You get assertion helpers without standing up an engine:

Scout::fake();
Product::search('widget')->get();
Scout::assertSearchCalled('widget');

Indexing workflow. For anything beyond a toy dataset, run indexing through the queue:

SCOUT_QUEUE=true
php artisan scout:import "App\Models\Product"

Import after deploy, not before — importing against a schema that the new code hasn't shipped yet is a reliable way to produce confusing partial results.

Integration tip: expose search through a form request with validated, whitelisted filter keys. Search parameters are user input, and passing arbitrary filter keys straight through to the engine is the easiest way to let someone filter on an unindexed or sensitive column.

Gotchas and Tips

The model() removal is a hard break, not a deprecation. There is no shim and no trigger_error — calls to the removed method will fail at runtime, potentially only when a specific code path executes. Before upgrading, grep the whole codebase (including queued jobs, console commands, and Blade views) for the old method name. Treat this as a major-version bump in your composer.json constraint and schedule it deliberately.

Scout indexing is eventually consistent. Writes hit your database immediately but the search index lags — and with SCOUT_QUEUE=true, it lags until a worker picks the job up. Tests that assert on search results right after a create() will be flaky. Use Scout::fake() in tests and ->searchable() / synchronous indexing in local debugging, never in production request paths.

A stopped queue worker looks exactly like a search bug. If results mysteriously stop updating, check the queue before you check the engine. This is the single most common "the package is broken" false alarm.

Pagination, not get(), on anything user-facing. Result sets from hosted engines are capped (Algolia defaults to 1000 hits) and get() will silently truncate long before that cap in memory terms.

Soft deletes need explicit handling. Scout respects SoftDeletes for removing documents only if the model is properly configured; a "deleted" record lingering in results is usually an index-side problem, fixed by re-running scout:import, not by changing the query.

Eager loading still matters. Scout returns model instances hydrated from your database. The N+1 you thought search would solve comes right back the moment your results view touches a relation — add ->with(['category']) to the search builder.

Extension points: the package's engine resolution is bound in its service provider, so a custom Scout engine (or a decorator that logs queries) can be swapped in via container binding without forking. That is the cleanest place to add cross-cutting behavior like search-term logging or result post-filtering.

Version pin cautiously. At 0.x, minor versions have broken things before — v0.3.0 itself is proof. Pin to a patch range, read the changelog on every bump, and keep a smoke test that exercises one real search against a real driver in CI so a surprise break surfaces in the pipeline rather than in production.

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.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo