848c458a7514bdb89f9e477862ea6f0430b40627
[yaffs-website] / web / core / tests / Drupal / Tests / Core / DependencyInjection / Compiler / TaggedHandlersPassTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\Core\DependencyInjection\Compiler\TaggedHandlersPassTest.
6  */
7
8 namespace Drupal\Tests\Core\DependencyInjection\Compiler;
9
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;
15
16 /**
17  * @coversDefaultClass \Drupal\Core\DependencyInjection\Compiler\TaggedHandlersPass
18  * @group DependencyInjection
19  */
20 class TaggedHandlersPassTest extends UnitTestCase {
21
22   protected function buildContainer($environment = 'dev') {
23     $container = new ContainerBuilder();
24     $container->setParameter('kernel.environment', $environment);
25     return $container;
26   }
27
28   /**
29    * Tests without any consumers.
30    *
31    * @covers ::process
32    */
33   public function testProcessNoConsumers() {
34     $container = $this->buildContainer();
35     $container
36       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer');
37
38     $handler_pass = new TaggedHandlersPass();
39     $handler_pass->process($container);
40
41     $this->assertCount(2, $container->getDefinitions());
42     $this->assertFalse($container->getDefinition('consumer_id')->hasMethodCall('addHandler'));
43   }
44
45   /**
46    * Tests a required consumer with no handlers.
47    *
48    * @covers ::process
49    */
50   public function testProcessRequiredHandlers() {
51     $container = $this->buildContainer();
52     $container
53       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
54       ->addTag('service_collector', [
55         'required' => TRUE,
56       ]);
57
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);
61   }
62
63   /**
64    * Tests a required consumer with no handlers.
65    *
66    * @covers ::process
67    * @covers ::processServiceIdCollectorPass
68    */
69   public function testIdCollectorProcessRequiredHandlers() {
70     $this->setExpectedException(LogicException::class, "At least one service tagged with 'consumer_id' is required.");
71     $container = $this->buildContainer();
72     $container
73       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
74       ->addTag('service_id_collector', [
75         'required' => TRUE,
76       ]);
77
78     $handler_pass = new TaggedHandlersPass();
79     $handler_pass->process($container);
80   }
81
82   /**
83    * Tests consumer with missing interface in non-production environment.
84    *
85    * @covers ::process
86    */
87   public function testProcessMissingInterface() {
88     $container = $this->buildContainer();
89     $container
90       ->register('consumer_id0', __NAMESPACE__ . '\ValidConsumer')
91       ->addTag('service_collector');
92     $container
93       ->register('consumer_id1', __NAMESPACE__ . '\InvalidConsumer')
94       ->addTag('service_collector');
95
96     $handler_pass = new TaggedHandlersPass();
97     $this->setExpectedException(LogicException::class, "Service consumer 'consumer_id1' class method Drupal\Tests\Core\DependencyInjection\Compiler\InvalidConsumer::addHandler() has to type-hint an interface.");
98     $handler_pass->process($container);
99   }
100
101   /**
102    * Tests one consumer and two handlers.
103    *
104    * @covers ::process
105    */
106   public function testProcess() {
107     $container = $this->buildContainer();
108     $container
109       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
110       ->addTag('service_collector');
111
112     $container
113       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
114       ->addTag('consumer_id');
115     $container
116       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
117       ->addTag('consumer_id');
118
119     $handler_pass = new TaggedHandlersPass();
120     $handler_pass->process($container);
121
122     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
123     $this->assertCount(2, $method_calls);
124   }
125
126   /**
127    * Tests one consumer and two handlers with service ID collection.
128    *
129    * @covers ::process
130    */
131   public function testserviceIdProcess() {
132     $container = $this->buildContainer();
133     $container
134       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
135       ->addTag('service_id_collector');
136
137     $container
138       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
139       ->addTag('consumer_id');
140     $container
141       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
142       ->addTag('consumer_id');
143
144     $handler_pass = new TaggedHandlersPass();
145     $handler_pass->process($container);
146
147     $arguments = $container->getDefinition('consumer_id')->getArguments();
148     $this->assertCount(1, $arguments);
149     $this->assertCount(2, $arguments[0]);
150   }
151
152   /**
153    * Tests handler priority sorting.
154    *
155    * @covers ::process
156    */
157   public function testProcessPriority() {
158     $container = $this->buildContainer();
159     $container
160       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
161       ->addTag('service_collector');
162
163     $container
164       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
165       ->addTag('consumer_id');
166     $container
167       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
168       ->addTag('consumer_id', [
169         'priority' => 10,
170       ]);
171
172     $handler_pass = new TaggedHandlersPass();
173     $handler_pass->process($container);
174
175     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
176     $this->assertCount(2, $method_calls);
177     $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
178     $this->assertEquals(10, $method_calls[0][1][1]);
179     $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
180     $this->assertEquals(0, $method_calls[1][1][1]);
181   }
182
183   /**
184    * Tests handler priority sorting for service ID collection.
185    *
186    * @covers ::process
187    */
188   public function testserviceIdProcessPriority() {
189     $container = $this->buildContainer();
190     $container
191       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
192       ->addTag('service_id_collector');
193
194     $container
195       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
196       ->addTag('consumer_id');
197     $container
198       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
199       ->addTag('consumer_id', [
200         'priority' => 20,
201       ]);
202     $container
203       ->register('handler3', __NAMESPACE__ . '\ValidHandler')
204       ->addTag('consumer_id', [
205         'priority' => 10,
206       ]);
207
208     $handler_pass = new TaggedHandlersPass();
209     $handler_pass->process($container);
210
211     $arguments = $container->getDefinition('consumer_id')->getArguments();
212     $this->assertCount(1, $arguments);
213     $this->assertSame(['handler2', 'handler3', 'handler1'], $arguments[0]);
214   }
215
216   /**
217    * Tests consumer method without priority parameter.
218    *
219    * @covers ::process
220    */
221   public function testProcessNoPriorityParam() {
222     $container = $this->buildContainer();
223     $container
224       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
225       ->addTag('service_collector', [
226         'call' => 'addNoPriority',
227       ]);
228
229     $container
230       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
231       ->addTag('consumer_id');
232     $container
233       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
234       ->addTag('consumer_id', [
235         'priority' => 10,
236       ]);
237
238     $handler_pass = new TaggedHandlersPass();
239     $handler_pass->process($container);
240
241     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
242     $this->assertCount(2, $method_calls);
243     $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
244     $this->assertCount(1, $method_calls[0][1]);
245     $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
246     $this->assertCount(1, $method_calls[0][1]);
247   }
248
249   /**
250    * Tests consumer method with an ID parameter.
251    *
252    * @covers ::process
253    */
254   public function testProcessWithIdParameter() {
255     $container = $this->buildContainer();
256     $container
257       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
258       ->addTag('service_collector', [
259         'call' => 'addWithId',
260       ]);
261
262     $container
263       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
264       ->addTag('consumer_id');
265     $container
266       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
267       ->addTag('consumer_id', [
268         'priority' => 10,
269       ]);
270
271     $handler_pass = new TaggedHandlersPass();
272     $handler_pass->process($container);
273
274     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
275     $this->assertCount(2, $method_calls);
276     $this->assertEquals(new Reference('handler2'), $method_calls[0][1][0]);
277     $this->assertEquals('handler2', $method_calls[0][1][1]);
278     $this->assertEquals(10, $method_calls[0][1][2]);
279     $this->assertEquals(new Reference('handler1'), $method_calls[1][1][0]);
280     $this->assertEquals('handler1', $method_calls[1][1][1]);
281     $this->assertEquals(0, $method_calls[1][1][2]);
282   }
283
284   /**
285    * Tests interface validation in non-production environment.
286    *
287    * @covers ::process
288    */
289   public function testProcessInterfaceMismatch() {
290     $container = $this->buildContainer();
291
292     $container
293       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
294       ->addTag('service_collector');
295     $container
296       ->register('handler1', __NAMESPACE__ . '\InvalidHandler')
297       ->addTag('consumer_id');
298     $container
299       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
300       ->addTag('consumer_id', [
301         'priority' => 10,
302       ]);
303
304     $handler_pass = new TaggedHandlersPass();
305     $this->setExpectedException(LogicException::class);
306     $handler_pass->process($container);
307   }
308
309   /**
310    * Tests consumer method with extra parameters.
311    *
312    * @covers ::process
313    */
314   public function testProcessWithExtraArguments() {
315     $container = $this->buildContainer();
316
317     $container
318       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
319       ->addTag('service_collector');
320
321     $container
322       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
323       ->addTag('consumer_id', [
324           'extra1' => 'extra1',
325           'extra2' => 'extra2',
326         ]);
327
328     $handler_pass = new TaggedHandlersPass();
329     $handler_pass->process($container);
330
331     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
332     $this->assertCount(4, $method_calls[0][1]);
333     $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
334     $this->assertEquals(0, $method_calls[0][1][1]);
335     $this->assertEquals('extra1', $method_calls[0][1][2]);
336     $this->assertEquals('extra2', $method_calls[0][1][3]);
337   }
338
339   /**
340    * Tests consumer method with extra parameters and no priority.
341    *
342    * @covers ::process
343    */
344   public function testProcessNoPriorityAndExtraArguments() {
345     $container = $this->buildContainer();
346
347     $container
348       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
349       ->addTag('service_collector', [
350         'call' => 'addNoPriority'
351       ]);
352
353     $container
354       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
355       ->addTag('consumer_id', [
356         'extra' => 'extra',
357       ]);
358
359     $handler_pass = new TaggedHandlersPass();
360     $handler_pass->process($container);
361
362     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
363     $this->assertCount(2, $method_calls[0][1]);
364     $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
365     $this->assertEquals('extra', $method_calls[0][1][1]);
366   }
367
368   /**
369    * Tests consumer method with priority, id and extra parameters.
370    *
371    * @covers ::process
372    */
373   public function testProcessWithIdAndExtraArguments() {
374     $container = $this->buildContainer();
375
376     $container
377       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
378       ->addTag('service_collector', [
379         'call' => 'addWithId'
380       ]);
381
382     $container
383       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
384       ->addTag('consumer_id', [
385         'extra1' => 'extra1',
386       ]);
387
388     $handler_pass = new TaggedHandlersPass();
389     $handler_pass->process($container);
390
391     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
392     $this->assertCount(5, $method_calls[0][1]);
393     $this->assertEquals(new Reference('handler1'), $method_calls[0][1][0]);
394     $this->assertEquals('handler1', $method_calls[0][1][1]);
395     $this->assertEquals(0, $method_calls[0][1][2]);
396     $this->assertEquals('extra1', $method_calls[0][1][3]);
397     $this->assertNull($method_calls[0][1][4]);
398   }
399
400   /**
401    * Tests consumer method with priority and extra parameters in different order.
402    *
403    * @covers ::process
404    */
405   public function testProcessWithDifferentArgumentsOrderAndDefaultValue() {
406     $container = $this->buildContainer();
407
408     $container
409       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
410       ->addTag('service_collector', [
411         'call' => 'addWithDifferentOrder'
412       ]);
413
414     $container
415       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
416       ->addTag('consumer_id', [
417         'priority' => 0,
418         'extra1' => 'extra1',
419         'extra3' => 'extra3'
420       ]);
421
422     $handler_pass = new TaggedHandlersPass();
423     $handler_pass->process($container);
424
425     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
426     $this->assertCount(5, $method_calls[0][1]);
427     $expected = [new Reference('handler1'), 'extra1', 0, 'default2', 'extra3'];
428     $this->assertEquals($expected, array_values($method_calls[0][1]));
429   }
430
431 }
432
433 interface HandlerInterface {
434 }
435 class ValidConsumer {
436   public function addHandler(HandlerInterface $instance, $priority = 0) {
437   }
438   public function addNoPriority(HandlerInterface $instance) {
439   }
440   public function addWithId(HandlerInterface $instance, $id, $priority = 0) {
441   }
442
443 }
444 class InvalidConsumer {
445   public function addHandler($instance, $priority = 0) {
446   }
447
448 }
449 class ValidConsumerWithExtraArguments {
450   public function addHandler(HandlerInterface $instance, $priority = 0, $extra1 = '', $extra2 = '') {
451   }
452   public function addNoPriority(HandlerInterface $instance, $extra) {
453   }
454   public function addWithId(HandlerInterface $instance, $id, $priority = 0, $extra1 = '', $extra2 = NULL) {
455   }
456   public function addWithDifferentOrder(HandlerInterface $instance, $extra1, $priority = 0, $extra2 = 'default2', $extra3 = 'default3') {
457   }
458
459 }
460 class ValidHandler implements HandlerInterface {
461 }
462 class InvalidHandler {
463 }