Skip to content

Commit

Permalink
Add helper class for single-event subscription
Browse files Browse the repository at this point in the history
  • Loading branch information
yceruto committed Sep 7, 2019
1 parent 5765539 commit 4875a6d
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/EventDispatcher/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========

4.4.0
-----

* added `InvokableEventSubscriberTrait` helper for single-event subscription.

4.3.0
-----

Expand Down
@@ -0,0 +1,56 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\EventDispatcher;

use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;

/**
* Helper trait for single-event subscription.
*
* @author Yonel Ceruto <yonelceruto@gmail.com>
*/
trait InvokableEventSubscriberTrait
{
/**
* {@inheritdoc}
*/
final public static function getSubscribedEvents(): array
{
return [self::getEventName() => ['__invoke', self::getPriority()]];
}

protected static function getEventName(): string
{
$method = new \ReflectionMethod(self::class, '__invoke');

if (0 === $method->getNumberOfParameters()) {
throw new \LogicException(sprintf('The Event name cannot be inferred from "%s::%s()" method without parameters, you must to define one or implement the "%s::getEventName()" method to return it explicitly.', self::class, $method->getName(), self::class));
}

$parameter = $method->getParameters()[0];

if (null === $type = $parameter->getType()) {
throw new \LogicException(sprintf('The Event name cannot be inferred from "%s::%s()" method without type-hint the "$%s" parameter, you must to type-hint it or implement the "%s::getEventName()" method to return it explicitly.', ContractsEvent::class, $method->getName(), $parameter->getName(), self::class));
}

if ($type->isBuiltin()) {
throw new \LogicException(sprintf('The "$%s" parameter defined in "%s::%s()" method must be a class, "%s" given.', $parameter->getName(), self::class, $method->getName(), $type->getName()));
}

return $type->getName();
}

protected static function getPriority(): int
{
return 0;
}
}
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcher;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\EventDispatcher\InvokableEventSubscriberTrait;
use Symfony\Contracts\EventDispatcher\Event as ContractsEvent;

class EventDispatcherTest extends TestCase
Expand Down Expand Up @@ -437,6 +438,16 @@ public function testLegacySignatureWithNewEventObject()
$this->expectExceptionMessage('Argument 1 passed to "Symfony\Component\EventDispatcher\EventDispatcherInterface::dispatch()" must be an object, string given.');
$this->dispatcher->dispatch('foo', new ContractsEvent());
}

public function testSingleEventSubsriber()
{
$subscriber = new TestSingleEventListener();
$this->dispatcher->addSubscriber($subscriber);
$this->assertTrue($this->dispatcher->hasListeners(MyEvent::class));

$this->dispatcher->dispatch(new MyEvent());
$this->assertTrue($subscriber->invoked);
}
}

class CallableClass
Expand Down Expand Up @@ -480,6 +491,22 @@ public function foo($e, $name, $dispatcher)
}
}

class MyEvent extends ContractsEvent
{
}

class TestSingleEventListener implements EventSubscriberInterface
{
use InvokableEventSubscriberTrait;

public $invoked = false;

public function __invoke(MyEvent $event): void
{
$this->invoked = true;
}
}

class TestEventSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
Expand Down

0 comments on commit 4875a6d

Please sign in to comment.