annotate core/modules/forum/forum.module @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /**
Chris@0 4 * @file
Chris@0 5 * Provides discussion forums.
Chris@0 6 */
Chris@0 7
Chris@0 8 use Drupal\comment\CommentInterface;
Chris@0 9 use Drupal\comment\Plugin\Field\FieldType\CommentItemInterface;
Chris@0 10 use Drupal\Core\Entity\EntityInterface;
Chris@0 11 use Drupal\Core\Entity\EntityTypeInterface;
Chris@0 12 use Drupal\Core\Url;
Chris@0 13 use Drupal\Core\Form\FormStateInterface;
Chris@0 14 use Drupal\Core\Routing\RouteMatchInterface;
Chris@0 15 use Drupal\taxonomy\VocabularyInterface;
Chris@0 16 use Drupal\user\Entity\User;
Chris@0 17
Chris@0 18 /**
Chris@0 19 * Implements hook_help().
Chris@0 20 */
Chris@0 21 function forum_help($route_name, RouteMatchInterface $route_match) {
Chris@0 22 switch ($route_name) {
Chris@0 23 case 'help.page.forum':
Chris@0 24 $output = '';
Chris@0 25 $output .= '<h3>' . t('About') . '</h3>';
Chris@0 26 $output .= '<p>' . t('The Forum module lets you create threaded discussion forums with functionality similar to other message board systems. In a forum, users post topics and threads in nested hierarchies, allowing discussions to be categorized and grouped.') . '</p>';
Chris@18 27 $output .= '<p>' . t('The Forum module adds and uses a content type called <em>Forum topic</em>. For background information on content types, see the <a href=":node_help">Node module help page</a>.', [':node_help' => Url::fromRoute('help.page', ['name' => 'node'])->toString()]) . '</p>';
Chris@0 28 $output .= '<p>' . t('A forum is represented by a hierarchical structure, consisting of:');
Chris@0 29 $output .= '<ul>';
Chris@0 30 $output .= '<li>' . t('<em>Forums</em> (for example, <em>Recipes for cooking vegetables</em>)') . '</li>';
Chris@0 31 $output .= '<li>' . t('<em>Forum topics</em> submitted by users (for example, <em>How to cook potatoes</em>), which start discussions.') . '</li>';
Chris@0 32 $output .= '<li>' . t('Threaded <em>comments</em> submitted by users (for example, <em>You wash the potatoes first and then...</em>).') . '</li>';
Chris@0 33 $output .= '<li>' . t('Optional <em>containers</em>, used to group similar forums. Forums can be placed inside containers, and vice versa.') . '</li>';
Chris@0 34 $output .= '</ul>';
Chris@0 35 $output .= '</p>';
Chris@0 36 $output .= '<p>' . t('For more information, see the <a href=":forum">online documentation for the Forum module</a>.', [':forum' => 'https://www.drupal.org/documentation/modules/forum']) . '</p>';
Chris@0 37 $output .= '<h3>' . t('Uses') . '</h3>';
Chris@0 38 $output .= '<dl>';
Chris@0 39 $output .= '<dt>' . t('Setting up the forum structure') . '</dt>';
Chris@18 40 $output .= '<dd>' . t('Visit the <a href=":forums">Forums page</a> to set up containers and forums to hold your discussion topics.', [':forums' => Url::fromRoute('forum.overview')->toString()]) . '</dd>';
Chris@0 41 $output .= '<dt>' . t('Starting a discussion') . '</dt>';
Chris@18 42 $output .= '<dd>' . t('The <a href=":create-topic">Forum topic</a> link on the <a href=":content-add">Add content</a> page creates the first post of a new threaded discussion, or thread.', [':create-topic' => Url::fromRoute('node.add', ['node_type' => 'forum'])->toString(), ':content-add' => Url::fromRoute('node.add_page')->toString()]) . '</dd>';
Chris@0 43 $output .= '<dt>' . t('Navigating in the forum') . '</dt>';
Chris@18 44 $output .= '<dd>' . t('Enabling the Forum module provides a default <em>Forums</em> menu item in the Tools menu that links to the <a href=":forums">Forums page</a>.', [':forums' => Url::fromRoute('forum.index')->toString()]) . '</dd>';
Chris@0 45 $output .= '<dt>' . t('Moving forum topics') . '</dt>';
Chris@0 46 $output .= '<dd>' . t('A forum topic (and all of its comments) may be moved between forums by selecting a different forum while editing a forum topic. When moving a forum topic between forums, the <em>Leave shadow copy</em> option creates a link in the original forum pointing to the new location.') . '</dd>';
Chris@0 47 $output .= '<dt>' . t('Locking and disabling comments') . '</dt>';
Chris@0 48 $output .= '<dd>' . t('Selecting <em>Closed</em> under <em>Comment settings</em> while editing a forum topic will lock (prevent new comments on) the thread. Selecting <em>Hidden</em> under <em>Comment settings</em> while editing a forum topic will hide all existing comments on the thread, and prevent new ones.') . '</dd>';
Chris@0 49 $output .= '</dl>';
Chris@0 50 return $output;
Chris@0 51
Chris@0 52 case 'forum.overview':
Chris@0 53 $output = '<p>' . t('Forums contain forum topics. Use containers to group related forums.') . '</p>';
Chris@0 54 $more_help_link = [
Chris@0 55 '#type' => 'link',
Chris@0 56 '#url' => Url::fromRoute('help.page', ['name' => 'forum']),
Chris@0 57 '#title' => t('More help'),
Chris@0 58 '#attributes' => [
Chris@0 59 'class' => ['icon-help'],
Chris@0 60 ],
Chris@0 61 ];
Chris@0 62 $container = [
Chris@0 63 '#theme' => 'container',
Chris@0 64 '#children' => $more_help_link,
Chris@0 65 '#attributes' => [
Chris@0 66 'class' => ['more-link'],
Chris@0 67 ],
Chris@0 68 ];
Chris@0 69 $output .= \Drupal::service('renderer')->renderPlain($container);
Chris@0 70 return $output;
Chris@0 71
Chris@0 72 case 'forum.add_container':
Chris@0 73 return '<p>' . t('Use containers to group related forums.') . '</p>';
Chris@0 74
Chris@0 75 case 'forum.add_forum':
Chris@0 76 return '<p>' . t('A forum holds related forum topics.') . '</p>';
Chris@0 77
Chris@0 78 case 'forum.settings':
Chris@18 79 return '<p>' . t('Adjust the display of your forum topics. Organize the forums on the <a href=":forum-structure">forum structure page</a>.', [':forum-structure' => Url::fromRoute('forum.overview')->toString()]) . '</p>';
Chris@0 80 }
Chris@0 81 }
Chris@0 82
Chris@0 83 /**
Chris@0 84 * Implements hook_theme().
Chris@0 85 */
Chris@0 86 function forum_theme() {
Chris@0 87 return [
Chris@0 88 'forums' => [
Chris@0 89 'variables' => ['forums' => [], 'topics' => [], 'topics_pager' => [], 'parents' => NULL, 'term' => NULL, 'sortby' => NULL, 'forum_per_page' => NULL, 'header' => []],
Chris@0 90 ],
Chris@0 91 'forum_list' => [
Chris@0 92 'variables' => ['forums' => NULL, 'parents' => NULL, 'tid' => NULL],
Chris@0 93 ],
Chris@0 94 'forum_icon' => [
Chris@0 95 'variables' => ['new_posts' => NULL, 'num_posts' => 0, 'comment_mode' => 0, 'sticky' => 0, 'first_new' => FALSE],
Chris@0 96 ],
Chris@0 97 'forum_submitted' => [
Chris@0 98 'variables' => ['topic' => NULL],
Chris@0 99 ],
Chris@0 100 ];
Chris@0 101 }
Chris@0 102
Chris@0 103 /**
Chris@0 104 * Implements hook_entity_type_build().
Chris@0 105 */
Chris@0 106 function forum_entity_type_build(array &$entity_types) {
Chris@0 107 /** @var $entity_types \Drupal\Core\Entity\EntityTypeInterface[] */
Chris@0 108 // Register forum specific forms.
Chris@0 109 $entity_types['taxonomy_term']
Chris@0 110 ->setFormClass('forum', 'Drupal\forum\Form\ForumForm')
Chris@0 111 ->setFormClass('container', 'Drupal\forum\Form\ContainerForm')
Chris@0 112 ->setLinkTemplate('forum-edit-container-form', '/admin/structure/forum/edit/container/{taxonomy_term}')
Chris@0 113 ->setLinkTemplate('forum-delete-form', '/admin/structure/forum/delete/forum/{taxonomy_term}')
Chris@0 114 ->setLinkTemplate('forum-edit-form', '/admin/structure/forum/edit/forum/{taxonomy_term}');
Chris@0 115 }
Chris@0 116
Chris@0 117 /**
Chris@0 118 * Implements hook_entity_bundle_info_alter().
Chris@0 119 */
Chris@0 120 function forum_entity_bundle_info_alter(&$bundles) {
Chris@0 121 // Take over URI construction for taxonomy terms that are forums.
Chris@0 122 if ($vid = \Drupal::config('forum.settings')->get('vocabulary')) {
Chris@0 123 if (isset($bundles['taxonomy_term'][$vid])) {
Chris@0 124 $bundles['taxonomy_term'][$vid]['uri_callback'] = 'forum_uri';
Chris@0 125 }
Chris@0 126 }
Chris@0 127 }
Chris@0 128
Chris@0 129 /**
Chris@0 130 * Entity URI callback used in forum_entity_bundle_info_alter().
Chris@0 131 */
Chris@0 132 function forum_uri($forum) {
Chris@0 133 return Url::fromRoute('forum.page', ['taxonomy_term' => $forum->id()]);
Chris@0 134 }
Chris@0 135
Chris@0 136 /**
Chris@0 137 * Implements hook_entity_bundle_field_info_alter().
Chris@0 138 */
Chris@0 139 function forum_entity_bundle_field_info_alter(&$fields, EntityTypeInterface $entity_type, $bundle) {
Chris@0 140 if ($entity_type->id() == 'node' && !empty($fields['taxonomy_forums'])) {
Chris@0 141 $fields['taxonomy_forums']->addConstraint('ForumLeaf', []);
Chris@0 142 }
Chris@0 143 }
Chris@0 144
Chris@0 145 /**
Chris@0 146 * Implements hook_ENTITY_TYPE_presave() for node entities.
Chris@0 147 *
Chris@0 148 * Assigns the forum taxonomy when adding a topic from within a forum.
Chris@0 149 */
Chris@0 150 function forum_node_presave(EntityInterface $node) {
Chris@0 151 if (\Drupal::service('forum_manager')->checkNodeType($node)) {
Chris@0 152 // Make sure all fields are set properly:
Chris@0 153 $node->icon = !empty($node->icon) ? $node->icon : '';
Chris@0 154 if (!$node->taxonomy_forums->isEmpty()) {
Chris@0 155 $node->forum_tid = $node->taxonomy_forums->target_id;
Chris@0 156 // Only do a shadow copy check if this is not a new node.
Chris@0 157 if (!$node->isNew()) {
Chris@0 158 $old_tid = \Drupal::service('forum.index_storage')->getOriginalTermId($node);
Chris@0 159 if ($old_tid && isset($node->forum_tid) && ($node->forum_tid != $old_tid) && !empty($node->shadow)) {
Chris@0 160 // A shadow copy needs to be created. Retain new term and add old term.
Chris@0 161 $node->taxonomy_forums[count($node->taxonomy_forums)] = ['target_id' => $old_tid];
Chris@0 162 }
Chris@0 163 }
Chris@0 164 }
Chris@0 165 }
Chris@0 166 }
Chris@0 167
Chris@0 168 /**
Chris@0 169 * Implements hook_ENTITY_TYPE_update() for node entities.
Chris@0 170 */
Chris@0 171 function forum_node_update(EntityInterface $node) {
Chris@0 172 if (\Drupal::service('forum_manager')->checkNodeType($node)) {
Chris@0 173 // If this is not a new revision and does exist, update the forum record,
Chris@0 174 // otherwise insert a new one.
Chris@0 175 /** @var \Drupal\forum\ForumIndexStorageInterface $forum_index_storage */
Chris@0 176 $forum_index_storage = \Drupal::service('forum.index_storage');
Chris@0 177 if ($node->getRevisionId() == $node->original->getRevisionId() && $forum_index_storage->getOriginalTermId($node)) {
Chris@0 178 if (!empty($node->forum_tid)) {
Chris@0 179 $forum_index_storage->update($node);
Chris@0 180 }
Chris@0 181 // The node is removed from the forum.
Chris@0 182 else {
Chris@0 183 $forum_index_storage->delete($node);
Chris@0 184 }
Chris@0 185 }
Chris@0 186 else {
Chris@0 187 if (!empty($node->forum_tid)) {
Chris@0 188 $forum_index_storage->create($node);
Chris@0 189 }
Chris@0 190 }
Chris@0 191 // If the node has a shadow forum topic, update the record for this
Chris@0 192 // revision.
Chris@0 193 if (!empty($node->shadow)) {
Chris@0 194 $forum_index_storage->deleteRevision($node);
Chris@0 195 $forum_index_storage->create($node);
Chris@0 196 }
Chris@0 197
Chris@0 198 // If the node is published, update the forum index.
Chris@0 199 if ($node->isPublished()) {
Chris@0 200 $forum_index_storage->deleteIndex($node);
Chris@0 201 $forum_index_storage->createIndex($node);
Chris@0 202 }
Chris@0 203 // When a forum node is unpublished, remove it from the forum_index table.
Chris@0 204 else {
Chris@0 205 $forum_index_storage->deleteIndex($node);
Chris@0 206 }
Chris@0 207 }
Chris@0 208 }
Chris@0 209
Chris@0 210 /**
Chris@0 211 * Implements hook_ENTITY_TYPE_insert() for node entities.
Chris@0 212 */
Chris@0 213 function forum_node_insert(EntityInterface $node) {
Chris@0 214 if (\Drupal::service('forum_manager')->checkNodeType($node)) {
Chris@0 215 /** @var \Drupal\forum\ForumIndexStorageInterface $forum_index_storage */
Chris@0 216 $forum_index_storage = \Drupal::service('forum.index_storage');
Chris@0 217 if (!empty($node->forum_tid)) {
Chris@0 218 $forum_index_storage->create($node);
Chris@0 219 }
Chris@0 220
Chris@0 221 // If the node is published, update the forum index.
Chris@0 222 if ($node->isPublished()) {
Chris@0 223 $forum_index_storage->createIndex($node);
Chris@0 224 }
Chris@0 225 }
Chris@0 226 }
Chris@0 227
Chris@0 228 /**
Chris@0 229 * Implements hook_ENTITY_TYPE_predelete() for node entities.
Chris@0 230 */
Chris@0 231 function forum_node_predelete(EntityInterface $node) {
Chris@0 232 if (\Drupal::service('forum_manager')->checkNodeType($node)) {
Chris@0 233 /** @var \Drupal\forum\ForumIndexStorageInterface $forum_index_storage */
Chris@0 234 $forum_index_storage = \Drupal::service('forum.index_storage');
Chris@0 235 $forum_index_storage->delete($node);
Chris@0 236 $forum_index_storage->deleteIndex($node);
Chris@0 237 }
Chris@0 238 }
Chris@0 239
Chris@0 240 /**
Chris@0 241 * Implements hook_ENTITY_TYPE_storage_load() for node entities.
Chris@0 242 */
Chris@0 243 function forum_node_storage_load($nodes) {
Chris@0 244 $node_vids = [];
Chris@0 245 foreach ($nodes as $node) {
Chris@0 246 if (\Drupal::service('forum_manager')->checkNodeType($node)) {
Chris@0 247 $node_vids[] = $node->getRevisionId();
Chris@0 248 }
Chris@0 249 }
Chris@0 250 if (!empty($node_vids)) {
Chris@0 251 $result = \Drupal::service('forum.index_storage')->read($node_vids);
Chris@0 252 foreach ($result as $record) {
Chris@0 253 $nodes[$record->nid]->forum_tid = $record->tid;
Chris@0 254 }
Chris@0 255 }
Chris@0 256 }
Chris@0 257
Chris@0 258 /**
Chris@0 259 * Implements hook_ENTITY_TYPE_update() for comment entities.
Chris@0 260 */
Chris@0 261 function forum_comment_update(CommentInterface $comment) {
Chris@0 262 if ($comment->getCommentedEntityTypeId() == 'node') {
Chris@0 263 \Drupal::service('forum.index_storage')->updateIndex($comment->getCommentedEntity());
Chris@0 264 }
Chris@0 265 }
Chris@0 266
Chris@0 267 /**
Chris@0 268 * Implements hook_ENTITY_TYPE_insert() for comment entities.
Chris@0 269 */
Chris@0 270 function forum_comment_insert(CommentInterface $comment) {
Chris@0 271 if ($comment->getCommentedEntityTypeId() == 'node') {
Chris@0 272 \Drupal::service('forum.index_storage')->updateIndex($comment->getCommentedEntity());
Chris@0 273 }
Chris@0 274 }
Chris@0 275
Chris@0 276 /**
Chris@0 277 * Implements hook_ENTITY_TYPE_delete() for comment entities.
Chris@0 278 */
Chris@0 279 function forum_comment_delete(CommentInterface $comment) {
Chris@0 280 if ($comment->getCommentedEntityTypeId() == 'node') {
Chris@0 281 \Drupal::service('forum.index_storage')->updateIndex($comment->getCommentedEntity());
Chris@0 282 }
Chris@0 283 }
Chris@0 284
Chris@0 285 /**
Chris@0 286 * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\taxonomy\VocabularyForm.
Chris@0 287 */
Chris@0 288 function forum_form_taxonomy_vocabulary_form_alter(&$form, FormStateInterface $form_state, $form_id) {
Chris@0 289 $vid = \Drupal::config('forum.settings')->get('vocabulary');
Chris@0 290 $vocabulary = $form_state->getFormObject()->getEntity();
Chris@0 291 if ($vid == $vocabulary->id()) {
Chris@0 292 $form['help_forum_vocab'] = [
Chris@0 293 '#markup' => t('This is the designated forum vocabulary. Some of the normal vocabulary options have been removed.'),
Chris@0 294 '#weight' => -1,
Chris@0 295 ];
Chris@0 296 // Forum's vocabulary always has single hierarchy. Forums and containers
Chris@0 297 // have only one parent or no parent for root items. By default this value
Chris@0 298 // is 0.
Chris@0 299 $form['hierarchy']['#value'] = VocabularyInterface::HIERARCHY_SINGLE;
Chris@0 300 // Do not allow to delete forum's vocabulary.
Chris@0 301 $form['actions']['delete']['#access'] = FALSE;
Chris@0 302 // Do not allow to change a vid of forum's vocabulary.
Chris@0 303 $form['vid']['#disabled'] = TRUE;
Chris@0 304 }
Chris@0 305 }
Chris@0 306
Chris@0 307 /**
Chris@0 308 * Implements hook_form_FORM_ID_alter() for \Drupal\taxonomy\TermForm.
Chris@0 309 */
Chris@0 310 function forum_form_taxonomy_term_form_alter(&$form, FormStateInterface $form_state, $form_id) {
Chris@0 311 $vid = \Drupal::config('forum.settings')->get('vocabulary');
Chris@0 312 if (isset($form['vid']['#value']) && $form['vid']['#value'] == $vid) {
Chris@0 313 // Hide multiple parents select from forum terms.
Chris@0 314 $form['relations']['parent']['#access'] = FALSE;
Chris@0 315 }
Chris@0 316 }
Chris@0 317
Chris@0 318 /**
Chris@0 319 * Implements hook_form_BASE_FORM_ID_alter() for \Drupal\node\NodeForm.
Chris@0 320 */
Chris@0 321 function forum_form_node_form_alter(&$form, FormStateInterface $form_state, $form_id) {
Chris@0 322 $node = $form_state->getFormObject()->getEntity();
Chris@0 323 if (isset($node->taxonomy_forums) && !$node->isNew()) {
Chris@0 324 $forum_terms = $node->taxonomy_forums;
Chris@0 325 // If editing, give option to leave shadows.
Chris@0 326 $shadow = (count($forum_terms) > 1);
Chris@0 327 $form['shadow'] = [
Chris@0 328 '#type' => 'checkbox',
Chris@0 329 '#title' => t('Leave shadow copy'),
Chris@0 330 '#default_value' => $shadow,
Chris@0 331 '#description' => t('If you move this topic, you can leave a link in the old forum to the new forum.'),
Chris@0 332 ];
Chris@0 333 $form['forum_tid'] = ['#type' => 'value', '#value' => $node->forum_tid];
Chris@0 334 }
Chris@0 335
Chris@0 336 if (isset($form['taxonomy_forums'])) {
Chris@0 337 $widget =& $form['taxonomy_forums']['widget'];
Chris@0 338 // Make the vocabulary required for 'real' forum-nodes.
Chris@0 339 $widget['#required'] = TRUE;
Chris@0 340 $widget['#multiple'] = FALSE;
Chris@0 341 if (empty($widget['#default_value'])) {
Chris@0 342 // If there is no default forum already selected, try to get the forum
Chris@0 343 // ID from the URL (e.g., if we are on a page like node/add/forum/2, we
Chris@0 344 // expect "2" to be the ID of the forum that was requested).
Chris@0 345 $requested_forum_id = \Drupal::request()->query->get('forum_id');
Chris@0 346 $widget['#default_value'] = is_numeric($requested_forum_id) ? $requested_forum_id : '';
Chris@0 347 }
Chris@0 348 }
Chris@0 349 }
Chris@0 350
Chris@0 351 /**
Chris@0 352 * Implements hook_preprocess_HOOK() for block templates.
Chris@0 353 */
Chris@0 354 function forum_preprocess_block(&$variables) {
Chris@0 355 if ($variables['configuration']['provider'] == 'forum') {
Chris@0 356 $variables['attributes']['role'] = 'navigation';
Chris@0 357 }
Chris@0 358 }
Chris@0 359
Chris@0 360 /**
Chris@0 361 * Implements hook_theme_suggestions_HOOK().
Chris@0 362 */
Chris@0 363 function forum_theme_suggestions_forums(array $variables) {
Chris@0 364 $suggestions = [];
Chris@0 365 $tid = $variables['term']->id();
Chris@0 366
Chris@0 367 // Provide separate template suggestions based on what's being output. Topic
Chris@0 368 // ID is also accounted for. Check both variables to be safe then the inverse.
Chris@0 369 // Forums with topic IDs take precedence.
Chris@0 370 if ($variables['forums'] && !$variables['topics']) {
Chris@0 371 $suggestions[] = 'forums__containers';
Chris@0 372 $suggestions[] = 'forums__' . $tid;
Chris@0 373 $suggestions[] = 'forums__containers__' . $tid;
Chris@0 374 }
Chris@0 375 elseif (!$variables['forums'] && $variables['topics']) {
Chris@0 376 $suggestions[] = 'forums__topics';
Chris@0 377 $suggestions[] = 'forums__' . $tid;
Chris@0 378 $suggestions[] = 'forums__topics__' . $tid;
Chris@0 379 }
Chris@0 380 else {
Chris@0 381 $suggestions[] = 'forums__' . $tid;
Chris@0 382 }
Chris@0 383
Chris@0 384 return $suggestions;
Chris@0 385 }
Chris@0 386
Chris@0 387 /**
Chris@0 388 * Prepares variables for forums templates.
Chris@0 389 *
Chris@0 390 * Default template: forums.html.twig.
Chris@0 391 *
Chris@0 392 * @param array $variables
Chris@0 393 * An array containing the following elements:
Chris@0 394 * - forums: An array of all forum objects to display for the given taxonomy
Chris@0 395 * term ID. If tid = 0 then all the top-level forums are displayed.
Chris@0 396 * - topics: An array of all the topics in the current forum.
Chris@0 397 * - parents: An array of taxonomy term objects that are ancestors of the
Chris@0 398 * current term ID.
Chris@0 399 * - term: Taxonomy term of the current forum.
Chris@0 400 * - sortby: One of the following integers indicating the sort criteria:
Chris@0 401 * - 1: Date - newest first.
Chris@0 402 * - 2: Date - oldest first.
Chris@0 403 * - 3: Posts with the most comments first.
Chris@0 404 * - 4: Posts with the least comments first.
Chris@0 405 * - forum_per_page: The maximum number of topics to display per page.
Chris@0 406 */
Chris@0 407 function template_preprocess_forums(&$variables) {
Chris@0 408 $variables['tid'] = $variables['term']->id();
Chris@0 409 if ($variables['forums_defined'] = count($variables['forums']) || count($variables['parents'])) {
Chris@0 410 if (!empty($variables['forums'])) {
Chris@0 411 $variables['forums'] = [
Chris@0 412 '#theme' => 'forum_list',
Chris@0 413 '#forums' => $variables['forums'],
Chris@0 414 '#parents' => $variables['parents'],
Chris@0 415 '#tid' => $variables['tid'],
Chris@0 416 ];
Chris@0 417 }
Chris@0 418
Chris@0 419 if ($variables['term'] && empty($variables['term']->forum_container->value) && !empty($variables['topics'])) {
Chris@0 420 $forum_topic_list_header = $variables['header'];
Chris@0 421
Chris@0 422 $table = [
Chris@0 423 '#theme' => 'table__forum_topic_list',
Chris@0 424 '#responsive' => FALSE,
Chris@0 425 '#attributes' => ['id' => 'forum-topic-' . $variables['tid']],
Chris@0 426 '#header' => [],
Chris@0 427 '#rows' => [],
Chris@0 428 ];
Chris@0 429
Chris@0 430 if (!empty($forum_topic_list_header)) {
Chris@0 431 $table['#header'] = $forum_topic_list_header;
Chris@0 432 }
Chris@0 433
Chris@0 434 /** @var \Drupal\node\NodeInterface $topic */
Chris@0 435 foreach ($variables['topics'] as $id => $topic) {
Chris@0 436 $variables['topics'][$id]->icon = [
Chris@0 437 '#theme' => 'forum_icon',
Chris@0 438 '#new_posts' => $topic->new,
Chris@0 439 '#num_posts' => $topic->comment_count,
Chris@0 440 '#comment_mode' => $topic->comment_mode,
Chris@0 441 '#sticky' => $topic->isSticky(),
Chris@0 442 '#first_new' => $topic->first_new,
Chris@0 443 ];
Chris@0 444
Chris@0 445 // We keep the actual tid in forum table, if it's different from the
Chris@0 446 // current tid then it means the topic appears in two forums, one of
Chris@0 447 // them is a shadow copy.
Chris@0 448 if ($variables['tid'] != $topic->forum_tid) {
Chris@0 449 $variables['topics'][$id]->moved = TRUE;
Chris@0 450 $variables['topics'][$id]->title = $topic->getTitle();
Chris@0 451 $variables['topics'][$id]->message = \Drupal::l(t('This topic has been moved'), new Url('forum.page', ['taxonomy_term' => $topic->forum_tid]));
Chris@0 452 }
Chris@0 453 else {
Chris@0 454 $variables['topics'][$id]->moved = FALSE;
Chris@18 455 $variables['topics'][$id]->title_link = \Drupal::l($topic->getTitle(), $topic->toUrl());
Chris@0 456 $variables['topics'][$id]->message = '';
Chris@0 457 }
Chris@0 458 $forum_submitted = [
Chris@0 459 '#theme' => 'forum_submitted',
Chris@0 460 '#topic' => (object) [
Chris@0 461 'uid' => $topic->getOwnerId(),
Chris@0 462 'name' => $topic->getOwner()->getDisplayName(),
Chris@0 463 'created' => $topic->getCreatedTime(),
Chris@0 464 ],
Chris@0 465 ];
Chris@0 466 $variables['topics'][$id]->submitted = \Drupal::service('renderer')->render($forum_submitted);
Chris@0 467 $forum_submitted = [
Chris@0 468 '#theme' => 'forum_submitted',
Chris@0 469 '#topic' => isset($topic->last_reply) ? $topic->last_reply : NULL,
Chris@0 470 ];
Chris@0 471 $variables['topics'][$id]->last_reply = \Drupal::service('renderer')->render($forum_submitted);
Chris@0 472
Chris@0 473 $variables['topics'][$id]->new_text = '';
Chris@0 474 $variables['topics'][$id]->new_url = '';
Chris@0 475
Chris@0 476 if ($topic->new_replies) {
Chris@0 477 $page_number = \Drupal::entityManager()->getStorage('comment')
Chris@0 478 ->getNewCommentPageNumber($topic->comment_count, $topic->new_replies, $topic, 'comment_forum');
Chris@0 479 $query = $page_number ? ['page' => $page_number] : NULL;
Chris@0 480 $variables['topics'][$id]->new_text = \Drupal::translation()->formatPlural($topic->new_replies, '1 new post<span class="visually-hidden"> in topic %title</span>', '@count new posts<span class="visually-hidden"> in topic %title</span>', ['%title' => $variables['topics'][$id]->label()]);
Chris@18 481 $variables['topics'][$id]->new_url = Url::fromRoute('entity.node.canonical', ['node' => $topic->id()], ['query' => $query, 'fragment' => 'new'])->toString();
Chris@0 482 }
Chris@0 483
Chris@0 484 // Build table rows from topics.
Chris@0 485 $row = [];
Chris@0 486 $row[] = [
Chris@0 487 'data' => [
Chris@0 488 $topic->icon,
Chris@0 489 [
Chris@0 490 '#markup' => '<div class="forum__title"><div>' . $topic->title_link . '</div><div>' . $topic->submitted . '</div></div>',
Chris@0 491 ],
Chris@0 492 ],
Chris@0 493 'class' => ['forum__topic'],
Chris@0 494 ];
Chris@0 495
Chris@0 496 if ($topic->moved) {
Chris@0 497 $row[] = [
Chris@0 498 'data' => $topic->message,
Chris@0 499 'colspan' => '2',
Chris@0 500 ];
Chris@0 501 }
Chris@0 502 else {
Chris@0 503 $new_replies = '';
Chris@0 504 if ($topic->new_replies) {
Chris@0 505 $new_replies = '<br /><a href="' . $topic->new_url . '">' . $topic->new_text . '</a>';
Chris@0 506 }
Chris@0 507
Chris@0 508 $row[] = [
Chris@0 509 'data' => [
Chris@0 510 [
Chris@0 511 '#prefix' => $topic->comment_count,
Chris@0 512 '#markup' => $new_replies,
Chris@0 513 ],
Chris@0 514 ],
Chris@0 515 'class' => ['forum__replies'],
Chris@0 516 ];
Chris@0 517 $row[] = [
Chris@0 518 'data' => $topic->last_reply,
Chris@0 519 'class' => ['forum__last-reply'],
Chris@0 520 ];
Chris@0 521 }
Chris@0 522 $table['#rows'][] = $row;
Chris@0 523 }
Chris@0 524
Chris@17 525 $variables['topics_original'] = $variables['topics'];
Chris@0 526 $variables['topics'] = $table;
Chris@0 527 $variables['topics_pager'] = [
Chris@0 528 '#type' => 'pager',
Chris@0 529 ];
Chris@0 530 }
Chris@0 531 }
Chris@0 532 }
Chris@0 533
Chris@0 534 /**
Chris@0 535 * Prepares variables for forum list templates.
Chris@0 536 *
Chris@0 537 * Default template: forum-list.html.twig.
Chris@0 538 *
Chris@0 539 * @param array $variables
Chris@0 540 * An array containing the following elements:
Chris@0 541 * - forums: An array of all forum objects to display for the given taxonomy
Chris@0 542 * term ID. If tid = 0 then all the top-level forums are displayed.
Chris@0 543 * - parents: An array of taxonomy term objects that are ancestors of the
Chris@0 544 * current term ID.
Chris@0 545 * - tid: Taxonomy term ID of the current forum.
Chris@0 546 */
Chris@0 547 function template_preprocess_forum_list(&$variables) {
Chris@0 548 $user = \Drupal::currentUser();
Chris@0 549 $row = 0;
Chris@0 550 // Sanitize each forum so that the template can safely print the data.
Chris@0 551 foreach ($variables['forums'] as $id => $forum) {
Chris@0 552 $variables['forums'][$id]->description = ['#markup' => $forum->description->value];
Chris@0 553 $variables['forums'][$id]->link = forum_uri($forum);
Chris@0 554 $variables['forums'][$id]->name = $forum->label();
Chris@0 555 $variables['forums'][$id]->is_container = !empty($forum->forum_container->value);
Chris@0 556 $variables['forums'][$id]->zebra = $row % 2 == 0 ? 'odd' : 'even';
Chris@0 557 $row++;
Chris@0 558
Chris@0 559 $variables['forums'][$id]->new_text = '';
Chris@0 560 $variables['forums'][$id]->new_url = '';
Chris@0 561 $variables['forums'][$id]->new_topics = 0;
Chris@0 562 $variables['forums'][$id]->old_topics = $forum->num_topics;
Chris@0 563 $variables['forums'][$id]->icon_class = 'default';
Chris@0 564 $variables['forums'][$id]->icon_title = t('No new posts');
Chris@0 565 if ($user->isAuthenticated()) {
Chris@0 566 $variables['forums'][$id]->new_topics = \Drupal::service('forum_manager')->unreadTopics($forum->id(), $user->id());
Chris@0 567 if ($variables['forums'][$id]->new_topics) {
Chris@0 568 $variables['forums'][$id]->new_text = \Drupal::translation()->formatPlural($variables['forums'][$id]->new_topics, '1 new post<span class="visually-hidden"> in forum %title</span>', '@count new posts<span class="visually-hidden"> in forum %title</span>', ['%title' => $variables['forums'][$id]->label()]);
Chris@18 569 $variables['forums'][$id]->new_url = Url::fromRoute('forum.page', ['taxonomy_term' => $forum->id()], ['fragment' => 'new'])->toString();
Chris@0 570 $variables['forums'][$id]->icon_class = 'new';
Chris@0 571 $variables['forums'][$id]->icon_title = t('New posts');
Chris@0 572 }
Chris@0 573 $variables['forums'][$id]->old_topics = $forum->num_topics - $variables['forums'][$id]->new_topics;
Chris@0 574 }
Chris@0 575 $forum_submitted = ['#theme' => 'forum_submitted', '#topic' => $forum->last_post];
Chris@0 576 $variables['forums'][$id]->last_reply = \Drupal::service('renderer')->render($forum_submitted);
Chris@0 577 }
Chris@0 578
Chris@0 579 $variables['pager'] = [
Chris@0 580 '#type' => 'pager',
Chris@0 581 ];
Chris@0 582
Chris@0 583 // Give meaning to $tid for themers. $tid actually stands for term ID.
Chris@0 584 $variables['forum_id'] = $variables['tid'];
Chris@0 585 unset($variables['tid']);
Chris@0 586 }
Chris@0 587
Chris@0 588 /**
Chris@0 589 * Prepares variables for forum icon templates.
Chris@0 590 *
Chris@0 591 * Default template: forum-icon.html.twig.
Chris@0 592 *
Chris@0 593 * @param array $variables
Chris@0 594 * An array containing the following elements:
Chris@0 595 * - new_posts: Indicates whether or not the topic contains new posts.
Chris@0 596 * - num_posts: The total number of posts in all topics.
Chris@0 597 * - comment_mode: An integer indicating whether comments are open, closed,
Chris@0 598 * or hidden.
Chris@0 599 * - sticky: Indicates whether the topic is sticky.
Chris@0 600 * - first_new: Indicates whether this is the first topic with new posts.
Chris@0 601 */
Chris@0 602 function template_preprocess_forum_icon(&$variables) {
Chris@0 603 $variables['hot_threshold'] = \Drupal::config('forum.settings')->get('topics.hot_threshold');
Chris@0 604
Chris@0 605 if ($variables['num_posts'] > $variables['hot_threshold']) {
Chris@0 606 $variables['icon_status'] = $variables['new_posts'] ? 'hot-new' : 'hot';
Chris@0 607 $variables['icon_title'] = $variables['new_posts'] ? t('Hot topic, new comments') : t('Hot topic');
Chris@0 608 }
Chris@0 609 else {
Chris@0 610 $variables['icon_status'] = $variables['new_posts'] ? 'new' : 'default';
Chris@0 611 $variables['icon_title'] = $variables['new_posts'] ? t('New comments') : t('Normal topic');
Chris@0 612 }
Chris@0 613
Chris@0 614 if ($variables['comment_mode'] == CommentItemInterface::CLOSED || $variables['comment_mode'] == CommentItemInterface::HIDDEN) {
Chris@0 615 $variables['icon_status'] = 'closed';
Chris@0 616 $variables['icon_title'] = t('Closed topic');
Chris@0 617 }
Chris@0 618
Chris@0 619 if ($variables['sticky'] == 1) {
Chris@0 620 $variables['icon_status'] = 'sticky';
Chris@0 621 $variables['icon_title'] = t('Sticky topic');
Chris@0 622 }
Chris@0 623
Chris@0 624 $variables['attributes']['title'] = $variables['icon_title'];
Chris@0 625 }
Chris@0 626
Chris@0 627 /**
Chris@0 628 * Prepares variables for forum submission information templates.
Chris@0 629 *
Chris@0 630 * The submission information will be displayed in the forum list and topic
Chris@0 631 * list.
Chris@0 632 *
Chris@0 633 * Default template: forum-submitted.html.twig.
Chris@0 634 *
Chris@0 635 * @param array $variables
Chris@0 636 * An array containing the following elements:
Chris@0 637 * - topic: The topic object.
Chris@0 638 */
Chris@0 639 function template_preprocess_forum_submitted(&$variables) {
Chris@0 640 $variables['author'] = '';
Chris@0 641 if (isset($variables['topic']->uid)) {
Chris@0 642 $username = ['#theme' => 'username', '#account' => User::load($variables['topic']->uid)];
Chris@0 643 $variables['author'] = \Drupal::service('renderer')->render($username);
Chris@0 644 }
Chris@0 645 $variables['time'] = isset($variables['topic']->created) ? \Drupal::service('date.formatter')->formatTimeDiffSince($variables['topic']->created) : '';
Chris@0 646 }