Updated to Drupal 8.6.4, which is PHP 7.3 friendly. Also updated HTMLaw library....
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Layout / LayoutPluginManagerTest.php
1 <?php
2
3 namespace Drupal\Tests\Core\Layout;
4
5 use Drupal\Component\Plugin\Derivative\DeriverBase;
6 use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
7 use Drupal\Core\Cache\CacheBackendInterface;
8 use Drupal\Core\DependencyInjection\ContainerBuilder;
9 use Drupal\Core\Extension\Extension;
10 use Drupal\Core\Extension\ModuleHandlerInterface;
11 use Drupal\Core\Extension\ThemeHandlerInterface;
12 use Drupal\Core\Layout\LayoutDefault;
13 use Drupal\Core\Layout\LayoutDefinition;
14 use Drupal\Core\Layout\LayoutPluginManager;
15 use Drupal\Tests\UnitTestCase;
16 use org\bovigo\vfs\vfsStream;
17 use Prophecy\Argument;
18
19 /**
20  * @coversDefaultClass \Drupal\Core\Layout\LayoutPluginManager
21  * @group Layout
22  */
23 class LayoutPluginManagerTest extends UnitTestCase {
24
25   /**
26    * The module handler.
27    *
28    * @var \Drupal\Core\Extension\ModuleHandlerInterface
29    */
30   protected $moduleHandler;
31
32   /**
33    * The theme handler.
34    *
35    * @var \Drupal\Core\Extension\ThemeHandlerInterface
36    */
37   protected $themeHandler;
38
39   /**
40    * Cache backend instance.
41    *
42    * @var \Drupal\Core\Cache\CacheBackendInterface
43    */
44   protected $cacheBackend;
45
46   /**
47    * The layout plugin manager.
48    *
49    * @var \Drupal\Core\Layout\LayoutPluginManagerInterface
50    */
51   protected $layoutPluginManager;
52
53   /**
54    * {@inheritdoc}
55    */
56   protected function setUp() {
57     parent::setUp();
58
59     $this->setUpFilesystem();
60
61     $container = new ContainerBuilder();
62     $container->set('string_translation', $this->getStringTranslationStub());
63     \Drupal::setContainer($container);
64
65     $this->moduleHandler = $this->prophesize(ModuleHandlerInterface::class);
66
67     $this->moduleHandler->moduleExists('module_a')->willReturn(TRUE);
68     $this->moduleHandler->moduleExists('theme_a')->willReturn(FALSE);
69     $this->moduleHandler->moduleExists('core')->willReturn(FALSE);
70     $this->moduleHandler->moduleExists('invalid_provider')->willReturn(FALSE);
71
72     $module_a = new Extension('/', 'module', vfsStream::url('root/modules/module_a/module_a.layouts.yml'));
73     $this->moduleHandler->getModule('module_a')->willReturn($module_a);
74     $this->moduleHandler->getModuleDirectories()->willReturn(['module_a' => vfsStream::url('root/modules/module_a')]);
75     $this->moduleHandler->alter('layout', Argument::type('array'))->shouldBeCalled();
76
77     $this->themeHandler = $this->prophesize(ThemeHandlerInterface::class);
78
79     $this->themeHandler->themeExists('theme_a')->willReturn(TRUE);
80     $this->themeHandler->themeExists('core')->willReturn(FALSE);
81     $this->themeHandler->themeExists('invalid_provider')->willReturn(FALSE);
82
83     $theme_a = new Extension('/', 'theme', vfsStream::url('root/themes/theme_a/theme_a.layouts.yml'));
84     $this->themeHandler->getTheme('theme_a')->willReturn($theme_a);
85     $this->themeHandler->getThemeDirectories()->willReturn(['theme_a' => vfsStream::url('root/themes/theme_a')]);
86
87     $this->cacheBackend = $this->prophesize(CacheBackendInterface::class);
88
89     $namespaces = new \ArrayObject(['Drupal\Core' => vfsStream::url('root/core/lib/Drupal/Core')]);
90     $this->layoutPluginManager = new LayoutPluginManager($namespaces, $this->cacheBackend->reveal(), $this->moduleHandler->reveal(), $this->themeHandler->reveal(), $this->getStringTranslationStub());
91   }
92
93   /**
94    * @covers ::getDefinitions
95    * @covers ::providerExists
96    */
97   public function testGetDefinitions() {
98     $expected = [
99       'module_a_provided_layout',
100       'theme_a_provided_layout',
101       'plugin_provided_layout',
102     ];
103
104     $layout_definitions = $this->layoutPluginManager->getDefinitions();
105     $this->assertEquals($expected, array_keys($layout_definitions));
106     $this->assertContainsOnlyInstancesOf(LayoutDefinition::class, $layout_definitions);
107   }
108
109   /**
110    * @covers ::getDefinition
111    * @covers ::processDefinition
112    */
113   public function testGetDefinition() {
114     $theme_a_path = vfsStream::url('root/themes/theme_a');
115     $layout_definition = $this->layoutPluginManager->getDefinition('theme_a_provided_layout');
116     $this->assertSame('theme_a_provided_layout', $layout_definition->id());
117     $this->assertSame('2 column layout', $layout_definition->getLabel());
118     $this->assertSame('Columns: 2', $layout_definition->getCategory());
119     $this->assertSame('twocol', $layout_definition->getTemplate());
120     $this->assertSame("$theme_a_path/templates", $layout_definition->getPath());
121     $this->assertSame('theme_a/twocol', $layout_definition->getLibrary());
122     $this->assertSame('twocol', $layout_definition->getThemeHook());
123     $this->assertSame("$theme_a_path/templates", $layout_definition->getTemplatePath());
124     $this->assertSame('theme_a', $layout_definition->getProvider());
125     $this->assertSame('right', $layout_definition->getDefaultRegion());
126     $this->assertSame(LayoutDefault::class, $layout_definition->getClass());
127     $expected_regions = [
128       'left' => [
129         'label' => 'Left region',
130       ],
131       'right' => [
132         'label' => 'Right region',
133       ],
134     ];
135     $this->assertSame($expected_regions, $layout_definition->getRegions());
136
137     $module_a_path = vfsStream::url('root/modules/module_a');
138     $layout_definition = $this->layoutPluginManager->getDefinition('module_a_provided_layout');
139     $this->assertSame('module_a_provided_layout', $layout_definition->id());
140     $this->assertSame('1 column layout', $layout_definition->getLabel());
141     $this->assertSame('Columns: 1', $layout_definition->getCategory());
142     $this->assertSame(NULL, $layout_definition->getTemplate());
143     $this->assertSame("$module_a_path/layouts", $layout_definition->getPath());
144     $this->assertSame('module_a/onecol', $layout_definition->getLibrary());
145     $this->assertSame('onecol', $layout_definition->getThemeHook());
146     $this->assertSame(NULL, $layout_definition->getTemplatePath());
147     $this->assertSame('module_a', $layout_definition->getProvider());
148     $this->assertSame('top', $layout_definition->getDefaultRegion());
149     $this->assertSame(LayoutDefault::class, $layout_definition->getClass());
150     $expected_regions = [
151       'top' => [
152         'label' => 'Top region',
153       ],
154       'bottom' => [
155         'label' => 'Bottom region',
156       ],
157     ];
158     $this->assertSame($expected_regions, $layout_definition->getRegions());
159
160     $core_path = '/core/lib/Drupal/Core';
161     $layout_definition = $this->layoutPluginManager->getDefinition('plugin_provided_layout');
162     $this->assertSame('plugin_provided_layout', $layout_definition->id());
163     $this->assertEquals('Layout plugin', $layout_definition->getLabel());
164     $this->assertEquals('Columns: 1', $layout_definition->getCategory());
165     $this->assertSame('plugin-provided-layout', $layout_definition->getTemplate());
166     $this->assertSame($core_path, $layout_definition->getPath());
167     $this->assertSame(NULL, $layout_definition->getLibrary());
168     $this->assertSame('plugin_provided_layout', $layout_definition->getThemeHook());
169     $this->assertSame("$core_path/templates", $layout_definition->getTemplatePath());
170     $this->assertSame('core', $layout_definition->getProvider());
171     $this->assertSame('main', $layout_definition->getDefaultRegion());
172     $this->assertSame('Drupal\Core\Plugin\Layout\TestLayout', $layout_definition->getClass());
173     $expected_regions = [
174       'main' => [
175         'label' => 'Main Region',
176       ],
177     ];
178     $this->assertEquals($expected_regions, $layout_definition->getRegions());
179   }
180
181   /**
182    * @covers ::processDefinition
183    */
184   public function testProcessDefinition() {
185     $this->moduleHandler->alter('layout', Argument::type('array'))->shouldNotBeCalled();
186     $this->setExpectedException(InvalidPluginDefinitionException::class, 'The "module_a_derived_layout:array_based" layout definition must extend ' . LayoutDefinition::class);
187     $module_a_provided_layout = <<<'EOS'
188 module_a_derived_layout:
189   deriver: \Drupal\Tests\Core\Layout\LayoutDeriver
190   array_based: true
191 EOS;
192     vfsStream::create([
193       'modules' => [
194         'module_a' => [
195           'module_a.layouts.yml' => $module_a_provided_layout,
196         ],
197       ],
198     ]);
199     $this->layoutPluginManager->getDefinitions();
200   }
201
202   /**
203    * @covers ::getThemeImplementations
204    */
205   public function testGetThemeImplementations() {
206     $core_path = '/core/lib/Drupal/Core';
207     $theme_a_path = vfsStream::url('root/themes/theme_a');
208     $expected = [
209       'layout' => [
210         'render element' => 'content',
211       ],
212       'twocol' => [
213         'render element' => 'content',
214         'base hook' => 'layout',
215         'template' => 'twocol',
216         'path' => "$theme_a_path/templates",
217       ],
218       'plugin_provided_layout' => [
219         'render element' => 'content',
220         'base hook' => 'layout',
221         'template' => 'plugin-provided-layout',
222         'path' => "$core_path/templates",
223       ],
224     ];
225     $theme_implementations = $this->layoutPluginManager->getThemeImplementations();
226     $this->assertEquals($expected, $theme_implementations);
227   }
228
229   /**
230    * @covers ::getCategories
231    */
232   public function testGetCategories() {
233     $expected = [
234       'Columns: 1',
235       'Columns: 2',
236     ];
237     $categories = $this->layoutPluginManager->getCategories();
238     $this->assertEquals($expected, $categories);
239   }
240
241   /**
242    * @covers ::getSortedDefinitions
243    */
244   public function testGetSortedDefinitions() {
245     $expected = [
246       'module_a_provided_layout',
247       'plugin_provided_layout',
248       'theme_a_provided_layout',
249     ];
250
251     $layout_definitions = $this->layoutPluginManager->getSortedDefinitions();
252     $this->assertEquals($expected, array_keys($layout_definitions));
253     $this->assertContainsOnlyInstancesOf(LayoutDefinition::class, $layout_definitions);
254   }
255
256   /**
257    * @covers ::getGroupedDefinitions
258    */
259   public function testGetGroupedDefinitions() {
260     $category_expected = [
261       'Columns: 1' => [
262         'module_a_provided_layout',
263         'plugin_provided_layout',
264       ],
265       'Columns: 2' => [
266         'theme_a_provided_layout',
267       ],
268     ];
269
270     $definitions = $this->layoutPluginManager->getGroupedDefinitions();
271     $this->assertEquals(array_keys($category_expected), array_keys($definitions));
272     foreach ($category_expected as $category => $expected) {
273       $this->assertArrayHasKey($category, $definitions);
274       $this->assertEquals($expected, array_keys($definitions[$category]));
275       $this->assertContainsOnlyInstancesOf(LayoutDefinition::class, $definitions[$category]);
276     }
277   }
278
279   /**
280    * Sets up the filesystem with YAML files and annotated plugins.
281    */
282   protected function setUpFilesystem() {
283     $module_a_provided_layout = <<<'EOS'
284 module_a_provided_layout:
285   label: 1 column layout
286   category: 'Columns: 1'
287   theme_hook: onecol
288   path: layouts
289   library: module_a/onecol
290   regions:
291     top:
292       label: Top region
293     bottom:
294       label: Bottom region
295 module_a_derived_layout:
296   deriver: \Drupal\Tests\Core\Layout\LayoutDeriver
297   invalid_provider: true
298 EOS;
299     $theme_a_provided_layout = <<<'EOS'
300 theme_a_provided_layout:
301   class: '\Drupal\Core\Layout\LayoutDefault'
302   label: 2 column layout
303   category: 'Columns: 2'
304   template: twocol
305   path: templates
306   library: theme_a/twocol
307   default_region: right
308   regions:
309     left:
310       label: Left region
311     right:
312       label: Right region
313 EOS;
314     $plugin_provided_layout = <<<'EOS'
315 <?php
316 namespace Drupal\Core\Plugin\Layout;
317 use Drupal\Core\Layout\LayoutDefault;
318 /**
319  * @Layout(
320  *   id = "plugin_provided_layout",
321  *   label = @Translation("Layout plugin"),
322  *   category = @Translation("Columns: 1"),
323  *   description = @Translation("Test layout"),
324  *   path = "core/lib/Drupal/Core",
325  *   template = "templates/plugin-provided-layout",
326  *   regions = {
327  *     "main" = {
328  *       "label" = @Translation("Main Region")
329  *     }
330  *   }
331  * )
332  */
333 class TestLayout extends LayoutDefault {}
334 EOS;
335     vfsStream::setup('root');
336     vfsStream::create([
337       'modules' => [
338         'module_a' => [
339           'module_a.layouts.yml' => $module_a_provided_layout,
340         ],
341       ],
342     ]);
343     vfsStream::create([
344       'themes' => [
345         'theme_a' => [
346           'theme_a.layouts.yml' => $theme_a_provided_layout,
347         ],
348       ],
349     ]);
350     vfsStream::create([
351       'core' => [
352         'lib' => [
353           'Drupal' => [
354             'Core' => [
355               'Plugin' => [
356                 'Layout' => [
357                   'TestLayout.php' => $plugin_provided_layout,
358                 ],
359               ],
360             ],
361           ],
362         ],
363       ],
364     ]);
365   }
366
367 }
368
369 /**
370  * Provides a dynamic layout deriver for the test.
371  */
372 class LayoutDeriver extends DeriverBase {
373
374   /**
375    * {@inheritdoc}
376    */
377   public function getDerivativeDefinitions($base_plugin_definition) {
378     if ($base_plugin_definition->get('array_based')) {
379       $this->derivatives['array_based'] = [];
380     }
381     if ($base_plugin_definition->get('invalid_provider')) {
382       $this->derivatives['invalid_provider'] = new LayoutDefinition([
383         'id' => 'invalid_provider',
384         'provider' => 'invalid_provider',
385       ]);
386     }
387     return $this->derivatives;
388   }
389
390 }