PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/core/lib/Drupal/Core/Entity/EntityTypeManager.php

http://github.com/drupal/drupal
PHP | 300 lines | 142 code | 40 blank | 118 comment | 16 complexity | 6e5e32663bd6a00d0940c174c9ad996e MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1
  1. <?php
  2. namespace Drupal\Core\Entity;
  3. use Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException;
  4. use Drupal\Component\Plugin\Exception\PluginNotFoundException;
  5. use Drupal\Core\Cache\CacheBackendInterface;
  6. use Drupal\Core\DependencyInjection\ClassResolverInterface;
  7. use Drupal\Core\Entity\Exception\InvalidLinkTemplateException;
  8. use Drupal\Core\Extension\ModuleHandlerInterface;
  9. use Drupal\Core\Plugin\DefaultPluginManager;
  10. use Drupal\Core\Plugin\Discovery\AnnotatedClassDiscovery;
  11. use Drupal\Core\StringTranslation\TranslationInterface;
  12. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  13. use Symfony\Component\DependencyInjection\ContainerAwareTrait;
  14. /**
  15. * Manages entity type plugin definitions.
  16. *
  17. * Each entity type definition array is set in the entity type's annotation and
  18. * altered by hook_entity_type_alter().
  19. *
  20. * Do not use hook_entity_type_alter() hook to add information to entity types,
  21. * unless one of the following is true:
  22. * - You are filling in default values.
  23. * - You need to dynamically add information only in certain circumstances.
  24. * - Your hook needs to run after hook_entity_type_build() implementations.
  25. * Use hook_entity_type_build() instead in all other cases.
  26. *
  27. * @see \Drupal\Core\Entity\Annotation\EntityType
  28. * @see \Drupal\Core\Entity\EntityInterface
  29. * @see \Drupal\Core\Entity\EntityTypeInterface
  30. * @see hook_entity_type_alter()
  31. * @see hook_entity_type_build()
  32. */
  33. class EntityTypeManager extends DefaultPluginManager implements EntityTypeManagerInterface, ContainerAwareInterface {
  34. use ContainerAwareTrait;
  35. /**
  36. * Contains instantiated handlers keyed by handler type and entity type.
  37. *
  38. * @var array
  39. */
  40. protected $handlers = [];
  41. /**
  42. * The string translation service.
  43. *
  44. * @var \Drupal\Core\StringTranslation\TranslationInterface
  45. */
  46. protected $stringTranslation;
  47. /**
  48. * The class resolver.
  49. *
  50. * @var \Drupal\Core\DependencyInjection\ClassResolverInterface
  51. */
  52. protected $classResolver;
  53. /**
  54. * The entity last installed schema repository.
  55. *
  56. * @var \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface
  57. */
  58. protected $entityLastInstalledSchemaRepository;
  59. /**
  60. * A list of entity type definitions that are active for the current request.
  61. *
  62. * @var \Drupal\Core\Entity\EntityTypeInterface[]
  63. */
  64. protected $activeDefinitions;
  65. /**
  66. * Constructs a new Entity plugin manager.
  67. *
  68. * @param \Traversable $namespaces
  69. * An object that implements \Traversable which contains the root paths
  70. * keyed by the corresponding namespace to look for plugin implementations,
  71. * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
  72. * The module handler.
  73. * @param \Drupal\Core\Cache\CacheBackendInterface $cache
  74. * The cache backend to use.
  75. * @param \Drupal\Core\StringTranslation\TranslationInterface $string_translation
  76. * The string translation.
  77. * @param \Drupal\Core\DependencyInjection\ClassResolverInterface $class_resolver
  78. * The class resolver.
  79. * @param \Drupal\Core\Entity\EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository
  80. * The entity last installed schema repository.
  81. */
  82. public function __construct(\Traversable $namespaces, ModuleHandlerInterface $module_handler, CacheBackendInterface $cache, TranslationInterface $string_translation, ClassResolverInterface $class_resolver, EntityLastInstalledSchemaRepositoryInterface $entity_last_installed_schema_repository) {
  83. parent::__construct('Entity', $namespaces, $module_handler, 'Drupal\Core\Entity\EntityInterface');
  84. $this->setCacheBackend($cache, 'entity_type', ['entity_types']);
  85. $this->alterInfo('entity_type');
  86. $this->discovery = new AnnotatedClassDiscovery('Entity', $namespaces, 'Drupal\Core\Entity\Annotation\EntityType');
  87. $this->stringTranslation = $string_translation;
  88. $this->classResolver = $class_resolver;
  89. $this->entityLastInstalledSchemaRepository = $entity_last_installed_schema_repository;
  90. }
  91. /**
  92. * {@inheritdoc}
  93. */
  94. public function processDefinition(&$definition, $plugin_id) {
  95. /** @var \Drupal\Core\Entity\EntityTypeInterface $definition */
  96. parent::processDefinition($definition, $plugin_id);
  97. // All link templates must have a leading slash.
  98. foreach ((array) $definition->getLinkTemplates() as $link_relation_name => $link_template) {
  99. if ($link_template[0] != '/') {
  100. throw new InvalidLinkTemplateException("Link template '$link_relation_name' for entity type '$plugin_id' must start with a leading slash, the current link template is '$link_template'");
  101. }
  102. }
  103. }
  104. /**
  105. * {@inheritdoc}
  106. */
  107. protected function findDefinitions() {
  108. $definitions = $this->getDiscovery()->getDefinitions();
  109. // Directly call the hook implementations to pass the definitions to them
  110. // by reference, so new entity types can be added.
  111. foreach ($this->moduleHandler->getImplementations('entity_type_build') as $module) {
  112. $function = $module . '_entity_type_build';
  113. $function($definitions);
  114. }
  115. foreach ($definitions as $plugin_id => $definition) {
  116. $this->processDefinition($definition, $plugin_id);
  117. }
  118. $this->alterDefinitions($definitions);
  119. return $definitions;
  120. }
  121. /**
  122. * {@inheritdoc}
  123. */
  124. public function getDefinition($entity_type_id, $exception_on_invalid = TRUE) {
  125. if (($entity_type = parent::getDefinition($entity_type_id, FALSE)) && class_exists($entity_type->getClass())) {
  126. return $entity_type;
  127. }
  128. elseif (!$exception_on_invalid) {
  129. return NULL;
  130. }
  131. throw new PluginNotFoundException($entity_type_id, sprintf('The "%s" entity type does not exist.', $entity_type_id));
  132. }
  133. /**
  134. * Gets the active definition for a content entity type.
  135. *
  136. * @param string $entity_type_id
  137. * The entity type ID.
  138. *
  139. * @return \Drupal\Core\Entity\EntityTypeInterface
  140. * The active entity type definition.
  141. *
  142. * @internal
  143. */
  144. public function getActiveDefinition($entity_type_id) {
  145. if (!isset($this->activeDefinitions[$entity_type_id])) {
  146. $this->activeDefinitions[$entity_type_id] = $this->entityLastInstalledSchemaRepository->getLastInstalledDefinition($entity_type_id);
  147. }
  148. return $this->activeDefinitions[$entity_type_id] ?: $this->getDefinition($entity_type_id);
  149. }
  150. /**
  151. * {@inheritdoc}
  152. */
  153. public function clearCachedDefinitions() {
  154. parent::clearCachedDefinitions();
  155. $this->activeDefinitions = [];
  156. $this->handlers = [];
  157. }
  158. /**
  159. * {@inheritdoc}
  160. */
  161. public function useCaches($use_caches = FALSE) {
  162. parent::useCaches($use_caches);
  163. if (!$use_caches) {
  164. $this->activeDefinitions = [];
  165. $this->handlers = [];
  166. $this->container->get('entity.memory_cache')->reset();
  167. }
  168. }
  169. /**
  170. * {@inheritdoc}
  171. */
  172. public function hasHandler($entity_type_id, $handler_type) {
  173. if ($definition = $this->getDefinition($entity_type_id, FALSE)) {
  174. return $definition->hasHandlerClass($handler_type);
  175. }
  176. return FALSE;
  177. }
  178. /**
  179. * {@inheritdoc}
  180. */
  181. public function getStorage($entity_type_id) {
  182. return $this->getHandler($entity_type_id, 'storage');
  183. }
  184. /**
  185. * {@inheritdoc}
  186. */
  187. public function getListBuilder($entity_type_id) {
  188. return $this->getHandler($entity_type_id, 'list_builder');
  189. }
  190. /**
  191. * {@inheritdoc}
  192. */
  193. public function getFormObject($entity_type_id, $operation) {
  194. if (!$class = $this->getDefinition($entity_type_id, TRUE)->getFormClass($operation)) {
  195. throw new InvalidPluginDefinitionException($entity_type_id, sprintf('The "%s" entity type did not specify a "%s" form class.', $entity_type_id, $operation));
  196. }
  197. $form_object = $this->classResolver->getInstanceFromDefinition($class);
  198. return $form_object
  199. ->setStringTranslation($this->stringTranslation)
  200. ->setModuleHandler($this->moduleHandler)
  201. ->setEntityTypeManager($this)
  202. ->setOperation($operation);
  203. }
  204. /**
  205. * {@inheritdoc}
  206. */
  207. public function getRouteProviders($entity_type_id) {
  208. if (!isset($this->handlers['route_provider'][$entity_type_id])) {
  209. $route_provider_classes = $this->getDefinition($entity_type_id, TRUE)->getRouteProviderClasses();
  210. foreach ($route_provider_classes as $type => $class) {
  211. $this->handlers['route_provider'][$entity_type_id][$type] = $this->createHandlerInstance($class, $this->getDefinition($entity_type_id));
  212. }
  213. }
  214. return isset($this->handlers['route_provider'][$entity_type_id]) ? $this->handlers['route_provider'][$entity_type_id] : [];
  215. }
  216. /**
  217. * {@inheritdoc}
  218. */
  219. public function getViewBuilder($entity_type_id) {
  220. return $this->getHandler($entity_type_id, 'view_builder');
  221. }
  222. /**
  223. * {@inheritdoc}
  224. */
  225. public function getAccessControlHandler($entity_type_id) {
  226. return $this->getHandler($entity_type_id, 'access');
  227. }
  228. /**
  229. * {@inheritdoc}
  230. */
  231. public function getHandler($entity_type_id, $handler_type) {
  232. if (!isset($this->handlers[$handler_type][$entity_type_id])) {
  233. $definition = $this->getDefinition($entity_type_id);
  234. $class = $definition->getHandlerClass($handler_type);
  235. if (!$class) {
  236. throw new InvalidPluginDefinitionException($entity_type_id, sprintf('The "%s" entity type did not specify a %s handler.', $entity_type_id, $handler_type));
  237. }
  238. $this->handlers[$handler_type][$entity_type_id] = $this->createHandlerInstance($class, $definition);
  239. }
  240. return $this->handlers[$handler_type][$entity_type_id];
  241. }
  242. /**
  243. * {@inheritdoc}
  244. */
  245. public function createHandlerInstance($class, EntityTypeInterface $definition = NULL) {
  246. if (is_subclass_of($class, 'Drupal\Core\Entity\EntityHandlerInterface')) {
  247. $handler = $class::createInstance($this->container, $definition);
  248. }
  249. else {
  250. $handler = new $class($definition);
  251. }
  252. if (method_exists($handler, 'setModuleHandler')) {
  253. $handler->setModuleHandler($this->moduleHandler);
  254. }
  255. if (method_exists($handler, 'setStringTranslation')) {
  256. $handler->setStringTranslation($this->stringTranslation);
  257. }
  258. return $handler;
  259. }
  260. }