Security update for Core, with self-updated composer
[yaffs-website] / web / core / tests / Drupal / Tests / Core / Entity / Routing / DefaultHtmlRouteProviderTest.php
1 <?php
2
3 /**
4  * @file
5  * Contains \Drupal\Tests\Core\Entity\Routing\DefaultHtmlRouteProviderTest.
6  */
7
8 namespace Drupal\Tests\Core\Entity\Routing;
9
10 use Drupal\Core\Config\Entity\ConfigEntityTypeInterface;
11 use Drupal\Core\Entity\EntityFieldManagerInterface;
12 use Drupal\Core\Entity\EntityTypeInterface;
13 use Drupal\Core\Entity\EntityTypeManagerInterface;
14 use Drupal\Core\Entity\FieldableEntityInterface;
15 use Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider;
16 use Drupal\Core\Field\FieldStorageDefinitionInterface;
17 use Drupal\Core\StringTranslation\TranslatableMarkup;
18 use Drupal\Tests\UnitTestCase;
19 use Prophecy\Argument;
20 use Prophecy\Prophecy\ObjectProphecy;
21 use Symfony\Component\Routing\Route;
22
23 /**
24  * @coversDefaultClass \Drupal\Core\Entity\Routing\DefaultHtmlRouteProvider
25  * @group Entity
26  */
27 class DefaultHtmlRouteProviderTest extends UnitTestCase {
28
29   /**
30    * The entity type manager prophecy used in the test.
31    *
32    * @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityTypeManagerInterface
33    */
34   protected $entityTypeManager;
35
36   /**
37    * The entity field manager prophecy used in the test.
38    *
39    * @var \Prophecy\Prophecy\ProphecyInterface|\Drupal\Core\Entity\EntityFieldManagerInterface
40    */
41   protected $entityFieldManager;
42
43   /**
44    * The HTML route provider used in the test.
45    *
46    * @var \Drupal\Tests\Core\Entity\Routing\TestDefaultHtmlRouteProvider
47    */
48   protected $routeProvider;
49
50   /**
51    * {@inheritdoc}
52    */
53   protected function setUp() {
54     parent::setUp();
55
56     $this->entityTypeManager = $this->prophesize(EntityTypeManagerInterface::class);
57     $this->entityFieldManager = $this->prophesize(EntityFieldManagerInterface::class);
58
59     $this->routeProvider = new TestDefaultHtmlRouteProvider($this->entityTypeManager->reveal(), $this->entityFieldManager->reveal());
60   }
61
62   /**
63    * @covers ::getAddPageRoute
64    * @dataProvider providerTestGetAddPageRoute
65    */
66   public function testGetAddPageRoute(Route $expected = NULL, EntityTypeInterface $entity_type) {
67     $route = $this->routeProvider->getAddPageRoute($entity_type);
68     $this->assertEquals($expected, $route);
69   }
70
71   public function providerTestGetAddPageRoute() {
72     $data = [];
73
74     $entity_type1 = $this->getEntityType();
75     $entity_type1->hasLinkTemplate('add-page')->willReturn(FALSE);
76     $data['no_add_page_link_template'] = [NULL, $entity_type1->reveal()];
77
78     $entity_type2 = $this->getEntityType();
79     $entity_type2->hasLinkTemplate('add-page')->willReturn(TRUE);
80     $entity_type2->getKey('bundle')->willReturn(NULL);
81     $data['no_bundle'] = [NULL, $entity_type2->reveal()];
82
83     $entity_type3 = $this->getEntityType();
84     $entity_type3->hasLinkTemplate('add-page')->willReturn(TRUE);
85     $entity_type3->getLinkTemplate('add-page')->willReturn('/the/add/page/link/template');
86     $entity_type3->id()->willReturn('the_entity_type_id');
87     $entity_type3->getKey('bundle')->willReturn('type');
88     $route = new Route('/the/add/page/link/template');
89     $route->setDefaults([
90       '_controller' => 'Drupal\Core\Entity\Controller\EntityController::addPage',
91       '_title_callback' => 'Drupal\Core\Entity\Controller\EntityController::addTitle',
92       'entity_type_id' => 'the_entity_type_id',
93     ]);
94     $route->setRequirement('_entity_create_any_access', 'the_entity_type_id');
95     $data['add_page'] = [clone $route, $entity_type3->reveal()];
96
97     return $data;
98   }
99
100   /**
101    * @covers ::getAddFormRoute
102    * @dataProvider providerTestGetAddFormRoute
103    */
104   public function testGetAddFormRoute(Route $expected = NULL, EntityTypeInterface $entity_type, EntityTypeInterface $bundle_entity_type = NULL, FieldStorageDefinitionInterface $field_storage_definition = NULL) {
105     if ($bundle_entity_type) {
106       $this->entityTypeManager->getDefinition('the_bundle_entity_type_id')->willReturn($bundle_entity_type);
107
108       if ($field_storage_definition) {
109         $this->entityFieldManager->getFieldStorageDefinitions('the_bundle_entity_type_id')
110           ->willReturn(['id' => $field_storage_definition]);
111       }
112     }
113
114     $route = $this->routeProvider->getAddFormRoute($entity_type);
115     $this->assertEquals($expected, $route);
116   }
117
118   public function providerTestGetAddFormRoute() {
119     $data = [];
120
121     $entity_type1 = $this->getEntityType();
122     $entity_type1->hasLinkTemplate('add-form')->willReturn(FALSE);
123
124     $data['no_add_form_link_template'] = [NULL, $entity_type1->reveal()];
125
126     $entity_type2 = $this->getEntityType();
127     $entity_type2->getBundleEntityType()->willReturn(NULL);
128     $entity_type2->hasLinkTemplate('add-form')->willReturn(TRUE);
129     $entity_type2->id()->willReturn('the_entity_type_id');
130     $entity_type2->getLinkTemplate('add-form')->willReturn('/the/add/form/link/template');
131     $entity_type2->getFormClass('add')->willReturn(NULL);
132     $entity_type2->getKey('bundle')->willReturn(NULL);
133     $route = (new Route('/the/add/form/link/template'))
134       ->setDefaults([
135         '_entity_form' => 'the_entity_type_id.default',
136         'entity_type_id' => 'the_entity_type_id',
137         '_title_callback' => 'Drupal\Core\Entity\Controller\EntityController::addTitle',
138       ])
139       ->setRequirement('_entity_create_access', 'the_entity_type_id');
140     $data['no_add_form_no_bundle'] = [clone $route, $entity_type2->reveal()];
141
142     $entity_type3 = $this->getEntityType($entity_type2);
143     $entity_type3->getFormClass('add')->willReturn('Drupal\Core\Entity\EntityForm');
144     $route->setDefault('_entity_form', 'the_entity_type_id.add');
145     $data['add_form_no_bundle'] = [clone $route, $entity_type3->reveal()];
146
147     $entity_type4 = $this->getEntityType($entity_type3);
148     $entity_type4->getKey('bundle')->willReturn('the_bundle_key');
149     $entity_type4->getBundleEntityType()->willReturn(NULL);
150     $entity_type4->getLinkTemplate('add-form')->willReturn('/the/add/form/link/template/{the_bundle_key}');
151     $route->setPath('/the/add/form/link/template/{the_bundle_key}');
152     $route
153       ->setDefault('_title_callback', 'Drupal\Core\Entity\Controller\EntityController::addBundleTitle')
154       ->setDefault('bundle_parameter', 'the_bundle_key')
155       ->setRequirement('_entity_create_access', 'the_entity_type_id:{the_bundle_key}');
156     $data['add_form_bundle_static'] = [clone $route, $entity_type4->reveal()];
157
158     $entity_type5 = $this->getEntityType($entity_type4);
159     $entity_type5->getBundleEntityType()->willReturn('the_bundle_entity_type_id');
160     $entity_type5->getLinkTemplate('add-form')->willReturn('/the/add/form/link/template/{the_bundle_entity_type_id}');
161     $bundle_entity_type = $this->getEntityType();
162     $bundle_entity_type->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
163     $route->setPath('/the/add/form/link/template/{the_bundle_entity_type_id}');
164     $route
165       ->setDefault('bundle_parameter', 'the_bundle_entity_type_id')
166       ->setRequirement('_entity_create_access', 'the_entity_type_id:{the_bundle_entity_type_id}')
167       ->setOption('parameters', [
168         'the_bundle_entity_type_id' => [
169           'type' => 'entity:the_bundle_entity_type_id',
170         ],
171       ]);
172     $data['add_form_bundle_entity_id_key_type_null'] = [clone $route, $entity_type5->reveal(), $bundle_entity_type->reveal()];
173
174     $entity_type6 = $this->getEntityType($entity_type5);
175     $bundle_entity_type = $this->getEntityType();
176     $bundle_entity_type->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
177     $field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
178     $field_storage_definition->getType()->willReturn('integer');
179     $route->setRequirement('the_entity_type_id', '\d+');
180     $data['add_form_bundle_entity_id_key_type_integer'] = [clone $route, $entity_type6->reveal(), $bundle_entity_type->reveal(), $field_storage_definition->reveal()];
181
182     $entity_type7 = $this->getEntityType($entity_type6);
183     $bundle_entity_type = $this->prophesize(ConfigEntityTypeInterface::class);
184     $bundle_entity_type->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
185     $field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
186     $route
187       // Unset the 'the_entity_type_id' requirement.
188       ->setRequirements(['_entity_create_access' => $route->getRequirement('_entity_create_access')])
189       ->setOption('parameters', [
190         'the_bundle_entity_type_id' => [
191           'type' => 'entity:the_bundle_entity_type_id',
192           'with_config_overrides' => TRUE,
193         ],
194       ]);
195     $data['add_form_bundle_entity_id_key_type_integer'] = [clone $route, $entity_type7->reveal(), $bundle_entity_type->reveal(), $field_storage_definition->reveal()];
196
197     return $data;
198   }
199
200   /**
201    * @covers ::getCanonicalRoute
202    * @dataProvider providerTestGetCanonicalRoute
203    */
204   public function testGetCanonicalRoute(Route $expected = NULL, EntityTypeInterface $entity_type, FieldStorageDefinitionInterface $field_storage_definition = NULL) {
205     if ($field_storage_definition) {
206       $this->entityFieldManager->getFieldStorageDefinitions($entity_type->id())
207         ->willReturn([$entity_type->getKey('id') => $field_storage_definition]);
208     }
209
210     $route = $this->routeProvider->getCanonicalRoute($entity_type);
211     $this->assertEquals($expected, $route);
212   }
213
214   public function providerTestGetCanonicalRoute() {
215     $data = [];
216
217     $entity_type1 = $this->getEntityType();
218     $entity_type1->hasLinkTemplate('canonical')->willReturn(FALSE);
219     $data['no_canonical_link_template'] = [NULL, $entity_type1->reveal()];
220
221     $entity_type2 = $this->getEntityType();;
222     $entity_type2->hasLinkTemplate('canonical')->willReturn(TRUE);
223     $entity_type2->hasViewBuilderClass()->willReturn(FALSE);
224     $data['no_view_builder'] = [NULL, $entity_type2->reveal()];
225
226     $entity_type3 = $this->getEntityType($entity_type2);
227     $entity_type3->hasViewBuilderClass()->willReturn(TRUE);
228     $entity_type3->id()->willReturn('the_entity_type_id');
229     $entity_type3->getLinkTemplate('canonical')->willReturn('/the/canonical/link/template');
230     $entity_type3->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
231     $route = (new Route('/the/canonical/link/template'))
232       ->setDefaults([
233         '_entity_view' => 'the_entity_type_id.full',
234         '_title_callback' => '\Drupal\Core\Entity\Controller\EntityController::title',
235       ])
236       ->setRequirements([
237         '_entity_access' => 'the_entity_type_id.view',
238       ])
239       ->setOptions([
240         'parameters' => [
241           'the_entity_type_id' => [
242             'type' => 'entity:the_entity_type_id',
243           ],
244         ],
245       ]);
246     $data['id_key_type_null'] = [clone $route, $entity_type3->reveal()];
247
248     $entity_type4 = $this->getEntityType($entity_type3);
249     $entity_type4->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
250     $entity_type4->getKey('id')->willReturn('id');
251     $route->setRequirement('the_entity_type_id', '\d+');
252     $field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
253     $field_storage_definition->getType()->willReturn('integer');
254     $data['id_key_type_integer'] = [clone $route, $entity_type4->reveal(), $field_storage_definition->reveal()];
255
256     return $data;
257   }
258
259   /**
260    * @covers ::getCollectionRoute
261    * @dataProvider providerTestGetCollectionRoute
262    */
263   public function testGetCollectionRoute(Route $expected = NULL, EntityTypeInterface $entity_type) {
264     $route = $this->routeProvider->getCollectionRoute($entity_type);
265     $this->assertEquals($expected, $route);
266   }
267
268   public function providerTestGetCollectionRoute() {
269     $data = [];
270
271     $entity_type1 = $this->getEntityType();
272     $entity_type1->hasLinkTemplate('collection')->willReturn(FALSE);
273     $data['no_collection_link_template'] = [NULL, $entity_type1->reveal()];
274
275     $entity_type2 = $this->getEntityType();
276     $entity_type2->hasLinkTemplate('collection')->willReturn(TRUE);
277     $entity_type2->hasListBuilderClass()->willReturn(FALSE);
278     $data['no_list_builder'] = [NULL, $entity_type2->reveal()];
279
280     $entity_type3 = $this->getEntityType($entity_type2);
281     $entity_type3->hasListBuilderClass()->willReturn(TRUE);
282     $entity_type3->getAdminPermission()->willReturn(FALSE);
283     $data['no_admin_permission'] = [NULL, $entity_type3->reveal()];
284
285     $entity_type4 = $this->getEntityType($entity_type3);
286     $entity_type4->getAdminPermission()->willReturn('administer the entity type');
287     $entity_type4->id()->willReturn('the_entity_type_id');
288     $entity_type4->getLabel()->willReturn('The entity type');
289     $entity_type4->getCollectionLabel()->willReturn(new TranslatableMarkup('Test entities'));
290     $entity_type4->getLinkTemplate('collection')->willReturn('/the/collection/link/template');
291     $entity_type4->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
292     $route = (new Route('/the/collection/link/template'))
293       ->setDefaults([
294         '_entity_list' => 'the_entity_type_id',
295         '_title' => 'Test entities',
296         '_title_arguments' => [],
297         '_title_context' => '',
298       ])
299       ->setRequirements([
300         '_permission' => 'administer the entity type',
301       ]);
302     $data['collection_route'] = [clone $route, $entity_type4->reveal()];
303
304     return $data;
305   }
306
307   /**
308    * @covers ::getEntityTypeIdKeyType
309    */
310   public function testGetEntityTypeIdKeyType() {
311     $entity_type = $this->prophesize(EntityTypeInterface::class);
312     $entity_type->entityClassImplements(FieldableEntityInterface::class)->willReturn(TRUE);
313     $entity_type->id()->willReturn('the_entity_type_id');
314     $entity_type->getKey('id')->willReturn('id');
315
316     $field_storage_definition = $this->prophesize(FieldStorageDefinitionInterface::class);
317     $field_storage_definition->getType()->willReturn('integer');
318     $this->entityFieldManager->getFieldStorageDefinitions('the_entity_type_id')->willReturn(['id' => $field_storage_definition]);
319
320     $type = $this->routeProvider->getEntityTypeIdKeyType($entity_type->reveal());
321     $this->assertSame('integer', $type);
322   }
323
324   /**
325    * @covers ::getEntityTypeIdKeyType
326    */
327   public function testGetEntityTypeIdKeyTypeNotFieldable() {
328     $entity_type = $this->prophesize(EntityTypeInterface::class);
329     $entity_type->entityClassImplements(FieldableEntityInterface::class)->willReturn(FALSE);
330     $this->entityFieldManager->getFieldStorageDefinitions(Argument::any())->shouldNotBeCalled();
331
332     $type = $this->routeProvider->getEntityTypeIdKeyType($entity_type->reveal());
333     $this->assertNull($type);
334   }
335
336   /**
337    * @param \Prophecy\Prophecy\ObjectProphecy $base_entity_type
338    * @return \Prophecy\Prophecy\ObjectProphecy
339    */
340   protected function getEntityType(ObjectProphecy $base_entity_type = NULL) {
341     $entity_type = $this->prophesize(EntityTypeInterface::class);
342     if ($base_entity_type) {
343       foreach ($base_entity_type->getMethodProphecies() as $method => $prophecies) {
344         foreach ($prophecies as $prophecy) {
345           $entity_type->addMethodProphecy(clone $prophecy);
346         }
347       }
348     }
349     return $entity_type;
350   }
351
352 }
353
354 class TestDefaultHtmlRouteProvider extends DefaultHtmlRouteProvider {
355
356   public function getEntityTypeIdKeyType(EntityTypeInterface $entity_type) {
357     return parent::getEntityTypeIdKeyType($entity_type);
358   }
359   public function getAddPageRoute(EntityTypeInterface $entity_type) {
360     return parent::getAddPageRoute($entity_type);
361   }
362   public function getAddFormRoute(EntityTypeInterface $entity_type) {
363     return parent::getAddFormRoute($entity_type);
364   }
365   public function getCanonicalRoute(EntityTypeInterface $entity_type) {
366     return parent::getCanonicalRoute($entity_type);
367   }
368   public function getCollectionRoute(EntityTypeInterface $entity_type) {
369     return parent::getCollectionRoute($entity_type);
370   }
371
372 }