/web/core/modules/field/tests/src/Kernel/FieldDefinitionIntegrityTest.php

https://gitlab.com/mohamed_hussein/prodt · PHP · 191 lines · 98 code · 28 blank · 65 comment · 8 complexity · 458a265ef637b548e6fe1e2ac52bff96 MD5 · raw file

  1. <?php
  2. namespace Drupal\Tests\field\Kernel;
  3. use Drupal\Component\Plugin\Discovery\DiscoveryInterface;
  4. use Drupal\Component\Utility\NestedArray;
  5. use Drupal\Core\Entity\ContentEntityTypeInterface;
  6. use Drupal\Core\Entity\EntityTypeInterface;
  7. use Drupal\Core\Extension\Extension;
  8. use Drupal\Core\Field\BaseFieldDefinition;
  9. use Drupal\KernelTests\KernelTestBase;
  10. /**
  11. * Tests the integrity of field API plugin definitions.
  12. *
  13. * @group field
  14. */
  15. class FieldDefinitionIntegrityTest extends KernelTestBase {
  16. /**
  17. * @var array
  18. */
  19. protected static $modules = ['system', 'path_alias'];
  20. /**
  21. * Tests the integrity of field plugin definitions.
  22. */
  23. public function testFieldPluginDefinitionIntegrity() {
  24. // Enable all core modules that provide field plugins, and their
  25. // dependencies.
  26. $this->enableModules(
  27. $this->modulesWithSubdirectory(
  28. 'src' . DIRECTORY_SEPARATOR . 'Plugin' . DIRECTORY_SEPARATOR . 'Field'
  29. )
  30. );
  31. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  32. $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
  33. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  34. $field_formatter_manager = \Drupal::service('plugin.manager.field.formatter');
  35. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  36. $field_widget_manager = \Drupal::service('plugin.manager.field.widget');
  37. // Load the IDs of all available field type plugins.
  38. $available_field_type_ids = [];
  39. foreach ($field_type_manager->getDefinitions() as $definition) {
  40. $available_field_type_ids[] = $definition['id'];
  41. }
  42. // Load the IDs of all available field widget plugins.
  43. $available_field_widget_ids = [];
  44. foreach ($field_widget_manager->getDefinitions() as $definition) {
  45. $available_field_widget_ids[] = $definition['id'];
  46. }
  47. // Load the IDs of all available field formatter plugins.
  48. $available_field_formatter_ids = [];
  49. foreach ($field_formatter_manager->getDefinitions() as $definition) {
  50. $available_field_formatter_ids[] = $definition['id'];
  51. }
  52. // Test the field type plugins.
  53. foreach ($field_type_manager->getDefinitions() as $definition) {
  54. // Test default field widgets.
  55. if (isset($definition['default_widget'])) {
  56. $this->assertContains($definition['default_widget'], $available_field_widget_ids, sprintf('Field type %s uses a non-existent field widget by default: %s', $definition['id'], $definition['default_widget']));
  57. }
  58. // Test default field formatters.
  59. if (isset($definition['default_formatter'])) {
  60. $this->assertContains($definition['default_formatter'], $available_field_formatter_ids, sprintf('Field type %s uses a non-existent field formatter by default: %s', $definition['id'], $definition['default_formatter']));
  61. }
  62. }
  63. // Test the field widget plugins.
  64. foreach ($field_widget_manager->getDefinitions() as $definition) {
  65. $missing_field_type_ids = array_diff($definition['field_types'], $available_field_type_ids);
  66. $this->assertEmpty($missing_field_type_ids, sprintf('Field widget %s integrates with non-existent field types: %s', $definition['id'], implode(', ', $missing_field_type_ids)));
  67. }
  68. // Test the field formatter plugins.
  69. foreach ($field_formatter_manager->getDefinitions() as $definition) {
  70. $missing_field_type_ids = array_diff($definition['field_types'], $available_field_type_ids);
  71. $this->assertEmpty($missing_field_type_ids, sprintf('Field formatter %s integrates with non-existent field types: %s', $definition['id'], implode(', ', $missing_field_type_ids)));
  72. }
  73. }
  74. /**
  75. * Tests to load field plugin definitions used in core's existing entities.
  76. */
  77. public function testFieldPluginDefinitionAvailability() {
  78. $this->enableModules(
  79. $this->modulesWithSubdirectory('src' . DIRECTORY_SEPARATOR . 'Entity')
  80. );
  81. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  82. $field_formatter_manager = $this->container->get('plugin.manager.field.formatter');
  83. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  84. $field_widget_manager = $this->container->get('plugin.manager.field.widget');
  85. /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
  86. $entity_field_manager = $this->container->get('entity_field.manager');
  87. /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
  88. $entity_type_manager = $this->container->get('entity_type.manager');
  89. /** @var \Drupal\Core\Field\BaseFieldDefinition[][] $field_definitions */
  90. $field_definitions = [];
  91. /** @var \Drupal\Core\Entity\EntityTypeInterface[] $content_entity_types */
  92. $content_entity_types = array_filter($entity_type_manager->getDefinitions(), function (EntityTypeInterface $entity_type) {
  93. return $entity_type instanceof ContentEntityTypeInterface;
  94. });
  95. foreach ($content_entity_types as $entity_type_id => $entity_type_definition) {
  96. $field_definitions[$entity_type_id] = $entity_field_manager->getBaseFieldDefinitions($entity_type_id);
  97. }
  98. foreach ($field_definitions as $entity_type_id => $definitions) {
  99. foreach ($definitions as $field_id => $field_definition) {
  100. $this->checkDisplayOption($entity_type_id, $field_id, $field_definition, $field_formatter_manager, 'view');
  101. $this->checkDisplayOption($entity_type_id, $field_id, $field_definition, $field_widget_manager, 'form');
  102. }
  103. }
  104. }
  105. /**
  106. * Helper method that tries to load plugin definitions.
  107. *
  108. * @param string $entity_type_id
  109. * Id of entity type. Required by message.
  110. * @param string $field_id
  111. * Id of field. Required by message.
  112. * @param \Drupal\Core\Field\BaseFieldDefinition $field_definition
  113. * Field definition that provide display options.
  114. * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $plugin_manager
  115. * Plugin manager that will try to provide plugin definition.
  116. * @param string $display_context
  117. * Defines which display options should be loaded.
  118. */
  119. protected function checkDisplayOption($entity_type_id, $field_id, BaseFieldDefinition $field_definition, DiscoveryInterface $plugin_manager, $display_context) {
  120. $display_options = $field_definition->getDisplayOptions($display_context);
  121. if (!empty($display_options['type'])) {
  122. $plugin = $plugin_manager->getDefinition($display_options['type'], FALSE);
  123. $this->assertNotNull($plugin, sprintf(
  124. 'Plugin found for "%s" field %s display options of "%s" entity type.',
  125. $field_id,
  126. $display_context,
  127. $entity_type_id)
  128. );
  129. }
  130. }
  131. /**
  132. * Find modules with a specified subdirectory.
  133. *
  134. * @param string $subdirectory
  135. * The required path, relative to the module directory.
  136. *
  137. * @return string[]
  138. * A list of module names satisfying these criteria:
  139. * - provided by core
  140. * - not hidden
  141. * - not already enabled
  142. * - not in the Testing package
  143. * - containing the required $subdirectory
  144. * and all modules required by any of these modules.
  145. */
  146. protected function modulesWithSubdirectory($subdirectory) {
  147. $modules = \Drupal::service('extension.list.module')->getList();
  148. $modules = array_filter($modules, function (Extension $module) use ($subdirectory) {
  149. // Filter contrib, hidden, already enabled modules and modules in the
  150. // Testing package.
  151. return ($module->origin === 'core'
  152. && empty($module->info['hidden'])
  153. && $module->status == FALSE
  154. && $module->info['package'] !== 'Testing'
  155. && is_readable($module->getPath() . DIRECTORY_SEPARATOR . $subdirectory));
  156. });
  157. // Gather the dependencies of the modules.
  158. $dependencies = NestedArray::mergeDeepArray(array_map(function (Extension $module) {
  159. return array_keys($module->requires);
  160. }, $modules));
  161. return array_unique(NestedArray::mergeDeep(array_keys($modules), $dependencies));
  162. }
  163. }