Code Monkey home page Code Monkey logo

event's Introduction

event's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

event's Issues

Some help needed with understanding

Hey,

I love the idea of the package but the documentation isn't very clear and I have spotted a few mistakes. Is the repo on Github?

Anyway I am having some difficulty understanding how to set the listeners up correctly, so far I have this:

$emitter = new Emitter();

$emitter->addListener('NewIssueEvent', function ($event) {
    echo $event->getName(); 
});

$emitter->emit(new NewIssueEvent);

Now what is the correct way to call my listener? is it as simple as newing one up? new NewIssueEventListener(); But this doesn't seem correct as then what is the point in the handle function?

I'd love a quick example set up of class based events and listeners. Thanks ๐Ÿ‘

BufferedEmitter as service

Hi,

I am using BufferedEmitter in a middleware for the tactician CommandBus. Therefor I've registered BufferedEmitter as service and injected it in an EmitBufferedEventsMiddleware.

This lead to looping problems, when an event handler invoked another Command, because emitBufferedEvents did not remove the events from the buffer.

Using a copied version of BufferedEmitter, I slightly changed emitBufferedEvents() by utilizing array_shift to remove the events from the buffer.

    /**
     * Emit the buffered events.
     *
     * @return array
     */
    public function emitBufferedEvents()
    {
        $result = [];
        while($event = array_shift($this->bufferedEvents)) {
            $result[] = parent::emit($event);
        }

        return $result;
    }

This solved my problem using BufferedEmitter as a service.

[QUESTION / PROPOSAL] Is there a way to lazy load listeners?

I hate the idea of having "new's" anywhere except my DiC.
So something like
$emitter->addListener('some event', 'Some Class Name which Implements the Listener Interface');
$emitter->setListenerResolver(new ClassThatImplementsAListenerResolverInterface());

class ClassThatImplementsAListenerResolverInterface {

public function __construct('my DiC goes here') ...

public function getListener($className)
{
return $this->MyDiC->get($className);
}

It's just some meta code but you get the ideea. This way you don't do any instantiations unless the event listener MUST actually be called. Otherwise you work just with strings.

What do you think ? I don't see a way to do this right now (w/o customizing stuff quite a bit)

EmitBatch with warnings or exceptions

I am having some issues due to this line when throwing exceptions within the listeners. It currently returns array_map(): An error occurred while invoking the map callback because the callback failed to complete, thus suppressing the original error. Would you consider switching to a foreach so that the errors can be caught and easily debugged?

Tag a new release

IMO the new interfaces and traits deserve a minor release, or at least a branch-alias version dump.

waitFor method

What about a waitFor method ?

I'm not sure about this, but I want to hear your thoughts.

I build an API which use CQRS with Events (thanks to your lib). One endpoint is used to register a device. So, i launch a command inside it like this :

$command = new Command\RegisterDevice($user->getId(), $udid, $push_token, $platform);
$bus->handle($command);

I want to set the response of this endpoint with the device registered. But I must wait the registration (eg the event "DeviceRegistered") to query it and return it to the consumer.

So, I imagine this :

// Command Register device

$event = $emitter->waitFor('DeviceRegistered'); // Wait for the event, and return it when it is fired by the emitter

$query = new Query\FindDeviceByUdid($event->getUdid());
$device = $bus->handle($query);

// And return a JSON representation of the device

What do you think ?

Split EmitterTrait

This is the second time I came across the following scenario in two weeks:

Let's say I have an object which is some sort of decorator around another object. The decorated object is either an emitter or a class implementing emitter trait. If I want to access the even emitter from the outside, I probably should use emittertrait on the decorator as well. However in this case I have to override both get and set emitter functions. Not to mention the unused emitter variable in the decorator.

So I found out the folowing:

Have a trait which has the basic implementation of the emitter interface using the getEmitter() function. The getEmitter and the setEmitter should be declared as abstract.

trait EmitterAware
{
    /* Implementation */

    abstract public function getEmitter();
    abstract public function setEmitter(EmitterInterface $emitter);
}

Have another trait which extends the previous and implement getEmitter and setEmitter. This is what EmitterTrait is now.

trait EmitterTrait
{
    use EmitterAware;

    protected $emitter;

    public function getEmitter()
    {
        return $this->emitter;
    }

    // setEmitter
}

What do you think? Is it overcomplication?

The point is that you are able to retrieve an emitter from your custom implementation and use the object itself like it would be an emitter itself. (Now it is only possible to store an emitter in a property)

Stoppable Events

The way I understand the library, if I dispatch an event "bla.fasel"' that does not exist (ie. is not listened to) it is ignored silently (at least that's what happens with a handful of my events that are not set up yet, but called). Is there any way to remove an already set up event listener so that calling it will not result in it to be handled at all? I think the PSR calls this "Stoppable Events".

I found a class StubStoppableEvent but I am not sure that is what I want to use ;) It looks like propagation of events is stopped. I want to remove an event that was subscribed to by $dispatcher->subscribeTo($eventIdentifier, $listener, $priority); by using something like $dispatcher->unsubscribeFrom($eventIdentifier, $priority);. Is this already possible?

Support for partial wildcard in listener

I was wondering if this library does support partial wildcards in event name?

I had a use case where I did the following

$emitter = new Emitter();
$this->emitter->addListener('app.action.db.*', function($event, $param) {
   // Track all events that start with 'app.action.db'
});

$emitter->emit('app.action.db.write', 1);

When I tried this in my app, the event did not get fired, only when I listed to 'app.action.db.write' specifically, it was caught.

It would be great if the package supported the ability to listen to a partial wildcard - at minimum listen to all events that start with "X" for example.

Ditch EventInterface

I like to wrap dependencies in my own interfaces and use adapters so as not to be too coupled to a library, useful if, for example, I want to change from one library to another. I could do this with this library too, except for events as they rely on implementing EventInterface, thus meaning my event classes are coupled to this library.

So I was wondering if you'd consider ditching the interfaces on events? I guess the interface is useful to ensure the presence of a getName() method but wondering if we could get around that by a method exists check, perhaps falling back to the class name?

I can PR this if you are happy to do so. Tactician took a similar approach for commands a while ago too if it helps to understand the issue I'm likely horribly trying to describe thephpleague/tactician#43.

I'd understand if you want to keep the interface, but am interested in your thoughts none the less :)

What would be proper approach to add information to an event?

How do I add individual information to an event? I recently rewrote my v2 implementation to v3 and can't seem to wrap my head around this. I have for instance a "user.logout" event that wants to send a Slack message about the specific user logging out. How do I add something on dispatch() that is handed over to the listener callback?

Emitting events with parameters

Maybe I am missing something, but I can't find a way to easily pass parameters to events.

Example:
When an order is processed, the buyer should be notified about it. Since the notifications are basically listeners, I can't pass the order to them.

Ideally I would do:
$emitter->emit('order.notify', $order)

RFC: Dispatching multiple events within a single listener

While this is a long ways off for us, I've been thinking about replacing the CakePHP Event system with this package. Most of the changes are simply nomenclature - we can just alias methods as necessary - though I am missing the ability to dispatch multiple events from a single listener.

In CakePHP, any class can be a listener. For instance, events are how we handle Model and Controller callbacks - beforeFilter, afterFilter, beforeSave, afterSave, etc. When a class says it implements an event, it has to implement the following interface:

<?php
interface EventListenerInterface extends ListenerInterface
{

/**
 * Returns a list of events this object is implementing. When the class is registered
 * in an event manager, each individual method will be associated with the respective event.
 *
 * ### Example:
 *
 * {{{
 *  public function implementedEvents() {
 *      return array(
 *          'Order.complete' => 'sendEmail',
 *          'Article.afterBuy' => 'decrementInventory',
 *          'User.onRegister' => array('callable' => 'logRegistration', 'priority' => 20)
 *      );
 *  }
 * }}}
 *
 * @return array associative array or event key names pointing to the function
 * that should be called in the object when the respective event is fired
 */
    public function implementedEvents();
}

We might implement this like so:

<?php
class UserListener implements EventListenerInterface
{
    public function implementedEvents()
    {
        return [
            'Model.User.created' => 'sendActivationEmail'
        ];
    }

    public function sendActivationEmail(Event $event)
    {
    // Do something with this event
    }
}

In the current master and stable releases of the event class, it doesn't appear to be possible to alias a listener's handle method to anything else, so we could not really implement the above.

One thing I managed to hack into a subclassed Emitter is to allow attaching a listener to specific events as decided by the implementedEvents method. When attaching a listener, I check for an implementedEvents method via method_exists. If this method is available, I store the associated callable - in this case something like [$listener, $method] - on that specific event. The method key defaults to handle in cases where the method is not available. The other change is to make invokeListeners aware of the change to how $listeners are stored, and instead of hardcoding [$listener, 'handle], we simply invoke the listener directly.

I realize this may be a major change - and I don't know how far along you are on the next release - but I think it would be a worthwhile change, even if CakePHP doesn't end up adopting this package in the future.

Is it possible to provide a working example?

Hello team

Is it possible to provide a small, working, project with f.i. one event and two/three listeners ?

A project where we just need to run composer update and run php sample.php to fire the sample...

Thanks a lot.

EventEmitter missing interface ?

I've been using in the past Evenement. And one thing I missed in your library is a EventEmitterInterface something that would "help" me or others swap the Event library. If I'm not mistaking there is no PSR yet for this but maybe adding one interface in your library or trying to find a common ground between those two libraries fort a start, could help any futur PSR ?

Multi-Event Listener

Is there a common way to make a listener handle multple domain events? (meaning different way)

I would like to write as less conditions as possible.

My initial idea: look for a method in the listener matching with the event name (sanitized of course). If a match is found, the listener can handle it. However this sounds a bit weird.

Use case: PreEvent, Event, PostEvent handled by one listener.

Namespaced events?

Is this possible?

<?php
use League\Event\Event;

$emitter->addListener('string.event.name', function (Event $event) {
    echo $event->getName(); // echo's "string.event.name"
});

$emitter->emit('string.event.*');

Additional Arguments throw exception when using AbstractListener

I followed the instructions here: http://event.thephpleague.com/2.0/events/arguments/
However, the code below throws the following error because it doesn't comply with the ListenerInterface:

Fatal error: Declaration of App\Listeners\Error::handle(League\Event\AbstractEvent $event, $param = NULL) must be compatible with League\Event\ListenerInterface::handle(League\Event\EventInterface $event) in /home/vagrant/Code/Project/app/Listeners/Error.php on line 8

<?php
namespace App\Listeners;

use League\Event\AbstractEvent;
use League\Event\AbstractListener;

final class Error extends AbstractListener {
    public function handle(AbstractEvent $event, $param = null)
    {
        ...
    }   
}

Naming convention

I may have misunderstand, but I thought the League was following the PSR naming conventions, and by that, abstract classes should be prefixed with Abstract and not suffixed. Would you consider to rename those?

Fatal error: Uncaught Error: Class 'League\Event\Emitter' not found

Anytime i run the code below by browser throws an error. But if i trace it using my IDE, by pressing ctrl and clicking on new Emitter, my IDE opens the Emitter class. So i don't understand why my browser doesn't seem to find the class.

use League\Event\Emitter;

$emitter = new Emitter;

$emitter->addListener('foo', function (Event $event) {
    echo $event->getName(); // echo's "string.event.name"
});

I installed it using composer require league/event.

Event with same priority are fired in reverse order

Consider the following code:

$emitter = new Emitter();

$emitter->addListener('foobar', function () {
   echo 'a';
}, 50);

$emitter->addListener('foobar', function () {
    echo 'b';
}, 0);

$emitter->addListener('foobar', function () {
    echo 'c';
}, 0);

$emitter->addListener('foobar', function () {
   echo  'd';
}, -50);

$emitter->emit('foobar');

Now, as C was registered after B, I would expect it to fire after B too, but currently instead of abcd I get acbd. Is this expected behaviour? Is there any way to avoid this?

How do you remove listeners?

In version 2 there were these methods to remove listeners:

$emitter->removeListener($event, $listener);
$emitter->removeAllListeners($event);

How to do it in version 3?

Here we mention the matter, but always with reference to version 2.

It seems that other similar libraries have these methods:

https://github.com/symfony/event-dispatcher/blob/6.2/EventDispatcher.php#L132
https://github.com/laminas/laminas-eventmanager/blob/3.10.x/src/EventManager.php#L202
https://github.com/laminas/laminas-eventmanager/blob/3.10.x/src/EventManager.php#L250

Thanks!

Upgrade from 2 to 3 documentation is... incomplete...

I am trying to upgrade my events integration from 2 to 3 using the documentation at https://event.thephpleague.com/3.0/upgrade-from-2-to-3/. Following are some points that came up during this:

  1. under "Callable listeners" the text looks incomplete and stops mid (start) sentence

  2. EventDispatcher - class path Event is missing in the sample:

false

- $emitter = new League\Event\Emitter();
+ $dispatcher = new League\EventDispatcher();

right

- $emitter = new League\Event\Emitter();
+ $dispatcher = new League\Event\EventDispatcher();
  1. Event::named($event) stopped existing, but is not mentioned

  2. ListenerAcceptorInterface disappeared, but is not mentioned - what's the replacement?

  3. AbstractListenerProvider::provideListeners seems to have been renamed to subscribeListeners

Double invoked events with name same as their classname

Hi,
I am trying to upgrade this package to version 3.0 and I got some weird results when trying to subscribe to event which name is the same like its classname.

Previously it was implemented in AbstractEvent this way:

public function getName()
{
    return get_class($this);
}

So if I set the name of my event to get_class($event) or Event::class it is invoked twice.
Is it a bug or feature?

Failing test case here

Question: Can the Emitter be made ContainerAware?

How about having the Emitter implement the ContainerAware interface, so we can lazily fetch listeners from the container when we need them, instead of having to wire up a bunch of listeners which may never be needed for the current request?

class ContainerAwareEmitter implements ContainerAware
{
    protected function ensureListener($listener)
    {
        if ($listener instanceof ListenerInterface) {
            return $listener;
        }

        if (is_callable($listener)) {
            return CallbackListener::fromCallable($listener);
        }

        if (is_string($listener)) {
            return LazyListener::fromAlias($this->container, $listener);
        }

        throw new InvalidArgumentException('Listeners should be be ListenerInterface, Closure or callable, or an alias. Received type: '.gettype($listener));
    }
}

class LazyListener implements ListenerInterface
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @var string
     */
    protected $alias;

    /**
     * @var ListenerInterface
     */
    protected $listener;

    /**
     * @param ContainerInterface $container
     * @param string             $alias
     */
    public function __construct(ContainerInterface $container, $alias)
    {
        $this->container = $container;
        $this->alias = $alias;
    }

    /**
     * Get the listener.
     *
     * @return ListenerInterface
     */
    public function getListener()
    {
        if ($this->listener === null) {
            try {
                $listener = $this->container->get($this->alias);
            } catch (\Exception $exception) {
                throw new \BadMethodCallException('Unable to fetch listener from container');
            }

            if (!$listener instanceof ListenerInterface) {
                throw new \BadMethodCallException('Fetched listener does not implement ListenerInterface');
            }

            $this->listener = $listener;
        }

        return $this->listener;
    }

    /**
     * {@inheritdoc}
     */
    public function handle(EventInterface $event)
    {
        $this->getListener()->handle($event);
    }

    /**
     * {@inheritdoc}
     */
    public function isListener($listener)
    {
        if ($listener instanceof LazyListener) {
            $listener = $listener->getListener();
        }

        return $this->listener === $listener;
    }

    /**
     * @param ContainerInterface $container
     * @param string             $alias
     * @return static
     */
    public static function fromAlias(ContainerInterface $container, $alias)
    {
        return new static($container, $alias);
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.