laraveleloquentilluminate-container

Is there a way to send params to an observer?


Is there a way to send parameters to an Observer in Eloquent ORM?

Based on laravel's documentation:

User::observe(UserObserver::class);

observe method receive a class, not an instance of an object. So I cant do something like:

$observer = new MyComplexUserObserver($serviceA, $serviceB)
User::observe($observer);

So, in my code I can do something like:

class MyComplexUserObserver
{
    private $serviceA;
    private $serviceB;

    public function __constructor($serviceA, $serviceB){
        $this->serviceA = $serviceA;
        $this->serviceB = $serviceB;
    }

    public function created(User $user)
    {
        //Use parameters and services here, for example:
        $this->serviceA->sendEmail($user);
    }
}

Is there a way to pass parameters or services to a model observer?

Im not using laravel directly, but i'm using eloquent (illuminate/database and illuminate/events)

Im not trying to send additional parameters to an explicit event like in: Laravel Observers - Any way to pass additional arguments?, i'm trying to construct an observer with additional parameters.


FULL SOLUTION:

Thank you to @martin-henriksen.

use Illuminate\Container\Container as IlluminateContainer;

$illuminateContainer = new IlluminateContainer();
$illuminateContainer->bind(UserObserver::class, function () use ($container) {
    //$container is my project container
    return new UserObserver($container->serviceA, $container->serviceB);
});
$dispatcher = new Dispatcher($illuminateContainer);

Model::setEventDispatcher($dispatcher); //Set eventDispatcher for all models (All models extends this base model)
User::observe(UserObserver::class); 

Solution

  • In the Illuminate events there is the line, this indicates on event subscription it utilities the container. This mean we can use this to our advantage, i'm not super familiar with non Laravel bootstrapped applications. But where ever your app is defined, you will bind your class to your own class.

    $container = new Container();
    
    $container->bind(MyComplexUserObserver::class, function ($app) {
        return new MyComplexUserObserver($serviceA, $serviceB, $theAnswerToLife);
    });
    
    $dispatcher = new Dispatcher($container);
    

    This will result in, next time your application resolves your class, it will use this version of it and therefor you can setup your class as you intend.

    Edit: an example how you can utilize the Laravel container, to utilize the bind functionality.