RegisterListenersPass.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\EventDispatcher\DependencyInjection;
  11. use Symfony\Component\DependencyInjection\ContainerBuilder;
  12. use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
  13. /**
  14. * Compiler pass to register tagged services for an event dispatcher.
  15. */
  16. class RegisterListenersPass implements CompilerPassInterface
  17. {
  18. /**
  19. * @var string
  20. */
  21. protected $dispatcherService;
  22. /**
  23. * @var string
  24. */
  25. protected $listenerTag;
  26. /**
  27. * @var string
  28. */
  29. protected $subscriberTag;
  30. /**
  31. * Constructor.
  32. *
  33. * @param string $dispatcherService Service name of the event dispatcher in processed container
  34. * @param string $listenerTag Tag name used for listener
  35. * @param string $subscriberTag Tag name used for subscribers
  36. */
  37. public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber')
  38. {
  39. $this->dispatcherService = $dispatcherService;
  40. $this->listenerTag = $listenerTag;
  41. $this->subscriberTag = $subscriberTag;
  42. }
  43. public function process(ContainerBuilder $container)
  44. {
  45. if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
  46. return;
  47. }
  48. $definition = $container->findDefinition($this->dispatcherService);
  49. foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) {
  50. $def = $container->getDefinition($id);
  51. if (!$def->isPublic()) {
  52. throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id));
  53. }
  54. if ($def->isAbstract()) {
  55. throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event listeners are lazy-loaded.', $id));
  56. }
  57. foreach ($events as $event) {
  58. $priority = isset($event['priority']) ? $event['priority'] : 0;
  59. if (!isset($event['event'])) {
  60. throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
  61. }
  62. if (!isset($event['method'])) {
  63. $event['method'] = 'on'.preg_replace_callback(array(
  64. '/(?<=\b)[a-z]/i',
  65. '/[^a-z0-9]/i',
  66. ), function ($matches) { return strtoupper($matches[0]); }, $event['event']);
  67. $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);
  68. }
  69. $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
  70. }
  71. }
  72. foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) {
  73. $def = $container->getDefinition($id);
  74. if (!$def->isPublic()) {
  75. throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id));
  76. }
  77. if ($def->isAbstract()) {
  78. throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event subscribers are lazy-loaded.', $id));
  79. }
  80. // We must assume that the class value has been correctly filled, even if the service is created by a factory
  81. $class = $container->getParameterBag()->resolveValue($def->getClass());
  82. $refClass = new \ReflectionClass($class);
  83. $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
  84. if (!$refClass->implementsInterface($interface)) {
  85. throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
  86. }
  87. $definition->addMethodCall('addSubscriberService', array($id, $class));
  88. }
  89. }
  90. }