7e7381f92d3a15dc9ba595c70cd5fc4d103a49f3
[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(1, $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 consumer with missing interface in non-production environment.
65    *
66    * @covers ::process
67    */
68   public function testProcessMissingInterface() {
69     $container = $this->buildContainer();
70     $container
71       ->register('consumer_id0', __NAMESPACE__ . '\ValidConsumer')
72       ->addTag('service_collector');
73     $container
74       ->register('consumer_id1', __NAMESPACE__ . '\InvalidConsumer')
75       ->addTag('service_collector');
76
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);
80   }
81
82   /**
83    * Tests one consumer and two handlers.
84    *
85    * @covers ::process
86    */
87   public function testProcess() {
88     $container = $this->buildContainer();
89     $container
90       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
91       ->addTag('service_collector');
92
93     $container
94       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
95       ->addTag('consumer_id');
96     $container
97       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
98       ->addTag('consumer_id');
99
100     $handler_pass = new TaggedHandlersPass();
101     $handler_pass->process($container);
102
103     $method_calls = $container->getDefinition('consumer_id')->getMethodCalls();
104     $this->assertCount(2, $method_calls);
105   }
106
107   /**
108    * Tests handler priority sorting.
109    *
110    * @covers ::process
111    */
112   public function testProcessPriority() {
113     $container = $this->buildContainer();
114     $container
115       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
116       ->addTag('service_collector');
117
118     $container
119       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
120       ->addTag('consumer_id');
121     $container
122       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
123       ->addTag('consumer_id', [
124         'priority' => 10,
125       ]);
126
127     $handler_pass = new TaggedHandlersPass();
128     $handler_pass->process($container);
129
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]);
136   }
137
138   /**
139    * Tests consumer method without priority parameter.
140    *
141    * @covers ::process
142    */
143   public function testProcessNoPriorityParam() {
144     $container = $this->buildContainer();
145     $container
146       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
147       ->addTag('service_collector', [
148         'call' => 'addNoPriority',
149       ]);
150
151     $container
152       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
153       ->addTag('consumer_id');
154     $container
155       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
156       ->addTag('consumer_id', [
157         'priority' => 10,
158       ]);
159
160     $handler_pass = new TaggedHandlersPass();
161     $handler_pass->process($container);
162
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]);
169   }
170
171   /**
172    * Tests consumer method with an ID parameter.
173    *
174    * @covers ::process
175    */
176   public function testProcessWithIdParameter() {
177     $container = $this->buildContainer();
178     $container
179       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
180       ->addTag('service_collector', [
181         'call' => 'addWithId',
182       ]);
183
184     $container
185       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
186       ->addTag('consumer_id');
187     $container
188       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
189       ->addTag('consumer_id', [
190         'priority' => 10,
191       ]);
192
193     $handler_pass = new TaggedHandlersPass();
194     $handler_pass->process($container);
195
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]);
204   }
205
206   /**
207    * Tests interface validation in non-production environment.
208    *
209    * @covers ::process
210    */
211   public function testProcessInterfaceMismatch() {
212     $container = $this->buildContainer();
213
214     $container
215       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumer')
216       ->addTag('service_collector');
217     $container
218       ->register('handler1', __NAMESPACE__ . '\InvalidHandler')
219       ->addTag('consumer_id');
220     $container
221       ->register('handler2', __NAMESPACE__ . '\ValidHandler')
222       ->addTag('consumer_id', [
223         'priority' => 10,
224       ]);
225
226     $handler_pass = new TaggedHandlersPass();
227     $this->setExpectedException(LogicException::class);
228     $handler_pass->process($container);
229   }
230
231   /**
232    * Tests consumer method with extra parameters.
233    *
234    * @covers ::process
235    */
236   public function testProcessWithExtraArguments() {
237     $container = $this->buildContainer();
238
239     $container
240       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
241       ->addTag('service_collector');
242
243     $container
244       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
245       ->addTag('consumer_id', [
246           'extra1' => 'extra1',
247           'extra2' => 'extra2',
248         ]);
249
250     $handler_pass = new TaggedHandlersPass();
251     $handler_pass->process($container);
252
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]);
259   }
260
261   /**
262    * Tests consumer method with extra parameters and no priority.
263    *
264    * @covers ::process
265    */
266   public function testProcessNoPriorityAndExtraArguments() {
267     $container = $this->buildContainer();
268
269     $container
270       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
271       ->addTag('service_collector', [
272         'call' => 'addNoPriority'
273       ]);
274
275     $container
276       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
277       ->addTag('consumer_id', [
278         'extra' => 'extra',
279       ]);
280
281     $handler_pass = new TaggedHandlersPass();
282     $handler_pass->process($container);
283
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]);
288   }
289
290   /**
291    * Tests consumer method with priority, id and extra parameters.
292    *
293    * @covers ::process
294    */
295   public function testProcessWithIdAndExtraArguments() {
296     $container = $this->buildContainer();
297
298     $container
299       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
300       ->addTag('service_collector', [
301         'call' => 'addWithId'
302       ]);
303
304     $container
305       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
306       ->addTag('consumer_id', [
307         'extra1' => 'extra1',
308       ]);
309
310     $handler_pass = new TaggedHandlersPass();
311     $handler_pass->process($container);
312
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]);
320   }
321
322   /**
323    * Tests consumer method with priority and extra parameters in different order.
324    *
325    * @covers ::process
326    */
327   public function testProcessWithDifferentArgumentsOrderAndDefaultValue() {
328     $container = $this->buildContainer();
329
330     $container
331       ->register('consumer_id', __NAMESPACE__ . '\ValidConsumerWithExtraArguments')
332       ->addTag('service_collector', [
333         'call' => 'addWithDifferentOrder'
334       ]);
335
336     $container
337       ->register('handler1', __NAMESPACE__ . '\ValidHandler')
338       ->addTag('consumer_id', [
339         'priority' => 0,
340         'extra1' => 'extra1',
341         'extra3' => 'extra3'
342       ]);
343
344     $handler_pass = new TaggedHandlersPass();
345     $handler_pass->process($container);
346
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]));
351   }
352
353 }
354
355 interface HandlerInterface {
356 }
357 class ValidConsumer {
358   public function addHandler(HandlerInterface $instance, $priority = 0) {
359   }
360   public function addNoPriority(HandlerInterface $instance) {
361   }
362   public function addWithId(HandlerInterface $instance, $id, $priority = 0) {
363   }
364
365 }
366 class InvalidConsumer {
367   public function addHandler($instance, $priority = 0) {
368   }
369
370 }
371 class ValidConsumerWithExtraArguments {
372   public function addHandler(HandlerInterface $instance, $priority = 0, $extra1 = '', $extra2 = '') {
373   }
374   public function addNoPriority(HandlerInterface $instance, $extra) {
375   }
376   public function addWithId(HandlerInterface $instance, $id, $priority = 0, $extra1 = '', $extra2 = NULL) {
377   }
378   public function addWithDifferentOrder(HandlerInterface $instance, $extra1, $priority = 0, $extra2 = 'default2', $extra3 = 'default3') {
379   }
380
381 }
382 class ValidHandler implements HandlerInterface {
383 }
384 class InvalidHandler {
385 }