Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Can the Emitter be made ContainerAware? #59

Closed
localheinz opened this issue Sep 5, 2015 · 3 comments
Closed

Question: Can the Emitter be made ContainerAware? #59

localheinz opened this issue Sep 5, 2015 · 3 comments

Comments

@localheinz
Copy link
Contributor

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);
    }
}
@bradhanebury
Copy link

Would also love to see this addition. If we're adding many events, we would rather not have to instantiate an instance of each listener and then pass them into the emitter. Rather, let us pass in a list of string aliases and have the container lazy load them when / if needed:

$emitter->addListener('some.event', \Some\Listener::class);
$emitter->addListener('different.event', \SomeOther\Listener::class);

@localheinz
Copy link
Contributor Author

@bradhanebury

See #61!

@localheinz
Copy link
Contributor Author

@bradhanebury

Just released a small package right here: refinery29/league-lazy-event:0.1.0!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants