diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module
index 574d536..2620420 100644
--- a/core/modules/forum/forum.module
+++ b/core/modules/forum/forum.module
@@ -93,18 +93,11 @@ function forum_theme() {
function forum_menu() {
$items['forum'] = array(
'title' => 'Forums',
- 'page callback' => 'forum_page',
- 'access arguments' => array('access content'),
- 'file' => 'forum.pages.inc',
+ 'route_name' => 'forum_page',
);
- $items['forum/%forum_forum'] = array(
+ $items['forum/%forum'] = array(
'title' => 'Forums',
- 'title callback' => 'entity_page_label',
- 'title arguments' => array(1),
- 'page callback' => 'forum_page',
- 'page arguments' => array(1),
- 'access arguments' => array('access content'),
- 'file' => 'forum.pages.inc',
+ 'route_name' => 'forum_forum_page',
);
$items['admin/structure/forum'] = array(
'title' => 'Forums',
@@ -118,6 +111,7 @@ function forum_menu() {
'title' => 'List',
'type' => MENU_DEFAULT_LOCAL_TASK,
);
+ // @todo route and form controllerify this.
$items['admin/structure/forum/add/container'] = array(
'title' => 'Add container',
'page callback' => 'forum_form_main',
@@ -127,6 +121,7 @@ function forum_menu() {
'parent' => 'admin/structure/forum',
'file' => 'forum.admin.inc',
);
+ // @todo route and form controllerify this.
$items['admin/structure/forum/add/forum'] = array(
'title' => 'Add forum',
'page callback' => 'forum_form_main',
@@ -136,6 +131,7 @@ function forum_menu() {
'parent' => 'admin/structure/forum',
'file' => 'forum.admin.inc',
);
+ // @todo route and form controllerify this.
$items['admin/structure/forum/settings'] = array(
'title' => 'Settings',
'page callback' => 'drupal_get_form',
@@ -146,6 +142,7 @@ function forum_menu() {
'parent' => 'admin/structure/forum',
'file' => 'forum.admin.inc',
);
+ // @todo route and form controllerify this.
$items['admin/structure/forum/edit/container/%taxonomy_term'] = array(
'title' => 'Edit container',
'page callback' => 'forum_form_main',
@@ -153,6 +150,7 @@ function forum_menu() {
'access arguments' => array('administer forums'),
'file' => 'forum.admin.inc',
);
+ // @todo route and form controllerify this.
$items['admin/structure/forum/edit/forum/%taxonomy_term'] = array(
'title' => 'Edit forum',
'page callback' => 'forum_form_main',
@@ -171,48 +169,45 @@ function forum_menu_local_tasks(&$data, $router_item, $root_path) {
// Add action link to 'node/add/forum' on 'forum' sub-pages.
if ($root_path == 'forum' || $root_path == 'forum/%') {
- $tid = (isset($router_item['page_arguments'][0]) ? $router_item['page_arguments'][0]->tid : 0);
- $forum_term = forum_forum_load($tid);
- if ($forum_term) {
- $links = array();
- // Loop through all bundles for forum taxonomy vocabulary field.
- $field = field_info_field('taxonomy_forums');
- foreach ($field['bundles']['node'] as $type) {
- if (node_access('create', $type)) {
- $links[$type] = array(
- '#theme' => 'menu_local_action',
- '#link' => array(
- 'title' => t('Add new @node_type', array('@node_type' => node_type_get_label($type))),
- 'href' => 'node/add/' . $type . '/' . $forum_term->tid,
- ),
- );
- }
+ $tid = (isset($router_item['page_arguments'][0]) ? $router_item['page_arguments'][0] : 0);
+ $links = array();
+ // Loop through all bundles for forum taxonomy vocabulary field.
+ $field = field_info_field('taxonomy_forums');
+ foreach ($field['bundles']['node'] as $type) {
+ if (node_access('create', $type)) {
+ $links[$type] = array(
+ '#theme' => 'menu_local_action',
+ '#link' => array(
+ 'title' => t('Add new @node_type', array('@node_type' => node_type_get_label($type))),
+ 'href' => 'node/add/' . $type . '/' . $tid,
+ ),
+ );
}
- if (empty($links)) {
- // Authenticated user does not have access to create new topics.
- if ($user->uid) {
- $links['disallowed'] = array(
- '#theme' => 'menu_local_action',
- '#link' => array(
- 'title' => t('You are not allowed to post new content in the forum.'),
- ),
- );
- }
- // Anonymous user does not have access to create new topics.
- else {
- $links['login'] = array(
- '#theme' => 'menu_local_action',
- '#link' => array(
- 'title' => t('Log in to post new content in the forum.', array(
- '@login' => url('user/login', array('query' => drupal_get_destination())),
- )),
- 'localized_options' => array('html' => TRUE),
- ),
- );
- }
+ }
+ if (empty($links)) {
+ // Authenticated user does not have access to create new topics.
+ if ($user->uid) {
+ $links['disallowed'] = array(
+ '#theme' => 'menu_local_action',
+ '#link' => array(
+ 'title' => t('You are not allowed to post new content in the forum.'),
+ ),
+ );
+ }
+ // Anonymous user does not have access to create new topics.
+ else {
+ $links['login'] = array(
+ '#theme' => 'menu_local_action',
+ '#link' => array(
+ 'title' => t('Log in to post new content in the forum.', array(
+ '@login' => url('user/login', array('query' => drupal_get_destination())),
+ )),
+ 'localized_options' => array('html' => TRUE),
+ ),
+ );
}
- $data['actions'] += $links;
}
+ $data['actions'] += $links;
}
}
@@ -675,125 +670,6 @@ function forum_form(EntityInterface $node, &$form_state) {
}
/**
- * Returns a tree of all forums for a given taxonomy term ID.
- *
- * @param $tid
- * (optional) Taxonomy term ID of the forum. If not given all forums will be
- * returned.
- *
- * @return
- * A tree of taxonomy objects, with the following additional properties:
- * - num_topics: Number of topics in the forum.
- * - num_posts: Total number of posts in all topics.
- * - last_post: Most recent post for the forum.
- * - forums: An array of child forums.
- */
-function forum_forum_load($tid = NULL) {
- $cache = &drupal_static(__FUNCTION__, array());
-
- // Return a cached forum tree if available.
- if (!isset($tid)) {
- $tid = 0;
- }
- if (isset($cache[$tid])) {
- return $cache[$tid];
- }
-
- $config = config('forum.settings');
- $vid = $config->get('vocabulary');
-
- // Load and validate the parent term.
- if ($tid) {
- $forum_term = taxonomy_term_load($tid);
- if (!$forum_term || ($forum_term->bundle() != $vid)) {
- return $cache[$tid] = FALSE;
- }
- }
- // If $tid is 0, create an empty entity to hold the child terms.
- elseif ($tid === 0) {
- $forum_term = entity_create('taxonomy_term', array(
- 'tid' => 0,
- ));
- }
-
- // Determine if the requested term is a container.
- if (!$forum_term->tid || in_array($forum_term->tid, $config->get('containers'))) {
- $forum_term->container = 1;
- }
-
- // Load parent terms.
- $forum_term->parents = taxonomy_term_load_parents_all($forum_term->tid);
-
- // Load the tree below.
- $forums = array();
- $_forums = taxonomy_get_tree($vid, $tid, NULL, TRUE);
-
- if (count($_forums)) {
- $query = db_select('node', 'n');
- $query->join('node_comment_statistics', 'ncs', 'n.nid = ncs.nid');
- $query->join('forum', 'f', 'n.vid = f.vid');
- $query->addExpression('COUNT(n.nid)', 'topic_count');
- $query->addExpression('SUM(ncs.comment_count)', 'comment_count');
- $counts = $query
- ->fields('f', array('tid'))
- ->condition('n.status', 1)
- ->groupBy('tid')
- ->addTag('node_access')
- ->execute()
- ->fetchAllAssoc('tid');
- }
-
- foreach ($_forums as $forum) {
- // Determine if the child term is a container.
- if (in_array($forum->tid, $config->get('containers'))) {
- $forum->container = 1;
- }
-
- // Merge in the topic and post counters.
- if (!empty($counts[$forum->tid])) {
- $forum->num_topics = $counts[$forum->tid]->topic_count;
- $forum->num_posts = $counts[$forum->tid]->topic_count + $counts[$forum->tid]->comment_count;
- }
- else {
- $forum->num_topics = 0;
- $forum->num_posts = 0;
- }
-
- // Query "Last Post" information for this forum.
- $query = db_select('node', 'n');
- $query->join('forum', 'f', 'n.vid = f.vid AND f.tid = :tid', array(':tid' => $forum->tid));
- $query->join('node_comment_statistics', 'ncs', 'n.nid = ncs.nid');
- $query->join('users', 'u', 'ncs.last_comment_uid = u.uid');
- $query->addExpression('CASE ncs.last_comment_uid WHEN 0 THEN ncs.last_comment_name ELSE u.name END', 'last_comment_name');
-
- $topic = $query
- ->fields('ncs', array('last_comment_timestamp', 'last_comment_uid'))
- ->condition('n.status', 1)
- ->orderBy('last_comment_timestamp', 'DESC')
- ->range(0, 1)
- ->addTag('node_access')
- ->execute()
- ->fetchObject();
-
- // Merge in the "Last Post" information.
- $last_post = new stdClass();
- if (!empty($topic->last_comment_timestamp)) {
- $last_post->created = $topic->last_comment_timestamp;
- $last_post->name = $topic->last_comment_name;
- $last_post->uid = $topic->last_comment_uid;
- }
- $forum->last_post = $last_post;
-
- $forums[$forum->tid] = $forum;
- }
-
- // Cache the result, and return the tree.
- $forum_term->forums = $forums;
- $cache[$tid] = $forum_term;
- return $forum_term;
-}
-
-/**
* Calculates the number of new posts in a forum that the user has not yet read.
*
* Nodes are new if they are newer than HISTORY_READ_LIMIT.
diff --git a/core/modules/forum/forum.routing.yml b/core/modules/forum/forum.routing.yml
new file mode 100644
index 0000000..155bc57
--- /dev/null
+++ b/core/modules/forum/forum.routing.yml
@@ -0,0 +1,12 @@
+forum_page:
+ pattern: 'forum'
+ defaults:
+ _content: 'Drupal\forum\Controller\ForumController::forumPage'
+ requirements:
+ _permission: 'access content'
+forum_forum_page:
+ pattern: 'forum/{forum}'
+ defaults:
+ _content: 'Drupal\forum\Controller\ForumController::forumPage'
+ requirements:
+ _permission: 'access content'
diff --git a/core/modules/forum/lib/Drupal/forum/Controller/ForumController.php b/core/modules/forum/lib/Drupal/forum/Controller/ForumController.php
new file mode 100644
index 0000000..1e33923
--- /dev/null
+++ b/core/modules/forum/lib/Drupal/forum/Controller/ForumController.php
@@ -0,0 +1,144 @@
+get('config.factory'), $container->get('plugin.manager.entity'));
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param \Drupal\Core\Config\ConfigFactory $config_factory
+ * The config factory.
+ */
+ public function __construct(ConfigFactory $config_factory, EntityManager $entity_manager) {
+ $this->config = $config_factory->get('forum.settings');
+ $this->storageController = $entity_manager->getStorageController('forum');
+ }
+
+ /**
+ * Returns a forum page.
+ *
+ * @param \Drupal\forum\Plugin\Core\Entity\Forum $forum
+ * (optional) The forum to render the page for. If empty, the forum index is
+ * rendered instead. Defaults to NULL.
+ */
+ public function forumPage(Forum $forum = NULL) {
+ if ($forum) {
+ return $this->forumForumPage($forum);
+ }
+ // Index page.
+ return $this->forumIndex();
+ }
+
+ /**
+ * Returns forum page for a given forum.
+ *
+ * @param \Drupal\forum\Plugin\Core\Entity\Forum $forum
+ * The forum to render the page for.
+ *
+ * @return array
+ * A render array.
+ */
+ protected function forumForumPage(Forum $forum) {
+ // Page title.
+ drupal_set_title($forum->label());
+ // Breadcrumb navigation.
+ $vocabulary = entity_load('taxonomy_vocabulary', $this->config->get('vocabulary'));
+ $breadcrumb[] = l(t('Home'), NULL);
+ $breadcrumb[] = l($vocabulary->label(), 'forum');
+ foreach (array_reverse($forum->parents) as $parent) {
+ if ($parent->id() != $forum->id()) {
+ $breadcrumb[] = l($parent->label(), 'forum/' . $parent->id());
+ }
+ }
+ drupal_set_breadcrumb($breadcrumb);
+ if ($forum->container) {
+ // Add RSS feed for forums.
+ drupal_add_feed('taxonomy/term/' . $forum->id() . '/feed', 'RSS - ' . $forum->label());
+ }
+ $forum_per_page = $this->config->get('topics.page_limit');
+ $sort_by = $this->config->get('topics.order');
+
+ if (!$forum->container) {
+ $topics = forum_get_topics($forum->id(), $sort_by, $forum_per_page);
+ }
+ else {
+ $topics = '';
+ }
+
+ $build = array(
+ '#theme' => 'forums',
+ '#forums' => $forum->forums,
+ '#topics' => $topics,
+ '#parents' => $forum->parents,
+ '#tid' => $forum->id(),
+ '#sortby' => $sort_by,
+ '#forums_per_page' => $forum_per_page,
+ );
+ $build['#attached']['css'][] = drupal_get_path('module', 'forum') . '/forum.css';
+ return $build;
+ }
+
+ /**
+ * Returns forum index page.
+ *
+ * @return array
+ * A render array.
+ */
+ protected function forumIndex() {
+ $vocabulary = entity_load('taxonomy_vocabulary', $this->config->get('vocabulary'));
+ $index = $this->storageController->forumIndex();
+ // Set the page title to forum's vocabulary name.
+ drupal_set_title($vocabulary->label());
+ if (empty($index->forums)) {
+ // Root of empty forum.
+ drupal_set_title(t('No forums defined'));
+ }
+
+ $build = array(
+ '#theme' => 'forums',
+ '#forums' => $index->forums,
+ '#topics' => '',
+ '#parents' => array(),
+ '#tid' => $index->id(),
+ '#sortby' => $this->config->get('topics.order'),
+ '#forums_per_page' => $this->config->get('topics.page_limit'),
+ );
+ $build['#attached']['css'][] = drupal_get_path('module', 'forum') . '/forum.css';
+ return $build;
+ }
+
+}
diff --git a/core/modules/forum/lib/Drupal/forum/ForumFormController.php b/core/modules/forum/lib/Drupal/forum/ForumFormController.php
new file mode 100644
index 0000000..17419c7
--- /dev/null
+++ b/core/modules/forum/lib/Drupal/forum/ForumFormController.php
@@ -0,0 +1,27 @@
+config = config('forum.settings');
+ }
+
+ /**
+ * Overrides \Drupal\Core\Entity\DatabaseStorageController::delete().
+ */
+ public function delete(array $entities) {
+ parent::delete($entities);
+ // For containers, remove the tid from the forum_containers variable.
+ $containers = $this->config->get('containers');
+ foreach (array_keys($entities) as $tid) {
+ if (!empty($containser[$tid])) {
+ unset($containers[$tid]);
+ }
+ }
+ $this->config->set('containers', $containers)->save();
+ }
+
+ /**
+ * Overrides \Drupal\Core\Entity\DatabaseStorageController::load().
+ */
+ public function load(array $ids = NULL) {
+ $entities = parent::load($ids);
+ $vid = $this->config->get('vocabulary');
+ foreach ($entities as $tid => &$forum_term) {
+ if ($forum_term->bundle() != $vid) {
+ // Not a forum term.
+ unset($entities[$tid]);
+ }
+
+ // Determine if the requested term is a container.
+ if (in_array($forum_term->id(), $this->config->get('containers'))) {
+ $forum_term->container = TRUE;
+ }
+
+ // Load parent terms.
+ // @todo - is this still needed?
+ $forum_term->parents = taxonomy_term_load_parents_all($forum_term->id());
+
+ // Load the tree below.
+ $forum_term->forums = $this->getChildren($vid, $tid);
+ }
+ return $entities;
+ }
+
+ /**
+ * Utility method to get the last post information for the given forum tid.
+ *
+ * @param int $tid
+ * The forum tid.
+ *
+ * @return \stdClass
+ * The last post for the given forum.
+ */
+ protected function getLastPost($tid) {
+ if (!empty($this->lastPostData[$tid])) {
+ return $this->lastPostData[$tid];
+ }
+ // Query "Last Post" information for this forum.
+ $query = db_select('node', 'n');
+ $query->join('forum', 'f', 'n.vid = f.vid AND f.tid = :tid', array(':tid' => $tid));
+ $query->join('node_comment_statistics', 'ncs', 'n.nid = ncs.nid');
+ $query->join('users', 'u', 'ncs.last_comment_uid = u.uid');
+ $query->addExpression('CASE ncs.last_comment_uid WHEN 0 THEN ncs.last_comment_name ELSE u.name END', 'last_comment_name');
+
+ $topic = $query
+ ->fields('ncs', array('last_comment_timestamp', 'last_comment_uid'))
+ ->condition('n.status', 1)
+ ->orderBy('last_comment_timestamp', 'DESC')
+ ->range(0, 1)
+ ->addTag('node_access')
+ ->execute()
+ ->fetchObject();
+
+ // Build the last post information.
+ $last_post = new \stdClass();
+ if (!empty($topic->last_comment_timestamp)) {
+ $last_post->created = $topic->last_comment_timestamp;
+ $last_post->name = $topic->last_comment_name;
+ $last_post->uid = $topic->last_comment_uid;
+ }
+
+ $this->lastPostData[$tid] = $last_post;
+ return $last_post;
+ }
+
+ /**
+ * Utility method to fetch statistics for a forum.
+ *
+ * @param int $tid
+ * The forum tid.
+ *
+ * @return \stdClass|NULL
+ * Statistics for the given forum if statistics exist, else NULL
+ */
+ protected function getForumStatistics($tid) {
+ if (empty($this->forumStatistics)) {
+ // Prime the statistics.
+ $query = db_select('node', 'n');
+ $query->join('node_comment_statistics', 'ncs', 'n.nid = ncs.nid');
+ $query->join('forum', 'f', 'n.vid = f.vid');
+ $query->addExpression('COUNT(n.nid)', 'topic_count');
+ $query->addExpression('SUM(ncs.comment_count)', 'comment_count');
+ $this->forumStatistics = $query
+ ->fields('f', array('tid'))
+ ->condition('n.status', 1)
+ ->groupBy('tid')
+ ->addTag('node_access')
+ ->execute()
+ ->fetchAllAssoc('tid');
+ }
+
+ if (!empty($this->forumStatistics[$tid])) {
+ return $this->forumStatistics[$tid];
+ }
+ }
+
+ /**
+ * Utility method to fetch the child forums for a given forum.
+ *
+ * @param int $vid
+ * The forum vocabulary id.
+ * @param int $tid
+ * The forum id to fetch the children for.
+ *
+ * @return array
+ * Array of children.
+ */
+ protected function getChildren($vid, $tid) {
+ if (!empty($this->forumChildren[$tid])) {
+ return $this->forumChildren[$tid];
+ }
+ $forums = array();
+ $_forums = taxonomy_get_tree($vid, $tid, NULL, TRUE);
+ foreach ($_forums as $forum) {
+ // Determine if the child term is a container.
+ if (in_array($forum->tid, $this->config->get('containers'))) {
+ $forum->container = TRUE;
+ }
+
+ // Merge in the topic and post counters.
+ if (($count = $this->getForumStatistics($forum->tid))) {
+ $forum->num_topics = $count->topic_count;
+ $forum->num_posts = $count->topic_count + $count->comment_count;
+ }
+ else {
+ $forum->num_topics = 0;
+ $forum->num_posts = 0;
+ }
+
+ // Merge in last post details.
+ $forum->last_post = $this->getLastPost($forum->tid);
+ $forums[$forum->tid] = $forum;
+ }
+
+ $this->forumChildren[$tid] = $forums;
+ return $forums;
+ }
+
+ /**
+ * Generates and returns the forum index.
+ *
+ * The forum index is a psuedo term that provides an overview of all forums.
+ *
+ * @return \Drupal\taxonomy\Plugin\Core\Entity\Term
+ * A psuedo term representing the overview of all forums.
+ */
+ public function forumIndex() {
+ if ($this->index) {
+ return $index;
+ }
+
+ $index = $this->create(array(
+ 'tid' => 0,
+ 'container' => TRUE,
+ 'parents' => array(),
+ 'isIndex' => TRUE,
+ ));
+
+ // Load the tree below.
+ $index->forums = $this->getChildren($this->config->get('vocabulary'), 0);
+ $this->index = $index;
+ return $index;
+ }
+
+ /**
+ * Overrides \Drupal\Core\Entity\DatabaseStorageController::resetCache().
+ */
+ public function resetCache(array $ids = NULL) {
+ parent::resetCache($ids);
+ // Reset the index.
+ $this->index = NULL;
+ }
+
+ /**
+ * Overrides \Drupal\Core\Entity\DatabaseStorageController::save().
+ */
+ public function save(EntityInterface $entity) {
+ if (!empty($entity->isIndex)) {
+ throw new Exception(t('The forum index cannot be saved'));
+ }
+ return parent::save($entity);
+ }
+}
diff --git a/core/modules/forum/lib/Drupal/forum/Plugin/Core/Entity/Forum.php b/core/modules/forum/lib/Drupal/forum/Plugin/Core/Entity/Forum.php
new file mode 100644
index 0000000..759a94d
--- /dev/null
+++ b/core/modules/forum/lib/Drupal/forum/Plugin/Core/Entity/Forum.php
@@ -0,0 +1,84 @@
+ 'forum/' . $this->id(),
+ );
+ }
+}