Jump to content

Events and listeners in Processwire


Ivan Gretsky
 Share

Recommended Posts

Good day!

Is there an easy way to add events that some listeners can subscribe to in ProcessWire? I am thinking about adding these events in the template context, so I can add some listeners later. Preferably I'd like to be able to pass some variables to the listener. I am guessing it could be done calling some hookable method of a specially-made class. But please share anything more specific on that if you got some experience, colleagues.

Link to comment
Share on other sites

A while ago I added an event listener / event queue feature for Wireframe objects: https://github.com/wireframe-framework/Wireframe/blob/master/lib/EventListenerTrait.php. The rough idea is that the object itself keeps track of events and listeners, and if an event is emitted ($this->emit('event-name', $args)), related listeners will be notified. This concept was loosely based on the Vue.js events system.

This might be overtly complex for your needs, though. Something as simple as $this->runHooks('event-name', $args) would likely work just fine (though it depends on your use case) ?

  • Like 3
Link to comment
Share on other sites

26 minutes ago, kongondo said:

Just to add to the discussion....how Laravel does it:

https://laravel.com/docs/7.x/events

This is where I started))

 

36 minutes ago, LostKobrakai said:

Generally I think event handling can quite easily happen outside of processwire with something like https://event.thephpleague.com/2.0/.

Thanks, I'll look into it. But I always try to first use a native solution if it exists) And PW always tried to be all-in-one thing. I am actually thinking about building a module on this feature, so do not want to have an external dependency.

 

43 minutes ago, teppo said:

A while ago I added an event listener / event queue feature for Wireframe objects: https://github.com/wireframe-framework/Wireframe/blob/master/lib/EventListenerTrait.php. The rough idea is that the object itself keeps track of events and listeners, and if an event is emitted ($this->emit('event-name', $args)), related listeners will be notified. This concept was loosely based on the Vue.js events system.

This might be overtly complex for your needs, though. Something as simple as $this->runHooks('event-name', $args) would likely work just fine (though it depends on your use case) ?

The 1st part I didn't understand) But the second looks promising. Could you share an example of this in a template file context?

  • Like 1
Link to comment
Share on other sites

On 8/9/2020 at 3:37 PM, Ivan Gretsky said:

The 1st part I didn't understand) But the second looks promising. Could you share an example of this in a template file context?

Do you mean the part about "$this->runHooks('event-name', $args)"? ?

If so, what I meant is that you could register your "listener" by hooking into some non-existing method in the TemplateFile object (or class), and then "emit an event" by running hooks:

// somewhere early; prepend file or something:
$this->addHook('event-name', function(HookEvent $event) {
    echo "<!-- I'm " . $event->arguments['what'] . " -->";
});

// alternatively you could add the hook in module or init/ready.php:
wire()->addHook('TemplateFile::event-name', function(HookEvent $event) {
    echo "<!-- I'm still " . $event->arguments['what'] . " ->";
});

// then "emit an event" in the template file:
$this->runHooks('event-name', ['what' => 'listening']);

It's not quite the same thing, there's no queue, syntax is  a bit crude... but as I said before, this might be enough, depending on your actual use case ?

  • Like 4
Link to comment
Share on other sites

@teppo, a bit off-topic but I'm curious about the use of runHooks() because I haven't seen this used before. If you are adding a custom hook method "myEvent", what's the reason to do...

$this->runHooks('myEvent', ['what' => 'listening']);

...instead of...

$this->myEvent('listening');

 

  • Like 1
Link to comment
Share on other sites

@Robin S, that works (in some cases) as well, but there are two reasons why I mentioned runHooks:

  • Direct method call will cause an exception if myEvent hasn't been added as a hook method, runHooks won't. In this sort of scenario (events and listeners) the one emitting the event can't reliably know that someone is indeed listening, so this makes more sense.
  • Direct method calls require that the name be a valid method name, runHooks doesn't. Notice how I used 'event-name' in my example? ?

First one is really the key reason, second one is just a little quirk that one might find useful, i.e. it's easier to make sure that your event name can't accidentally clash with a real method.

Note: runHooks is tagged with #pw-internal. I've used this before in my code because I really needed it, but it's officially not a part of the public API, and thus in case Ryan decides to alter the implementation at some point, there's a chance that code relying on this feature may need revisiting. Just saying. Using only "official API methods" one would have to either check hooks with getHooks before calling the method (directly or via __call()), or just call it and handle possible exceptions with try ... catch.

  • Like 5
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...