PageRenderTime 39ms CodeModel.GetById 12ms RepoModel.GetById 1ms app.codeStats 0ms

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

http://github.com/drupal/drupal
PHP | 212 lines | 118 code | 29 blank | 65 comment | 16 complexity | 61ac37755103f4e0fc52a4cb9d007681 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  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. public static $modules = ['system'];
  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. if (in_array($definition['default_widget'], $available_field_widget_ids)) {
  57. $this->pass(sprintf('Field type %s uses an existing field widget by default.', $definition['id']));
  58. }
  59. else {
  60. $this->fail(sprintf('Field type %s uses a non-existent field widget by default: %s', $definition['id'], $definition['default_widget']));
  61. }
  62. }
  63. // Test default field formatters.
  64. if (isset($definition['default_formatter'])) {
  65. if (in_array($definition['default_formatter'], $available_field_formatter_ids)) {
  66. $this->pass(sprintf('Field type %s uses an existing field formatter by default.', $definition['id']));
  67. }
  68. else {
  69. $this->fail(sprintf('Field type %s uses a non-existent field formatter by default: %s', $definition['id'], $definition['default_formatter']));
  70. }
  71. }
  72. }
  73. // Test the field widget plugins.
  74. foreach ($field_widget_manager->getDefinitions() as $definition) {
  75. $missing_field_type_ids = array_diff($definition['field_types'], $available_field_type_ids);
  76. if ($missing_field_type_ids) {
  77. $this->fail(sprintf('Field widget %s integrates with non-existent field types: %s', $definition['id'], implode(', ', $missing_field_type_ids)));
  78. }
  79. else {
  80. $this->pass(sprintf('Field widget %s integrates with existing field types.', $definition['id']));
  81. }
  82. }
  83. // Test the field formatter plugins.
  84. foreach ($field_formatter_manager->getDefinitions() as $definition) {
  85. $missing_field_type_ids = array_diff($definition['field_types'], $available_field_type_ids);
  86. if ($missing_field_type_ids) {
  87. $this->fail(sprintf('Field formatter %s integrates with non-existent field types: %s', $definition['id'], implode(', ', $missing_field_type_ids)));
  88. }
  89. else {
  90. $this->pass(sprintf('Field formatter %s integrates with existing field types.', $definition['id']));
  91. }
  92. }
  93. }
  94. /**
  95. * Tests to load field plugin definitions used in core's existing entities.
  96. */
  97. public function testFieldPluginDefinitionAvailability() {
  98. $this->enableModules(
  99. $this->modulesWithSubdirectory('src' . DIRECTORY_SEPARATOR . 'Entity')
  100. );
  101. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  102. $field_formatter_manager = $this->container->get('plugin.manager.field.formatter');
  103. /** @var \Drupal\Component\Plugin\Discovery\DiscoveryInterface $field_type_manager */
  104. $field_widget_manager = $this->container->get('plugin.manager.field.widget');
  105. /** @var \Drupal\Core\Entity\EntityFieldManagerInterface $entity_field_manager */
  106. $entity_field_manager = $this->container->get('entity_field.manager');
  107. /** @var \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager */
  108. $entity_type_manager = $this->container->get('entity_type.manager');
  109. /** @var \Drupal\Core\Field\BaseFieldDefinition[][] $field_definitions */
  110. $field_definitions = [];
  111. /** @var \Drupal\Core\Entity\EntityTypeInterface[] $content_entity_types */
  112. $content_entity_types = array_filter($entity_type_manager->getDefinitions(), function (EntityTypeInterface $entity_type) {
  113. return $entity_type instanceof ContentEntityTypeInterface;
  114. });
  115. foreach ($content_entity_types as $entity_type_id => $entity_type_definition) {
  116. $field_definitions[$entity_type_id] = $entity_field_manager->getBaseFieldDefinitions($entity_type_id);
  117. }
  118. foreach ($field_definitions as $entity_type_id => $definitions) {
  119. foreach ($definitions as $field_id => $field_definition) {
  120. $this->checkDisplayOption($entity_type_id, $field_id, $field_definition, $field_formatter_manager, 'view');
  121. $this->checkDisplayOption($entity_type_id, $field_id, $field_definition, $field_widget_manager, 'form');
  122. }
  123. }
  124. }
  125. /**
  126. * Helper method that tries to load plugin definitions.
  127. *
  128. * @param string $entity_type_id
  129. * Id of entity type. Required by message.
  130. * @param string $field_id
  131. * Id of field. Required by message.
  132. * @param \Drupal\Core\Field\BaseFieldDefinition $field_definition
  133. * Field definition that provide display options.
  134. * @param \Drupal\Component\Plugin\Discovery\DiscoveryInterface $plugin_manager
  135. * Plugin manager that will try to provide plugin definition.
  136. * @param string $display_context
  137. * Defines which display options should be loaded.
  138. */
  139. protected function checkDisplayOption($entity_type_id, $field_id, BaseFieldDefinition $field_definition, DiscoveryInterface $plugin_manager, $display_context) {
  140. $display_options = $field_definition->getDisplayOptions($display_context);
  141. if (!empty($display_options['type'])) {
  142. $plugin = $plugin_manager->getDefinition($display_options['type'], FALSE);
  143. $this->assertNotNull($plugin, sprintf(
  144. 'Plugin found for "%s" field %s display options of "%s" entity type.',
  145. $field_id,
  146. $display_context,
  147. $entity_type_id)
  148. );
  149. }
  150. }
  151. /**
  152. * Find modules with a specified subdirectory.
  153. *
  154. * @param string $subdirectory
  155. * The required path, relative to the module directory.
  156. *
  157. * @return string[]
  158. * A list of module names satisfying these criteria:
  159. * - provided by core
  160. * - not hidden
  161. * - not already enabled
  162. * - not in the Testing package
  163. * - containing the required $subdirectory
  164. * and all modules required by any of these modules.
  165. */
  166. protected function modulesWithSubdirectory($subdirectory) {
  167. $modules = \Drupal::service('extension.list.module')->getList();
  168. $modules = array_filter($modules, function (Extension $module) use ($subdirectory) {
  169. // Filter contrib, hidden, already enabled modules and modules in the
  170. // Testing package.
  171. return ($module->origin === 'core'
  172. && empty($module->info['hidden'])
  173. && $module->status == FALSE
  174. && $module->info['package'] !== 'Testing'
  175. && is_readable($module->getPath() . DIRECTORY_SEPARATOR . $subdirectory));
  176. });
  177. // Gather the dependencies of the modules.
  178. $dependencies = NestedArray::mergeDeepArray(array_map(function (Extension $module) {
  179. return array_keys($module->requires);
  180. }, $modules));
  181. return array_unique(NestedArray::mergeDeep(array_keys($modules), $dependencies));
  182. }
  183. }