[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; namespace Symfony\Component\Config\Resource;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/** /**
* @author Nicolas Grekas <p@tchwork.com> * @author Nicolas Grekas <p@tchwork.com>
*/ */
@ -114,7 +117,9 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
private function generateSignature(\ReflectionClass $class) private function generateSignature(\ReflectionClass $class)
{ {
yield $class->getDocComment().$class->getModifiers(); yield $class->getDocComment();
yield (int) $class->isFinal();
yield (int) $class->isAbstract();
if ($class->isTrait()) { if ($class->isTrait()) {
yield print_r(class_uses($class->name), true); yield print_r(class_uses($class->name), true);
@ -149,6 +154,16 @@ class ReflectionClassResource implements SelfCheckingResourceInterface, \Seriali
yield print_r($defaults, true); 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 PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Resource\ReflectionClassResource; use Symfony\Component\Config\Resource\ReflectionClassResource;
use Symfony\Component\DependencyInjection\ServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ReflectionClassResourceTest extends TestCase class ReflectionClassResourceTest extends TestCase
{ {
@ -136,8 +138,52 @@ EOPHP;
yield array(0, 14, '/** priv docblock */'); yield array(0, 14, '/** priv docblock */');
yield array(0, 15, ''); 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 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": { "require-dev": {
"symfony/finder": "~3.3|~4.0", "symfony/finder": "~3.3|~4.0",
"symfony/yaml": "~3.0|~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": { "conflict": {
"symfony/finder": "<3.3", "symfony/finder": "<3.3",

View File

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

View File

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