RegisterListenersPass.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100
  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. protected $dispatcherService;
  19. protected $listenerTag;
  20. protected $subscriberTag;
  21. /**
  22. * @param string $dispatcherService Service name of the event dispatcher in processed container
  23. * @param string $listenerTag Tag name used for listener
  24. * @param string $subscriberTag Tag name used for subscribers
  25. */
  26. public function __construct($dispatcherService = 'event_dispatcher', $listenerTag = 'kernel.event_listener', $subscriberTag = 'kernel.event_subscriber')
  27. {
  28. $this->dispatcherService = $dispatcherService;
  29. $this->listenerTag = $listenerTag;
  30. $this->subscriberTag = $subscriberTag;
  31. }
  32. public function process(ContainerBuilder $container)
  33. {
  34. if (!$container->hasDefinition($this->dispatcherService) && !$container->hasAlias($this->dispatcherService)) {
  35. return;
  36. }
  37. $definition = $container->findDefinition($this->dispatcherService);
  38. foreach ($container->findTaggedServiceIds($this->listenerTag) as $id => $events) {
  39. $def = $container->getDefinition($id);
  40. if (!$def->isPublic()) {
  41. throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event listeners are lazy-loaded.', $id));
  42. }
  43. if ($def->isAbstract()) {
  44. throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event listeners are lazy-loaded.', $id));
  45. }
  46. foreach ($events as $event) {
  47. $priority = isset($event['priority']) ? $event['priority'] : 0;
  48. if (!isset($event['event'])) {
  49. throw new \InvalidArgumentException(sprintf('Service "%s" must define the "event" attribute on "%s" tags.', $id, $this->listenerTag));
  50. }
  51. if (!isset($event['method'])) {
  52. $event['method'] = 'on'.preg_replace_callback(array(
  53. '/(?<=\b)[a-z]/i',
  54. '/[^a-z0-9]/i',
  55. ), function ($matches) { return strtoupper($matches[0]); }, $event['event']);
  56. $event['method'] = preg_replace('/[^a-z0-9]/i', '', $event['method']);
  57. }
  58. $definition->addMethodCall('addListenerService', array($event['event'], array($id, $event['method']), $priority));
  59. }
  60. }
  61. foreach ($container->findTaggedServiceIds($this->subscriberTag) as $id => $attributes) {
  62. $def = $container->getDefinition($id);
  63. if (!$def->isPublic()) {
  64. throw new \InvalidArgumentException(sprintf('The service "%s" must be public as event subscribers are lazy-loaded.', $id));
  65. }
  66. if ($def->isAbstract()) {
  67. throw new \InvalidArgumentException(sprintf('The service "%s" must not be abstract as event subscribers are lazy-loaded.', $id));
  68. }
  69. // We must assume that the class value has been correctly filled, even if the service is created by a factory
  70. $class = $container->getParameterBag()->resolveValue($def->getClass());
  71. $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface';
  72. if (!is_subclass_of($class, $interface)) {
  73. if (!class_exists($class, false)) {
  74. throw new \InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id));
  75. }
  76. throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface));
  77. }
  78. $definition->addMethodCall('addSubscriberService', array($id, $class));
  79. }
  80. }
  81. }