Skip to content

Model Observer ​

The Model Observer component registers classes that handle Hyperf model events. An observer can be bound from the observer class or from the model class.

Installation ​

shell
composer require friendsofhyperf/model-observer

The component is registered automatically through its ConfigProvider. It requires hyperf/database when used with Hyperf models:

shell
composer require hyperf/database

Generate an Observer ​

Pass a model class to gen:observer to generate an observer in the default App\Observer namespace:

shell
php bin/hyperf.php gen:observer UserObserver --model="App\\Model\\User"

The command also supports:

shell
php bin/hyperf.php gen:observer UserObserver \
  --model="App\\Model\\User" \
  --namespace="App\\ModelObserver" \
  --force
  • --model, -M: model class used in the generated attribute and method signatures.
  • --namespace, -N: namespace of the generated observer.
  • --force, -f: overwrite an existing observer file.

You can change the default namespace or stub in config/autoload/devtool.php:

php
return [
    'generator' => [
        'observer' => [
            'namespace' => 'App\\ModelObserver',
            'stub' => BASE_PATH . '/stubs/observer.stub',
        ],
    ],
];

Bind from an Observer ​

Use #[Observer] on an observer class. The model argument accepts one model class or an array of model classes:

php
namespace App\Observer;

use App\Model\User;
use FriendsOfHyperf\ModelObserver\Annotation\Observer;

#[Observer(model: User::class)]
class UserObserver
{
    public function creating(User $model): void
    {
        // Runs when a user is being created.
    }

    public function created(User $model): void
    {
        // Runs after a user has been created.
    }
}
php
namespace App\Observer;

use App\Model\Post;
use App\Model\User;
use FriendsOfHyperf\ModelObserver\Annotation\Observer;
use Hyperf\Database\Model\Model;

#[Observer(model: [User::class, Post::class])]
class SearchIndexObserver
{
    public function saved(Model $model): void
    {
        // Update the search index.
    }
}

#[Observer] is repeatable. You can use priority to run higher-priority observers first:

php
#[Observer(model: User::class, priority: 100)]
#[Observer(model: Post::class, priority: 50)]
class AuditObserver
{
    // ...
}

Bind from a Model ​

Use #[ObservedBy] to declare observers on a model. Its classes argument accepts one observer class or an array of observer classes, and the attribute is repeatable:

php
namespace App\Model;

use App\Observer\AuditObserver;
use App\Observer\UserObserver;
use FriendsOfHyperf\ModelObserver\Annotation\ObservedBy;
use Hyperf\Database\Model\Model;

#[ObservedBy([UserObserver::class, AuditObserver::class], priority: 100)]
class User extends Model
{
    // ...
}

Bindings from #[Observer] and #[ObservedBy] are combined. Duplicate observer classes for the same model are called only once.

Run an Observer in a Coroutine ​

Implement ShouldCoroutine when all callable event methods on an observer should run in newly created coroutines:

php
namespace App\Observer;

use App\Model\User;
use FriendsOfHyperf\ModelObserver\Annotation\Observer;
use FriendsOfHyperf\ModelObserver\Contract\ShouldCoroutine;

#[Observer(model: User::class)]
class UserObserver implements ShouldCoroutine
{
    public function created(User $model): void
    {
        // Runs in a newly created coroutine.
    }
}

Coroutine observers run asynchronously. Do not rely on them completing before the model operation returns.

Supported Events ​

Define only the methods needed by an observer. Each callable method receives the model instance:

  • booting
  • booted
  • retrieved
  • creating
  • created
  • updating
  • updated
  • saving
  • saved
  • restoring
  • restored
  • deleting
  • deleted
  • forceDeleted

The component dispatches these methods through Hyperf events. Return values from observer methods are ignored and cannot cancel a model operation.