1

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); 
Community
  • 1
  • 1
Pipe
  • 2,379
  • 2
  • 19
  • 33
  • Possible duplicate of [Laravel Observers - Any way to pass additional arguments?](https://stackoverflow.com/questions/43923958/laravel-observers-any-way-to-pass-additional-arguments) – Kenny Horna Jun 07 '19 at 20:42
  • I don't understand the solution. Where do I put that code? In model, in Event file or in AppServiceProvider? I tried addint that to AppServiceProvider and got an error "Cannot instantiate interface Illuminate\Contracts\Events\Dispatcher" – Altin Apr 20 '21 at 16:43
  • I used `use Illuminate\Events\Dispatcher`. Worked for me. – Pipe Apr 20 '21 at 19:04

1 Answers1

3

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.

mrhn
  • 17,961
  • 4
  • 27
  • 46
  • It seems the `bind` method is part of the `illuminate/container`, used in laravel but im not using it... any other possible solution? – Pipe Jun 07 '19 at 22:51
  • Here is an example of someone utilising the app outside of laravel, i think you are using it, because it needs it for the container which events uses. https://github.com/mattstauffer/Torch/blob/e2cc707b4c73eb1e499558333fb6dc0c2af00cbd/other-components/html/index.php#L23 – mrhn Jun 07 '19 at 22:55
  • I updated the answers with how i think you can solve it – mrhn Jun 08 '19 at 07:16
  • Thank you! It worked :) (I have updated my question with full solution) – Pipe Jun 10 '19 at 21:00