[Config] Handle Service/EventSubscriberInterface in ReflectionClassResource

This commit is contained in:
Nicolas Grekas 2018-01-30 22:38:46 +01:00
parent 0023f4e84d
commit 67e821b94f
5 changed files with 77 additions and 17 deletions

View File

@ -11,6 +11,9 @@
namespace Symfony\Component\Config\Resource;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* @author Nicolas Grekas <p@tchwork.com>
*/
@ -114,7 +117,9 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
private function generateSignature(\ReflectionClass $class)
{
yield $class->getDocComment().$class->getModifiers();
yield $class->getDocComment();
yield (int) $class->isFinal();
yield (int) $class->isAbstract();
if ($class->isTrait()) {
yield print_r(class_uses($class->name), true);
@ -149,6 +154,16 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
yield print_r($defaults, true);
}
}
if ($class->isSubclassOf(EventSubscriberInterface::class)) {
yield EventSubscriberInterface::class;
yield print_r(\call_user_func(array($class->name, 'getSubscribedEvents')), true);
}
if ($class->isSubclassOf(ServiceSubscriberInterface::class)) {
yield ServiceSubscriberInterface::class;
yield print_r(\call_user_func(array($class->name, 'getSubscribedServices')), true);
}
}
}

View File

@ -13,6 +13,8 @@ namespace Symfony\Component\Config\Tests\Resource;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Resource\ReflectionClassResource;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ReflectionClassResourceTest extends TestCase
{
@ -136,8 +138,52 @@ EOPHP;
yield array(0, 14, '/** priv docblock */');
yield array(0, 15, '');
}
public function testEventSubscriber()
{
$res = new ReflectionClassResource(new \ReflectionClass(TestEventSubscriber::class));
$this->assertTrue($res->isFresh(0));
TestEventSubscriber::$subscribedEvents = array(123);
$this->assertFalse($res->isFresh(0));
$res = new ReflectionClassResource(new \ReflectionClass(TestEventSubscriber::class));
$this->assertTrue($res->isFresh(0));
}
public function testServiceSubscriber()
{
$res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class));
$this->assertTrue($res->isFresh(0));
TestServiceSubscriber::$subscribedServices = array(123);
$this->assertFalse($res->isFresh(0));
$res = new ReflectionClassResource(new \ReflectionClass(TestServiceSubscriber::class));
$this->assertTrue($res->isFresh(0));
}
}
interface DummyInterface
{
}
class TestEventSubscriber implements EventSubscriberInterface
{
public static $subscribedEvents = array();
public static function getSubscribedEvents()
{
return self::$subscribedEvents;
}
}
class TestServiceSubscriber implements ServiceSubscriberInterface
{
public static $subscribedServices = array();
public static function getSubscribedServices()
{
return self::$subscribedServices;
}
}

View File

@ -22,7 +22,8 @@
"require-dev": {
"symfony/finder": "~3.3|~4.0",
"symfony/yaml": "~3.0|~4.0",
"symfony/dependency-injection": "~3.3|~4.0"
"symfony/dependency-injection": "~3.3|~4.0",
"symfony/event-dispatcher": "~3.3|~4.0"
},
"conflict": {
"symfony/finder": "<3.3",

View File

@ -56,14 +56,14 @@ class RegisterServiceSubscribersPass extends AbstractRecursivePass
}
$class = $value->getClass();
if (!is_subclass_of($class, ServiceSubscriberInterface::class)) {
if (!class_exists($class, false)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $this->currentId));
}
if (!$r = $this->container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $this->currentId));
}
if (!$r->isSubclassOf(ServiceSubscriberInterface::class)) {
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $this->currentId, ServiceSubscriberInterface::class));
}
$this->container->addObjectResource($class);
$class = $r->name;
$subscriberMap = array();
$declaringClass = (new \ReflectionMethod($class, 'getSubscribedServices'))->class;

View File

@ -89,17 +89,15 @@ class RegisterListenersPass implements CompilerPassInterface
$def = $container->getDefinition($id);
// We must assume that the class value has been correctly filled, even if the service is created by a factory
$class = $container->getParameterBag()->resolveValue($def->getClass());
$interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
$class = $def->getClass();
if (!is_subclass_of($class, $interface)) {
if (!class_exists($class, false)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
if (!$r = $container->getReflectionClass($class)) {
throw new InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
}
$container->addObjectResource($class);
if (!$r->isSubclassOf(EventSubscriberInterface::class)) {
throw new InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, EventSubscriberInterface::class));
}
$class = $r->name;
ExtractingEventDispatcher::$subscriber = $class;
$extractingDispatcher->addSubscriber($extractingDispatcher);