PageRenderTime 25ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://bitbucket.org/aswinvk28/smartpan-stock-drupal
PHP | 293 lines | 137 code | 34 blank | 122 comment | 11 complexity | 77a2844423c86513fe93a35a00c31420 MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @file
  4. * Contains \Drupal\Core\Entity\EntityViewBuilder.
  5. */
  6. namespace Drupal\Core\Entity;
  7. use Drupal\Core\Cache\Cache;
  8. use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
  9. use Drupal\Core\Language\Language;
  10. use Drupal\Core\Language\LanguageManagerInterface;
  11. use Drupal\entity\Entity\EntityViewDisplay;
  12. use Symfony\Component\DependencyInjection\ContainerInterface;
  13. /**
  14. * Base class for entity view controllers.
  15. */
  16. class EntityViewBuilder extends EntityControllerBase implements EntityControllerInterface, EntityViewBuilderInterface {
  17. /**
  18. * The type of entities for which this controller is instantiated.
  19. *
  20. * @var string
  21. */
  22. protected $entityTypeId;
  23. /**
  24. * Information about the entity type.
  25. *
  26. * @var \Drupal\Core\Entity\EntityTypeInterface
  27. */
  28. protected $entityType;
  29. /**
  30. * The entity manager service.
  31. *
  32. * @var \Drupal\Core\Entity\EntityManagerInterface
  33. */
  34. protected $entityManager;
  35. /**
  36. * The cache bin used to store the render cache.
  37. *
  38. * @todo Defaults to 'cache' for now, until http://drupal.org/node/1194136 is
  39. * fixed.
  40. *
  41. * @var string
  42. */
  43. protected $cacheBin = 'cache';
  44. /**
  45. * The language manager.
  46. *
  47. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
  48. */
  49. protected $languageManager;
  50. /**
  51. * Constructs a new EntityViewBuilder.
  52. *
  53. * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
  54. * The entity type definition.
  55. * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
  56. * The entity manager service.
  57. * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
  58. * The language manager.
  59. */
  60. public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager) {
  61. $this->entityTypeId = $entity_type->id();
  62. $this->entityType = $entity_type;
  63. $this->entityManager = $entity_manager;
  64. $this->languageManager = $language_manager;
  65. }
  66. /**
  67. * {@inheritdoc}
  68. */
  69. public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
  70. return new static(
  71. $entity_type,
  72. $container->get('entity.manager'),
  73. $container->get('language_manager')
  74. );
  75. }
  76. /**
  77. * {@inheritdoc}
  78. */
  79. public function buildContent(array $entities, array $displays, $view_mode, $langcode = NULL) {
  80. $entities_by_bundle = array();
  81. foreach ($entities as $id => $entity) {
  82. // Remove previously built content, if exists.
  83. $entity->content = array(
  84. '#view_mode' => $view_mode,
  85. );
  86. // Initialize the field item attributes for the fields being displayed.
  87. // The entity can include fields that are not displayed, and the display
  88. // can include components that are not fields, so we want to act on the
  89. // intersection. However, the entity can have many more fields than are
  90. // displayed, so we avoid the cost of calling $entity->getProperties()
  91. // by iterating the intersection as follows.
  92. foreach ($displays[$entity->bundle()]->getComponents() as $name => $options) {
  93. if ($entity->hasField($name)) {
  94. foreach ($entity->get($name) as $item) {
  95. $item->_attributes = array();
  96. }
  97. }
  98. }
  99. // Group the entities by bundle.
  100. $entities_by_bundle[$entity->bundle()][$id] = $entity;
  101. }
  102. // Invoke hook_entity_prepare_view().
  103. module_invoke_all('entity_prepare_view', $this->entityTypeId, $entities, $displays, $view_mode);
  104. // Let the displays build their render arrays.
  105. foreach ($entities_by_bundle as $bundle => $bundle_entities) {
  106. $build = $displays[$bundle]->buildMultiple($bundle_entities);
  107. foreach ($bundle_entities as $id => $entity) {
  108. $entity->content += $build[$id];
  109. }
  110. }
  111. }
  112. /**
  113. * Provides entity-specific defaults to the build process.
  114. *
  115. * @param \Drupal\Core\Entity\EntityInterface $entity
  116. * The entity for which the defaults should be provided.
  117. * @param string $view_mode
  118. * The view mode that should be used.
  119. * @param string $langcode
  120. * (optional) For which language the entity should be prepared, defaults to
  121. * the current content language.
  122. *
  123. * @return array
  124. */
  125. protected function getBuildDefaults(EntityInterface $entity, $view_mode, $langcode) {
  126. $return = array(
  127. '#theme' => $this->entityTypeId,
  128. "#{$this->entityTypeId}" => $entity,
  129. '#view_mode' => $view_mode,
  130. '#langcode' => $langcode,
  131. );
  132. // Cache the rendered output if permitted by the view mode and global entity
  133. // type configuration.
  134. if ($this->isViewModeCacheable($view_mode) && !$entity->isNew() && !isset($entity->in_preview) && $this->entityType->isRenderCacheable()) {
  135. $return['#cache'] = array(
  136. 'keys' => array('entity_view', $this->entityTypeId, $entity->id(), $view_mode),
  137. 'granularity' => DRUPAL_CACHE_PER_ROLE,
  138. 'bin' => $this->cacheBin,
  139. 'tags' => array(
  140. $this->entityTypeId . '_view' => TRUE,
  141. $this->entityTypeId => array($entity->id()),
  142. ),
  143. );
  144. }
  145. return $return;
  146. }
  147. /**
  148. * Specific per-entity building.
  149. *
  150. * @param array $build
  151. * The render array that is being created.
  152. * @param \Drupal\Core\Entity\EntityInterface $entity
  153. * The entity to be prepared.
  154. * @param \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display
  155. * The entity view display holding the display options configured for the
  156. * entity components.
  157. * @param string $view_mode
  158. * The view mode that should be used to prepare the entity.
  159. * @param string $langcode
  160. * (optional) For which language the entity should be prepared, defaults to
  161. * the current content language.
  162. */
  163. protected function alterBuild(array &$build, EntityInterface $entity, EntityViewDisplayInterface $display, $view_mode, $langcode = NULL) { }
  164. /**
  165. * {@inheritdoc}
  166. */
  167. public function view(EntityInterface $entity, $view_mode = 'full', $langcode = NULL) {
  168. $buildList = $this->viewMultiple(array($entity), $view_mode, $langcode);
  169. return $buildList[0];
  170. }
  171. /**
  172. * {@inheritdoc}
  173. */
  174. public function viewMultiple(array $entities = array(), $view_mode = 'full', $langcode = NULL) {
  175. if (!isset($langcode)) {
  176. $langcode = $this->languageManager->getCurrentLanguage(Language::TYPE_CONTENT)->id;
  177. }
  178. // Build the view modes and display objects.
  179. $view_modes = array();
  180. $context = array('langcode' => $langcode);
  181. foreach ($entities as $key => $entity) {
  182. $bundle = $entity->bundle();
  183. // Ensure that from now on we are dealing with the proper translation
  184. // object.
  185. $entity = $this->entityManager->getTranslationFromContext($entity, $langcode);
  186. $entities[$key] = $entity;
  187. // Allow modules to change the view mode.
  188. $entity_view_mode = $view_mode;
  189. drupal_alter('entity_view_mode', $entity_view_mode, $entity, $context);
  190. // Store entities for rendering by view_mode.
  191. $view_modes[$entity_view_mode][$entity->id()] = $entity;
  192. }
  193. foreach ($view_modes as $mode => $view_mode_entities) {
  194. $displays[$mode] = EntityViewDisplay::collectRenderDisplays($view_mode_entities, $mode);
  195. $this->buildContent($view_mode_entities, $displays[$mode], $mode, $langcode);
  196. }
  197. $view_hook = "{$this->entityTypeId}_view";
  198. $build = array('#sorted' => TRUE);
  199. $weight = 0;
  200. foreach ($entities as $key => $entity) {
  201. $entity_view_mode = isset($entity->content['#view_mode']) ? $entity->content['#view_mode'] : $view_mode;
  202. $display = $displays[$entity_view_mode][$entity->bundle()];
  203. module_invoke_all($view_hook, $entity, $display, $entity_view_mode, $langcode);
  204. module_invoke_all('entity_view', $entity, $display, $entity_view_mode, $langcode);
  205. $build[$key] = $entity->content;
  206. // We don't need duplicate rendering info in $entity->content.
  207. unset($entity->content);
  208. $build[$key] += $this->getBuildDefaults($entity, $entity_view_mode, $langcode);
  209. $this->alterBuild($build[$key], $entity, $display, $entity_view_mode, $langcode);
  210. // Assign the weights configured in the display.
  211. // @todo: Once https://drupal.org/node/1875974 provides the missing API,
  212. // only do it for 'extra fields', since other components have been taken
  213. // care of in EntityViewDisplay::buildMultiple().
  214. foreach ($display->getComponents() as $name => $options) {
  215. if (isset($build[$key][$name])) {
  216. $build[$key][$name]['#weight'] = $options['weight'];
  217. }
  218. }
  219. $build[$key]['#weight'] = $weight++;
  220. // Allow modules to modify the render array.
  221. drupal_alter(array($view_hook, 'entity_view'), $build[$key], $entity, $display);
  222. }
  223. return $build;
  224. }
  225. /**
  226. * {@inheritdoc}
  227. */
  228. public function resetCache(array $entities = NULL) {
  229. if (isset($entities)) {
  230. $tags = array();
  231. foreach ($entities as $entity) {
  232. $id = $entity->id();
  233. $tags[$this->entityTypeId][$id] = $id;
  234. $tags[$this->entityTypeId . '_view_' . $entity->bundle()] = TRUE;
  235. }
  236. Cache::deleteTags($tags);
  237. }
  238. else {
  239. Cache::deleteTags(array($this->entityTypeId . '_view' => TRUE));
  240. }
  241. }
  242. /**
  243. * Returns TRUE if the view mode is cacheable.
  244. *
  245. * @param string $view_mode
  246. * Name of the view mode that should be rendered.
  247. *
  248. * @return bool
  249. * TRUE if the view mode can be cached, FALSE otherwise.
  250. */
  251. protected function isViewModeCacheable($view_mode) {
  252. if ($view_mode == 'default') {
  253. // The 'default' is not an actual view mode.
  254. return TRUE;
  255. }
  256. $view_modes_info = entity_get_view_modes($this->entityTypeId);
  257. return !empty($view_modes_info[$view_mode]['cache']);
  258. }
  259. }