1

Is it possible to register multiple EventHandlers?

I mean something like this:

    Event::on(
        Entry::class,
        Entry::EVENT_AFTER_SAVE,[
           NotifyWhenCookPostedArticle::handle,
           RunSomethingElse::handle,
           DeSomethingDifferent::handle
        ]

I tried it and got a PHP Warning – yii\base\ErrorException call_user_func() expects parameter 1 to be a valid callback, second array member is not a valid method

Is there a notation or helper to get this to work?

Thanks in advance . Michael

2

I don't think that syntax is possible, and in any case it could get a bit confusing. Why not simply use a single anonymous function and then call your individual handlers inside that e.g.

Event::on(
    Entry::class,
    Entry::EVENT_AFTER_SAVE, function(Event $event) {
        $this->NotifyWhenCookPostedArticle();
        $this->RunSomethingElse();
        $this->DoSomethingDifferent();
    }
);

public function NotifyWhenCookPostedArticle() {
    return 'woop';
}

(Depending on how separate those things are and/or how large and complex you expect the site to be/become, you would typically abstract them further into your Services layer for reusability and encapsulation).

1
  • Yes you are totally right. Thank you. – Slowwie Jan 25 at 15:44
1

I wrote a convient solution - so you can do things like that with invokable Classes:

In AppModule.php:

Event::on(
        Entry::class,
        Entry::EVENT_AFTER_SAVE,
        new OnEntryAfterSave()
    );

In modules\appmodule\Listeners\OnEntryAfterSave.php

class OnEntryAfterSave
{
    use Invokable, HasActions;

    protected function actions(): array
    {
        return [
            NotifyWhenCookPostedArticle::class,
            RunSomethingElse::class
        ];
    }

}

For this you have to create this two traits:

trait Invokable
{
    public function __invoke($args)
    {
        foreach (get_class_methods($this) as $method) {
            if (StringHelper::startsWith($method, 'invoke')) {
                $this->$method($args);
            }
        }
    }
}

This was just the setup for using as many invoke functions as you want and extend the class more and more. (just for future thinking - to keep it clean and short)

Then the HasActions trait actually listens for actions to call:

trait HasActions
{
    public function invokeActions(ModelEvent $event)
    {
        if (method_exists($this, 'actions')) {
            foreach ($this->actions() as $action) {
                (new $action)($event);
            }
        }
    }
}

With this setup you can just create a listener class for each CraftEvent to pass. This class only holds an array of Action Classes to call.

I like it. It's super clean and reuseable.

You can put it into an Abstract Class to extend from. So you end up with something like this:

class OnEntryAfterSave extends BaseListener
{

    protected function actions(): array
    {
        return [
            NotifyWhenCookPostedArticle::class,
            RunSomethingElse::class
        ];
    }

} 

Super slick. ;)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.