5 * Contains \Drupal\Tests\Core\DependencyInjection\Compiler\TaggedHandlersPassTest.
8 namespace Drupal\Tests\Core\DependencyInjection\Compiler;
10 use Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass;
11 use Drupal\Tests\UnitTestCase;
12 use Symfony\Component\DependencyInjection\ContainerBuilder;
13 use Symfony\Component\DependencyInjection\Exception\LogicException;
14 use Symfony\Component\DependencyInjection\Reference;
17 * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass
18 * @group DependencyInjection
20 class TaggedHandlersPassTest extends UnitTestCase {
22 protected function buildContainer($environment = 'dev') {
23 $container = new ContainerBuilder();
24 $container->setParameter('kernel.environment', $environment);
29 * Tests without any consumers.
33 public function testProcessNoConsumers() {
34 $container = $this->buildContainer();
36 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer');
38 $handler_pass = new TaggedHandlersPass();
39 $handler_pass->process($container);
41 $this->assertCount(1, $container->getDefinitions());
42 $this->assertFalse($container->getDefinition('consumer_id')->hasMethodCall('addHandler'));
46 * Tests a required consumer with no handlers.
50 public function testProcessRequiredHandlers() {
51 $container = $this->buildContainer();
53 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
54 ->addTag('service_collector', [
58 $handler_pass = new TaggedHandlersPass();
59 $this->setExpectedException(LogicException::class, "At least one service tagged with 'consumer_id' is required.");
60 $handler_pass->process($container);
64 * Tests consumer with missing interface in non-production environment.
68 public function testProcessMissingInterface() {
69 $container = $this->buildContainer();
71 ->register('consumer_id0', __NAMESPACE__ . '\ValidConsumer')
72 ->addTag('service_collector');
74 ->register('consumer_id1', __NAMESPACE__ . '\InvalidConsumer')
75 ->addTag('service_collector');
77 $handler_pass = new TaggedHandlersPass();
78 $this->setExpectedException(LogicException::class, "Service consumer 'consumer_id1' class method Drupal\Tests\Core\DependencyInjection\Compiler\InvalidConsumer::addHandler() has to type-hint an interface.");
79 $handler_pass->process($container);
83 * Tests one consumer and two handlers.
87 public function testProcess() {
88 $container = $this->buildContainer();
90 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
91 ->addTag('service_collector');
94 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
95 ->addTag('consumer_id');
97 ->register('handler2', __NAMESPACE__ . '\ValidHandler')
98 ->addTag('consumer_id');
100 $handler_pass = new TaggedHandlersPass();
101 $handler_pass->process($container);
103 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
104 $this->assertCount(2, $method_calls);
108 * Tests handler priority sorting.
112 public function testProcessPriority() {
113 $container = $this->buildContainer();
115 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
116 ->addTag('service_collector');
119 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
120 ->addTag('consumer_id');
122 ->register('handler2', __NAMESPACE__ . '\ValidHandler')
123 ->addTag('consumer_id', [
127 $handler_pass = new TaggedHandlersPass();
128 $handler_pass->process($container);
130 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
131 $this->assertCount(2, $method_calls);
132 $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
133 $this->assertEquals(10, $method_calls[0][1][1]);
134 $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
135 $this->assertEquals(0, $method_calls[1][1][1]);
139 * Tests consumer method without priority parameter.
143 public function testProcessNoPriorityParam() {
144 $container = $this->buildContainer();
146 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
147 ->addTag('service_collector', [
148 'call' => 'addNoPriority',
152 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
153 ->addTag('consumer_id');
155 ->register('handler2', __NAMESPACE__ . '\ValidHandler')
156 ->addTag('consumer_id', [
160 $handler_pass = new TaggedHandlersPass();
161 $handler_pass->process($container);
163 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
164 $this->assertCount(2, $method_calls);
165 $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
166 $this->assertCount(1, $method_calls[0][1]);
167 $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
168 $this->assertCount(1, $method_calls[0][1]);
172 * Tests consumer method with an ID parameter.
176 public function testProcessWithIdParameter() {
177 $container = $this->buildContainer();
179 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
180 ->addTag('service_collector', [
181 'call' => 'addWithId',
185 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
186 ->addTag('consumer_id');
188 ->register('handler2', __NAMESPACE__ . '\ValidHandler')
189 ->addTag('consumer_id', [
193 $handler_pass = new TaggedHandlersPass();
194 $handler_pass->process($container);
196 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
197 $this->assertCount(2, $method_calls);
198 $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
199 $this->assertEquals('handler2', $method_calls[0][1][1]);
200 $this->assertEquals(10, $method_calls[0][1][2]);
201 $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
202 $this->assertEquals('handler1', $method_calls[1][1][1]);
203 $this->assertEquals(0, $method_calls[1][1][2]);
207 * Tests interface validation in non-production environment.
211 public function testProcessInterfaceMismatch() {
212 $container = $this->buildContainer();
215 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
216 ->addTag('service_collector');
218 ->register('handler1', __NAMESPACE__ . '\InvalidHandler')
219 ->addTag('consumer_id');
221 ->register('handler2', __NAMESPACE__ . '\ValidHandler')
222 ->addTag('consumer_id', [
226 $handler_pass = new TaggedHandlersPass();
227 $this->setExpectedException(LogicException::class);
228 $handler_pass->process($container);
232 * Tests consumer method with extra parameters.
236 public function testProcessWithExtraArguments() {
237 $container = $this->buildContainer();
240 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
241 ->addTag('service_collector');
244 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
245 ->addTag('consumer_id', [
246 'extra1' => 'extra1',
247 'extra2' => 'extra2',
250 $handler_pass = new TaggedHandlersPass();
251 $handler_pass->process($container);
253 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
254 $this->assertCount(4, $method_calls[0][1]);
255 $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
256 $this->assertEquals(0, $method_calls[0][1][1]);
257 $this->assertEquals('extra1', $method_calls[0][1][2]);
258 $this->assertEquals('extra2', $method_calls[0][1][3]);
262 * Tests consumer method with extra parameters and no priority.
266 public function testProcessNoPriorityAndExtraArguments() {
267 $container = $this->buildContainer();
270 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
271 ->addTag('service_collector', [
272 'call' => 'addNoPriority'
276 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
277 ->addTag('consumer_id', [
281 $handler_pass = new TaggedHandlersPass();
282 $handler_pass->process($container);
284 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
285 $this->assertCount(2, $method_calls[0][1]);
286 $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
287 $this->assertEquals('extra', $method_calls[0][1][1]);
291 * Tests consumer method with priority, id and extra parameters.
295 public function testProcessWithIdAndExtraArguments() {
296 $container = $this->buildContainer();
299 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
300 ->addTag('service_collector', [
301 'call' => 'addWithId'
305 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
306 ->addTag('consumer_id', [
307 'extra1' => 'extra1',
310 $handler_pass = new TaggedHandlersPass();
311 $handler_pass->process($container);
313 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
314 $this->assertCount(5, $method_calls[0][1]);
315 $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
316 $this->assertEquals('handler1', $method_calls[0][1][1]);
317 $this->assertEquals(0, $method_calls[0][1][2]);
318 $this->assertEquals('extra1', $method_calls[0][1][3]);
319 $this->assertNull($method_calls[0][1][4]);
323 * Tests consumer method with priority and extra parameters in different order.
327 public function testProcessWithDifferentArgumentsOrderAndDefaultValue() {
328 $container = $this->buildContainer();
331 ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
332 ->addTag('service_collector', [
333 'call' => 'addWithDifferentOrder'
337 ->register('handler1', __NAMESPACE__ . '\ValidHandler')
338 ->addTag('consumer_id', [
340 'extra1' => 'extra1',
344 $handler_pass = new TaggedHandlersPass();
345 $handler_pass->process($container);
347 $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
348 $this->assertCount(5, $method_calls[0][1]);
349 $expected = [new Reference('handler1'), 'extra1', 0, 'default2', 'extra3'];
350 $this->assertEquals($expected, array_values($method_calls[0][1]));
355 interface HandlerInterface {
357 class ValidConsumer {
358 public function addHandler(HandlerInterface $instance, $priority = 0) {
360 public function addNoPriority(HandlerInterface $instance) {
362 public function addWithId(HandlerInterface $instance, $id, $priority = 0) {
366 class InvalidConsumer {
367 public function addHandler($instance, $priority = 0) {
371 class ValidConsumerWithExtraArguments {
372 public function addHandler(HandlerInterface $instance, $priority = 0, $extra1 = '', $extra2 = '') {
374 public function addNoPriority(HandlerInterface $instance, $extra) {
376 public function addWithId(HandlerInterface $instance, $id, $priority = 0, $extra1 = '', $extra2 = NULL) {
378 public function addWithDifferentOrder(HandlerInterface $instance, $extra1, $priority = 0, $extra2 = 'default2', $extra3 = 'default3') {
382 class ValidHandler implements HandlerInterface {
384 class InvalidHandler {