PageRenderTime 58ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/core/modules/comment/lib/Drupal/comment/CommentViewBuilder.php

https://bitbucket.org/aswinvk28/smartpan-stock-drupal
PHP | 347 lines | 201 code | 35 blank | 111 comment | 24 complexity | 72ccc180174d9afa968784adaf2fc47c MD5 | raw file
Possible License(s): LGPL-2.1
  1. <?php
  2. /**
  3. * @file
  4. * Definition of Drupal\comment\CommentViewBuilder.
  5. */
  6. namespace Drupal\comment;
  7. use Drupal\Core\Access\CsrfTokenGenerator;
  8. use Drupal\Core\Entity\Display\EntityViewDisplayInterface;
  9. use Drupal\Core\Entity\EntityInterface;
  10. use Drupal\Core\Entity\EntityManagerInterface;
  11. use Drupal\Core\Entity\EntityTypeInterface;
  12. use Drupal\Core\Entity\EntityViewBuilder;
  13. use Drupal\Core\Language\LanguageManagerInterface;
  14. use Drupal\field\FieldInfo;
  15. use Symfony\Component\DependencyInjection\ContainerInterface;
  16. /**
  17. * Render controller for comments.
  18. */
  19. class CommentViewBuilder extends EntityViewBuilder {
  20. /**
  21. * The field info service.
  22. *
  23. * @var \Drupal\field\FieldInfo
  24. */
  25. protected $fieldInfo;
  26. /**
  27. * The module handler service.
  28. *
  29. * @var \Drupal\Core\Extension\ModuleHandlerInterface
  30. */
  31. protected $moduleHandler;
  32. /**
  33. * The CSRF token manager service.
  34. *
  35. * @var \Drupal\Core\Access\CsrfTokenGenerator
  36. */
  37. protected $csrfToken;
  38. /**
  39. * {@inheritdoc}
  40. */
  41. public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
  42. return new static(
  43. $entity_type,
  44. $container->get('entity.manager'),
  45. $container->get('language_manager'),
  46. $container->get('field.info'),
  47. $container->get('csrf_token')
  48. );
  49. }
  50. /**
  51. * Constructs a new CommentViewBuilder.
  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. * @param \Drupal\field\FieldInfo $field_info
  60. * The field info service.
  61. * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token
  62. * The CSRF token manager service.
  63. */
  64. public function __construct(EntityTypeInterface $entity_type, EntityManagerInterface $entity_manager, LanguageManagerInterface $language_manager, FieldInfo $field_info, CsrfTokenGenerator $csrf_token) {
  65. parent::__construct($entity_type, $entity_manager, $language_manager);
  66. $this->fieldInfo = $field_info;
  67. $this->csrfToken = $csrf_token;
  68. }
  69. /**
  70. * Overrides Drupal\Core\Entity\EntityViewBuilder::buildContent().
  71. *
  72. * In addition to modifying the content key on entities, this implementation
  73. * will also set the comment entity key which all comments carry.
  74. *
  75. * @throws \InvalidArgumentException
  76. * Thrown when a comment is attached to an entity that no longer exists.
  77. */
  78. public function buildContent(array $entities, array $displays, $view_mode, $langcode = NULL) {
  79. /** @var \Drupal\comment\CommentInterface[] $entities */
  80. $return = array();
  81. if (empty($entities)) {
  82. return $return;
  83. }
  84. // Pre-load associated users into cache to leverage multiple loading.
  85. $uids = array();
  86. foreach ($entities as $entity) {
  87. $uids[] = $entity->getOwnerId();
  88. }
  89. $this->entityManager->getStorageController('user')->loadMultiple(array_unique($uids));
  90. parent::buildContent($entities, $displays, $view_mode, $langcode);
  91. // Load all the entities that have comments attached.
  92. $commented_entity_ids = array();
  93. $commented_entities = array();
  94. foreach ($entities as $entity) {
  95. $commented_entity_ids[$entity->getCommentedEntityTypeId()][] = $entity->getCommentedEntityId();
  96. }
  97. // Load entities in bulk. This is more performant than using
  98. // $comment->getCommentedEntity() as we can load them in bulk per type.
  99. foreach ($commented_entity_ids as $entity_type => $entity_ids) {
  100. $commented_entities[$entity_type] = $this->entityManager->getStorageController($entity_type)->loadMultiple($entity_ids);
  101. }
  102. foreach ($entities as $entity) {
  103. if (isset($commented_entities[$entity->getCommentedEntityTypeId()][$entity->getCommentedEntityId()])) {
  104. $commented_entity = $commented_entities[$entity->getCommentedEntityTypeId()][$entity->getCommentedEntityId()];
  105. }
  106. else {
  107. throw new \InvalidArgumentException(t('Invalid entity for comment.'));
  108. }
  109. $entity->content['#entity'] = $entity;
  110. $entity->content['#theme'] = 'comment__' . $entity->getFieldId() . '__' . $commented_entity->bundle();
  111. $entity->content['links'] = array(
  112. '#type' => 'render_cache_placeholder',
  113. '#callback' => '\Drupal\comment\CommentViewBuilder::renderLinks',
  114. '#context' => array(
  115. 'comment_entity_id' => $entity->id(),
  116. 'view_mode' => $view_mode,
  117. 'langcode' => $langcode,
  118. 'commented_entity_type' => $commented_entity->getEntityTypeId(),
  119. 'commented_entity_id' => $commented_entity->id(),
  120. 'in_preview' => !empty($entity->in_preview),
  121. ),
  122. );
  123. if (!isset($entity->content['#attached'])) {
  124. $entity->content['#attached'] = array();
  125. }
  126. $entity->content['#attached']['library'][] = array('comment', 'drupal.comment-by-viewer');
  127. if ($this->moduleHandler->moduleExists('history') && \Drupal::currentUser()->isAuthenticated()) {
  128. $entity->content['#attached']['library'][] = array('comment', 'drupal.comment-new-indicator');
  129. // Embed the metadata for the comment "new" indicators on this node.
  130. $entity->content['#post_render_cache']['history_attach_timestamp'] = array(
  131. array('node_id' => $commented_entity->id()),
  132. );
  133. }
  134. }
  135. }
  136. /**
  137. * #post_render_cache callback; replaces the placeholder with comment links.
  138. *
  139. * Renders the links on a comment.
  140. *
  141. * @param array $context
  142. * An array with the following keys:
  143. * - comment_entity_id: a comment entity ID
  144. * - view_mode: the view mode in which the comment entity is being viewed
  145. * - langcode: in which language the comment entity is being viewed
  146. * - commented_entity_type: the entity type to which the comment is attached
  147. * - commented_entity_id: the entity ID to which the comment is attached
  148. * - in_preview: whether the comment is currently being previewed
  149. *
  150. * @return array
  151. * A renderable array representing the comment links.
  152. */
  153. public static function renderLinks(array $context) {
  154. $links = array(
  155. '#theme' => 'links__comment',
  156. '#pre_render' => array('drupal_pre_render_links'),
  157. '#attributes' => array('class' => array('links', 'inline')),
  158. );
  159. if (!$context['in_preview']) {
  160. $entity = entity_load('comment', $context['comment_entity_id']);
  161. $commented_entity = entity_load($context['commented_entity_type'], $context['commented_entity_id']);
  162. $links['comment'] = self::buildLinks($entity, $commented_entity);
  163. // Allow other modules to alter the comment links.
  164. $hook_context = array(
  165. 'view_mode' => $context['view_mode'],
  166. 'langcode' => $context['langcode'],
  167. 'commented_entity' => $commented_entity
  168. );
  169. \Drupal::moduleHandler()->alter('comment_links', $links, $entity, $hook_context);
  170. }
  171. return $links;
  172. }
  173. /**
  174. * Build the default links (reply, edit, delete …) for a comment.
  175. *
  176. * @param \Drupal\comment\CommentInterface $entity
  177. * The comment object.
  178. * @param \Drupal\Core\Entity\EntityInterface $commented_entity
  179. * The entity to which the comment is attached.
  180. *
  181. * @return array
  182. * An array that can be processed by drupal_pre_render_links().
  183. */
  184. protected static function buildLinks(CommentInterface $entity, EntityInterface $commented_entity) {
  185. $links = array();
  186. $status = $commented_entity->get($entity->getFieldName())->status;
  187. $container = \Drupal::getContainer();
  188. if ($status == COMMENT_OPEN) {
  189. if ($entity->access('delete')) {
  190. $links['comment-delete'] = array(
  191. 'title' => t('Delete'),
  192. 'href' => "comment/{$entity->id()}/delete",
  193. 'html' => TRUE,
  194. );
  195. }
  196. if ($entity->access('update')) {
  197. $links['comment-edit'] = array(
  198. 'title' => t('Edit'),
  199. 'href' => "comment/{$entity->id()}/edit",
  200. 'html' => TRUE,
  201. );
  202. }
  203. if ($entity->access('create')) {
  204. $links['comment-reply'] = array(
  205. 'title' => t('Reply'),
  206. 'href' => "comment/reply/{$entity->getCommentedEntityId()}/{$entity->getCommentedEntityId()}/{$entity->getFieldName()}/{$entity->id()}",
  207. 'html' => TRUE,
  208. );
  209. }
  210. if (!$entity->isPublished() && $entity->access('approve')) {
  211. $links['comment-approve'] = array(
  212. 'title' => t('Approve'),
  213. 'route_name' => 'comment.approve',
  214. 'route_parameters' => array('comment' => $entity->id()),
  215. 'html' => TRUE,
  216. );
  217. }
  218. if (empty($links)) {
  219. $links['comment-forbidden']['title'] = \Drupal::service('comment.manager')->forbiddenMessage($commented_entity, $entity->getFieldName());
  220. $links['comment-forbidden']['html'] = TRUE;
  221. }
  222. }
  223. // Add translations link for translation-enabled comment bundles.
  224. if ($container->get('module_handler')->moduleExists('content_translation') && content_translation_translate_access($entity)) {
  225. $links['comment-translations'] = array(
  226. 'title' => t('Translate'),
  227. 'href' => 'comment/' . $entity->id() . '/translations',
  228. 'html' => TRUE,
  229. );
  230. }
  231. return array(
  232. '#theme' => 'links__comment__comment',
  233. // The "entity" property is specified to be present, so no need to
  234. // check.
  235. '#links' => $links,
  236. '#attributes' => array('class' => array('links', 'inline')),
  237. );
  238. }
  239. /**
  240. * {@inheritdoc}
  241. */
  242. protected function alterBuild(array &$build, EntityInterface $comment, EntityViewDisplayInterface $display, $view_mode, $langcode = NULL) {
  243. parent::alterBuild($build, $comment, $display, $view_mode, $langcode);
  244. if (empty($comment->in_preview)) {
  245. $prefix = '';
  246. $commented_entity = $comment->getCommentedEntity();
  247. $instance = $this->fieldInfo->getInstance($commented_entity->getEntityTypeId(), $commented_entity->bundle(), $comment->getFieldName());
  248. $is_threaded = isset($comment->divs)
  249. && $instance->getSetting('default_mode') == COMMENT_MODE_THREADED;
  250. // Add indentation div or close open divs as needed.
  251. if ($is_threaded) {
  252. $build['#attached']['css'][] = drupal_get_path('module', 'comment') . '/css/comment.theme.css';
  253. $prefix .= $comment->divs <= 0 ? str_repeat('</div>', abs($comment->divs)) : "\n" . '<div class="indented">';
  254. }
  255. // Add anchor for each comment.
  256. $prefix .= "<a id=\"comment-{$comment->id()}\"></a>\n";
  257. $build['#prefix'] = $prefix;
  258. // Close all open divs.
  259. if ($is_threaded && !empty($comment->divs_final)) {
  260. $build['#suffix'] = str_repeat('</div>', $comment->divs_final);
  261. }
  262. }
  263. }
  264. /**
  265. * #post_render_cache callback; attaches "X new comments" link metadata.
  266. *
  267. * @param array $element
  268. * A render array with the following keys:
  269. * - #markup
  270. * - #attached
  271. * @param array $context
  272. * An array with the following keys:
  273. * - entity_type: an entity type
  274. * - entity_id: an entity ID
  275. * - field_name: a comment field name
  276. *
  277. * @return array $element
  278. * The updated $element.
  279. */
  280. public static function attachNewCommentsLinkMetadata(array $element, array $context) {
  281. // Build "X new comments" link metadata.
  282. $new = (int)comment_num_new($context['entity_id'], $context['entity_type']);
  283. // Early-return if there are zero new comments for the current user.
  284. if ($new === 0) {
  285. return $element;
  286. }
  287. $entity = \Drupal::entityManager()
  288. ->getStorageController($context['entity_type'])
  289. ->load($context['entity_id']);
  290. $field_name = $context['field_name'];
  291. $query = comment_new_page_count($entity->{$field_name}->comment_count, $new, $entity);
  292. // Attach metadata.
  293. $element['#attached']['js'][] = array(
  294. 'type' => 'setting',
  295. 'data' => array(
  296. 'comment' => array(
  297. 'newCommentsLinks' => array(
  298. $context['entity_type'] => array(
  299. $context['field_name'] => array(
  300. $context['entity_id'] => array(
  301. 'new_comment_count' => (int)$new,
  302. 'first_new_comment_link' => \Drupal::urlGenerator()->generateFromPath('node/' . $entity->id(), array('query' => $query, 'fragment' => 'new')),
  303. )
  304. )
  305. ),
  306. )
  307. ),
  308. ),
  309. );
  310. return $element;
  311. }
  312. }