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

alexstewartja/laravel-attribute-observer

Laravel Attribute Observer lets you react to changes on specific Eloquent model attributes. Define observers for individual fields instead of the whole model, keeping update logic clean, focused, and easy to register in your service provider.

View on GitHub
Deep Wiki
Context7

Getting Started

  • Install with Composer: composer require alexstewartja/laravel-attribute-observer. The package is auto-discovered; there is usually no service provider to register manually.
  • As of 1.8.0, the package supports Laravel 13. There are no breaking changes called out in the release notes, so existing 1.7.x usage should carry forward. Confirm your application's PHP and illuminate/* constraints allow Laravel 13 before upgrading.
  • First place to look is the README section covering attribute observer registration and the package's base observer/contract class. Then inspect the package tests for the exact lifecycle method names supported by your installed version.
  • The first practical use case is attribute-scoped side effects: send an email verification only when email changes, regenerate a slug only when title changes, or invalidate a cache only when status changes — instead of writing if ($model->wasChanged('email')) inside a broad updated observer.

Minimal shape:

use Alexstewartja\AttributeObserver\Concerns\HasAttributeObservers;

class User extends Model
{
    use HasAttributeObservers;

    protected array $attributeObservers = [
        'email' => \App\Observers\EmailAttributeObserver::class,
    ];
}
namespace App\Observers;

use Alexstewartja\AttributeObserver\AttributeObserver;

class EmailAttributeObserver extends AttributeObserver
{
    public function updated($model, string $attribute, mixed $old, mixed $new): void
    {
        // Only runs when the observed attribute changes.
        $model->sendEmailVerificationNotification();
    }
}

Verify the exact observer method signatures and registration property against the installed version's README; the package's public API is small, so this should take only a few minutes.

Implementation Patterns

  • Targeted domain reactions. Map one observer per meaningful attribute or per small group of related attributes. This keeps observers narrow and avoids the classic “god observer” with a long chain of wasChanged() checks.
  • Audit and history. Use attribute observers to write audit records only for sensitive fields (role, status, email, price). Capture old/new values directly from the observer arguments where available, or fall back to getOriginal() / getChanges().
  • Cache invalidation. Invalidate a view or API cache when a specific field changes, rather than clearing caches on every model save. This is a strong day-to-day win for read-heavy applications.
  • External system sync. Dispatch a queued job from the attribute observer when a synced field changes. Use ->afterCommit() on the job or DB::afterCommit() so external systems never see uncommitted state.
  • Compose with native Eloquent observers. Keep native observers for cross-cutting model lifecycle work and use attribute observers for field-specific behavior. Avoid duplicating the same side effect in both places.
  • Conditional logic. If the package exposes pre-save hooks, use them for validation-like checks; use post-save hooks for notifications and integrations. Prefer explicit checks such as $model->isDirty($attribute) before save and $model->wasChanged($attribute) after save.
  • Testing. Use Event::fake(), Queue::fake(), and Notification::fake() around model updates, then assert the expected job/notification was dispatched only when the observed attribute actually changed. Add negative tests where another attribute changes and the observer must not fire.
  • Modular applications. Register attribute observers in domain modules or service providers if the package supports runtime registration. This keeps attribute-to-observer mappings close to the domain code rather than in one large model.

Gotchas and Tips

  • Create vs. update semantics. Decide whether your observer should react on creation as well as updates. Many “attribute changed” use cases should explicitly ignore the initial create event unless the attribute is present and meaningful at creation time.
  • Bypassed events. saveQuietly(), updateQuietly(), withoutEvents(), and bulk query updates (Model::where(...)->update(...)) will not fire model observers. If a critical integration must run for bulk changes, trigger it explicitly or use a database-level mechanism.
  • Infinite loops. Updating the same model inside an attribute observer can re-trigger observers. Guard with withoutEvents(), a static flag, or by changing a different attribute and checking isDirty() carefully.
  • Original vs. current values. Before save, use isDirty() / getDirty(); after save, use wasChanged() / getChanges(). Casts matter: an attribute may appear unchanged at the raw level but differ after casting, or vice versa.
  • Transactions and side effects. Observers run inside the save call. Dispatching emails or HTTP calls synchronously can leave users with notifications for rolled-back transactions. Prefer queued jobs with afterCommit.
  • Performance. Every registered attribute observer adds work to the save lifecycle. Avoid queries, API calls, or heavy serialization in synchronous observer methods; push that work to queues.
  • Mass assignment and model events. Ensure the attribute is actually being persisted and that the model's events are enabled. Packages or application code that disable events will silently skip attribute observers.
  • Laravel 13 upgrade. 1.8.0 is a compatibility release. Run your test suite against Laravel 13 in CI, verify PHP version requirements, and check that any other Laravel packages in the same app also support Laravel 13. There is no migration path required from 1.7.8 based on the release notes.
  • Debugging. If an observer is not firing, check: the trait is present, the attribute key matches the database column name, the model actually changed that attribute, events are enabled, and the save was not a “quiet” operation. Temporarily log inside the observer to confirm lifecycle entry.
  • Extension points. The package is intentionally small. If you need shared behavior across observers, create your own base observer class or trait, and keep package-specific observer classes thin. Avoid forking the package for small conveniences; wrap it instead.
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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
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