Download the PHP package ascend/laravel-column-watcher without Composer

On this page you can find all versions of the php package ascend/laravel-column-watcher. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.

FAQ

After the download, you have to make one include require_once('vendor/autoload.php');. After that you have to import the classes with use statements.

Example:
If you use only one package a project is not needed. But if you use more then one package, without a project it is not possible to import the classes with use statements.

In general, it is recommended to use always a project to download your libraries. In an application normally there is more than one library needed.
Some PHP packages are not free to download and because of that hosted in private repositories. In this case some credentials are needed to access such packages. Please use the auth.json textarea to insert credentials, if a package is coming from a private repository. You can look here for more information.

  • Some hosting areas are not accessible by a terminal or SSH. Then it is not possible to use Composer.
  • To use Composer is sometimes complicated. Especially for beginners.
  • Composer needs much resources. Sometimes they are not available on a simple webspace.
  • If you are using private repositories you don't need to share your credentials. You can set up everything on our site and then you provide a simple download link to your team member.
  • Simplify your Composer build process. Use our own command line tool to download the vendor folder as binary. This makes your build process faster and you don't need to expose your credentials for private repositories.
Please rate this library. Is it a good library?

Informations about the package laravel-column-watcher

Laravel Column Watcher

Latest Version on Packagist

A Laravel package that provides attribute-based column watching for Eloquent models. React to specific column changes without the boilerplate of full model observers.

Table of Contents

The Problem

Laravel's observer pattern is powerful but fundamentally flawed for column-level reactions. What starts as a simple "notify when status changes" requirement quickly becomes a maintenance burden.

The "God Observer" Anti-Pattern

Observers tend to grow into monolithic classes that handle everything:

This violates the Single Responsibility Principle. Your observer becomes a dumping ground for unrelated concerns, making it difficult to understand, maintain, and test.

Observers Can't Be Mocked

Testing observer behaviour is notoriously difficult:

There's no clean way to verify that your observer logic was triggered without testing the downstream effects. This leads to either undertested code or slow, integration-heavy test suites.

Observers Can't Be Queued

When your observer needs to call a slow external API, you're stuck dispatching a job from within the observer:

This means creating two classes for every async operation: the observer to detect the change, and the job to handle it. The observer becomes nothing more than a dispatcher.

The Hidden Coupling Problem

Observers create invisible dependencies:

New developers (and future you) must hunt through service providers and observer classes to understand what happens when a model changes.

Summary of Observer Pain Points

The Solution

Column Watcher represents a paradigm shift in how you react to model changes. Instead of centralised observers, you get:

Each handler is a focused, testable, optionally-queueable class.

Fully mockable and fakeable:

Queueable with a single interface:

No observer class. No service provider registration. No manual change detection. The handler only runs when status actually changes.

Installation

The package auto-discovers its service provider. No manual registration needed.

Usage

1. Create a Handler

Generate a handler using the artisan command:

This creates app/Watchers/HandleStatusChange.php:

All handlers extend ColumnWatcher, which includes built-in testing utilities like HandleStatusChange::fake() and HandleStatusChange::assertTriggered(). See Testing for details.

2. Register the Watcher

Option A: Using Attributes (Recommended)

Add the #[Watch] attribute to your model class:

Option B: Programmatic Registration

Register watchers in a service provider:

3. Watch Multiple Columns

A single handler can watch multiple columns:

When any of these columns change, the handler receives a ColumnChange object that tells you which specific column triggered it:

4. Multiple Watchers

You can attach multiple watchers to the same model:

5. Timing: Before vs After Save

By default, handlers run after the model is saved (Timing::SAVED). You can run them before save using the timing parameter:

When to use each:

Timing Event Use Case
Timing::SAVED (default) After database write Notifications, logging, external API calls
Timing::SAVING Before database write Validation, data transformation, blocking invalid changes

6. Queueable Handlers

For handlers that perform slow operations (sending emails, calling APIs), add implements ShouldQueue to run them in the background:

You can optionally configure queue behaviour using standard Laravel properties:

Note: Queueable handlers only work with timing: Timing::SAVED (the default). Using timing: Timing::SAVING with a queueable handler would defeat the purpose since the save hasn't happened yet.

The ColumnChange Object

Handlers receive a ColumnChange object with these properties and methods:

Real-World Examples

Send Notification on Status Change

Audit Trail for Sensitive Fields

Validate State Transitions

Sync to External Service (Queued)

Important: Don't use constructor dependency injection in queueable handlers. Laravel serializes the job for the queue and cannot restore injected dependencies. Use app() or resolve() inside the execute() method instead.

Comparison with Observers

Feature Observers Column Watcher
Testing Cannot be mocked or faked Built-in fake(), assertTriggered()
Queueing Must dispatch separate jobs implements ShouldQueue on handler
Code organisation Tends toward "God observer" One handler per concern
Declaration Separate class + service provider Attribute on model
Visibility Hidden in observer class Visible on model
Granularity All model events Specific columns only
Change detection Manual (wasChanged()) Automatic
Multiple handlers One observer per model Multiple #[Watch] attributes
Timing control Different methods Single timing parameter

Before: Observer Approach

After: Column Watcher Approach

Disabling Watchers

You can temporarily disable watchers globally (useful for migrations, seeding, or testing):

Or use the config:

Events

The package dispatches events during watcher execution, allowing you to hook into the lifecycle for logging, metrics, or error tracking.

Available Events

Event Dispatched When
WatcherStarted Before the watcher's execute() method runs
WatcherSucceeded After execute() completes successfully
WatcherFailed When execute() throws an exception

All events contain a reference to the watcher instance, giving you access to the model, column, and values:

Events Fire for Both Sync and Queued Handlers

Events are dispatched inside the watcher's handle() method, which means they fire:

This gives you consistent behaviour regardless of how the watcher is executed.

Laravel Octane Compatibility

This package is fully compatible with Laravel Octane. Internal state is stored using Laravel's scoped container bindings, which are automatically reset between requests.

You don't need to do anything special - it just works. The package avoids static properties that could cause state to bleed between requests in Octane's long-running worker processes.

Configuration

Publish the config file:

Artisan Commands

watcher:list

List all registered column watchers in your application:

Output (styled similar to Laravel's event:list):

The command scans model directories configured in model_paths and includes programmatically registered watchers. Queueable handlers are marked with [queued].

make:watcher

Generate a new watcher handler class:

This creates a file in app/Watchers/ (configurable via namespace in config):

With --queued, the class also implements ShouldQueue:

Testing

Faking Handlers

All handlers that extend ColumnWatcher can be faked for testing, similar to Laravel's notification and event faking:

Available Assertions

Method Description
Handler::fake() Start faking the handler
Handler::stopFaking() Stop faking and clear recorded changes
Handler::assertTriggered() Assert handler was triggered at least once
Handler::assertTriggered($callback) Assert with custom condition
Handler::assertNotTriggered() Assert handler was never triggered
Handler::assertTriggeredTimes($n) Assert handler was triggered exactly N times
Handler::assertTriggeredForColumn($col) Assert handler was triggered for specific column
Handler::assertTriggeredWithValues($old, $new) Assert handler was triggered with specific values
Handler::recorded() Get all recorded ColumnChange objects

Accessing Recorded Changes

When faking, you can access all recorded changes:

Disabling All Watchers

To disable all watchers globally (useful for migrations, seeding, or bulk operations):

Testing Without Faking

You can also test handler side-effects directly:

Cleaning Up Fake State

When mixing tests that use fake() with tests that need watchers to actually execute, call stopFaking() in your tearDown() to prevent state pollution between tests:

Without this, a test that calls fake() will leave the watcher in fake mode, causing subsequent tests that expect the watcher to run to fail silently.

Testing Queued Handlers with DatabaseTransactions

When using Laravel's DatabaseTransactions trait, queued handlers won't execute because they wait for DB::afterCommit(), which never fires (transactions are rolled back, not committed).

Call withoutAfterCommit() in your setUp() to bypass this:

Note: withoutAfterCommit() is safe to call unconditionally - it only affects behaviour when there's an active transaction.

Edge Cases & Limitations

Model Creation

Watchers fire on both create() and update() operations. When a model is created, the "old value" will be null for all columns:

Infinite Loop Protection

The package automatically prevents infinite loops when a watcher saves the same model:

However, be careful with watchers that modify different columns watched by other handlers.

Transaction Safety

Queued handlers are dispatched after the database transaction commits. If a transaction rolls back, the queued job will not be dispatched:

Deleted Models and Queued Handlers

If a model is deleted before a queued handler processes, Laravel will throw a ModelNotFoundException. Handle this in your handler if needed:

Queueable Handlers Must Use Timing::SAVED

You cannot use queueable handlers with Timing::SAVING. This is enforced at registration time:

Requirements

License

MIT


All versions of laravel-column-watcher with dependencies

PHP Build Version
Package Version
Requires php Version ^8.2
illuminate/database Version ^11.0|^12.0|^13.0
illuminate/support Version ^11.0|^12.0|^13.0
Composer command for our command line client (download client) This client runs in each environment. You don't need a specific PHP version etc. The first 20 API calls are free. Standard composer command

The package ascend/laravel-column-watcher contains the following files

Loading the files please wait ...