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 Dynamic Observer Laravel Package

avinash403/laravel-dynamic-observer

Laravel package for attaching Eloquent model observers dynamically at runtime, letting you register create, update, and delete hooks without hardcoding them in the model class. Useful for modular or conditional event handling.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the release and confirm you're on v1.0.4:

composer require <vendor>/<package>:^1.0.4

There is nothing to publish or migrate for this release — the change is additive to an existing trait, so no config or schema changes are required.

Where to look first: open the trait itself (typically src/Concerns/*.php or src/Traits/*.php) and read it end to end. It is small, and it is the authoritative list of lifecycle hooks the package fires. The README was rewritten in this release and is now descriptive enough to use as the primary reference, but the trait is what actually runs — trust it over the docs when they disagree.

First use case: add a hook method to a model that uses the trait, and let the package call it automatically after the model is retrieved:

use Vendor\Package\Concerns\Retrievable;

class Invoice extends Model
{
    use Retrievable;

    public function afterRetreive(): void
    {
        $this->status_label = $this->status->label();
    }
}

No registration, no interface, no service provider wiring. If the method exists, it is called; if it doesn't, nothing happens. That zero-config opt-in is the whole point of the feature — start with one model, confirm it fires, then roll it out.

Implementation Patterns

Treat hooks as opt-in per model. The trait checks for the method's existence before calling it, so you can adopt it incrementally across a large codebase. Add afterRetreive() only to models that genuinely need post-retrieval work, rather than to a base model that everything inherits from — otherwise you pay the method_exists() check on every model in the app for no benefit.

Keep the hook cheap and non-mutating. The natural fit is deriving read-only attributes that depend on other loaded relations or casts:

public function afterRetreive(): void
{
    $this->display_name = "{$this->customer->name} — {$this->reference}";
}

If the work is expensive or touches the database, do it in an accessor with memoization or in the query layer instead. Retrieval hooks run in the hot path of every fetch.

Use it for cross-cutting, per-instance concerns. Good candidates: decrypting a field into a transient property, stamping a tenant or request context onto the model for downstream policy checks, or normalizing legacy data shapes that predate a migration. These are things you'd otherwise scatter across controllers or repeat in every observer.

Pair it with, don't replace, model observers. Observers fire on Eloquent events (retrieved, saving, etc.) and are the idiomatic Laravel tool. Reach for this hook when you want the behaviour scoped to models using the trait and want it to survive Eloquent event deregistration. Don't duplicate the same logic in both places — pick one per concern and be consistent, or you'll get double execution that's hard to trace.

Make it testable. Because the hook is just a public method, you can assert on it directly, but the more valuable test is an integration one that actually retrieves a model and asserts the derived state:

$invoice = Invoice::factory()->create();
$this->assertSame('...', Invoice::find($invoice->id)->display_name);

Migrate to it deliberately. If you currently do post-retrieval work in a repository or a retrieved observer, moving it into afterRetreive() is low-risk and usually a net simplification, but do it model by model and keep the observer until the hook version is covered by a test.

Gotchas and Tips

The method name is misspelled — and you must match the misspelling exactly. The hook is afterRetreive (missing the second i), not afterRetrieve. If you write the correctly spelled name on your model, it will never be called and nothing will warn you. Copy the name from the trait source, not from memory. This is the single most likely source of "my hook doesn't run" bug reports, and it will persist until a future release renames it — at which point your working code breaks. Pin your constraint and watch the changelog.

Failures are silent by design. The existence check means there is no error path for a typo, a wrong visibility modifier, or a signature mismatch. When a hook appears not to fire, check in this order: exact spelling, public visibility, the model actually uses the trait, and the model was actually retrieved (a freshly create()d instance has not been through the retrieve path — create() returns the instance you built, not a fetched one). Model::find() on a just-created record or refresh() will exercise it; save() alone typically won't.

It fires once per model instance, so cost multiplies with collections. Invoice::all() on 5,000 rows calls your hook 5,000 times. Anything you do inside runs in a loop: relation access will trigger an N+1 unless you eager load, and string building or formatting adds up. Profile before putting non-trivial logic here, and always eager load whatever the hook touches.

Don't persist inside the hook. Calling save(), update(), or push() from afterRetreive() risks recursion and unexpected write amplification — the hook runs on models fetched inside your own save paths and inside queued jobs. If you need to record something at retrieval time, write to a log, a cache, or a separate table via a query builder call, not through the model itself.

Return values are ignored. This is a notification hook, not a transformer — you can't return a modified model and have the package substitute it. Mutate $this properties or attributes directly, and prefer transient (non-persisted) properties for derived values so a stray save() elsewhere doesn't write them to the database.

Watch serialization boundaries. Derived properties set in the hook exist only on the in-memory instance. They are lost on queue serialization/deserialization unless included in $appends/toArray() handling, so don't rely on them in queued jobs or in code that reconstitutes models from cache. If the package or your app caches model instances, be aware the hook may or may not re-run on a cache hit depending on how the instance is revived — verify this explicitly if you depend on it.

Upgrade risk from earlier versions is low. This release only adds a method check to the trait and documentation changes. Existing behaviour is unchanged unless you happen to already have an unrelated afterRetreive() method on a model using the trait — in which case it will now be called on every retrieval. Grep the codebase for that name before upgrading; a name collision is the only realistic breaking scenario here.

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.
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk