From a080a523d6317fa8679383261a65c3650a37f0cf Mon Sep 17 00:00:00 2001 From: Alex Pott <alex.a.pott@googlemail.com> Date: Tue, 10 Sep 2013 10:55:49 +0200 Subject: [PATCH] Issue #1978958 by jibran, disasm, kgoel, Pancho, vijaycs85, cosmicdreams, dawehner, wamilton: Convert comment_reply() to a Controller. --- core/modules/comment/comment.module | 8 -- core/modules/comment/comment.pages.inc | 101 -------------- core/modules/comment/comment.routing.yml | 9 ++ core/modules/comment/comment.services.yml | 6 + .../comment/CommentBreadcrumbBuilder.php | 58 ++++++++ .../comment/Controller/CommentController.php | 125 +++++++++++++++--- 6 files changed, 181 insertions(+), 126 deletions(-) delete mode 100644 core/modules/comment/comment.pages.inc create mode 100644 core/modules/comment/comment.services.yml create mode 100644 core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 973bccbdd2e9..c3b0357fd4d0 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -228,14 +228,6 @@ function comment_menu() { 'route_name' => 'comment_confirm_delete', 'weight' => 20, ); - $items['comment/reply/%node'] = array( - 'title' => 'Add new comment', - 'page callback' => 'comment_reply', - 'page arguments' => array(2), - 'access callback' => 'node_access', - 'access arguments' => array('view', 2), - 'file' => 'comment.pages.inc', - ); return $items; } diff --git a/core/modules/comment/comment.pages.inc b/core/modules/comment/comment.pages.inc deleted file mode 100644 index d193132b84ff..000000000000 --- a/core/modules/comment/comment.pages.inc +++ /dev/null @@ -1,101 +0,0 @@ -<?php - -/** - * @file - * User page callbacks for the Comment module. - */ - -use Drupal\Core\Entity\EntityInterface; -use Drupal\comment\Entity\Comment; -use Symfony\Component\HttpFoundation\RedirectResponse; -use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException; - -/** - * Form constructor for the comment reply form. - * - * There are several cases that have to be handled, including: - * - replies to comments - * - replies to nodes - * - attempts to reply to nodes that can no longer accept comments - * - respecting access permissions ('access comments', 'post comments', etc.) - * - * The node or comment that is being replied to must appear above the comment - * form to provide the user context while authoring the comment. - * - * @param \Drupal\Core\Entity\EntityInterface $node - * Every comment belongs to a node. This is that node. - * @param $pid - * (optional) Some comments are replies to other comments. In those cases, - * $pid is the parent comment's comment ID. Defaults to NULL. - * - * @return array - * An associative array containing: - * - An array for rendering the node or parent comment. - * - comment_node: If the comment is a reply to the node. - * - comment_parent: If the comment is a reply to another comment. - * - comment_form: The comment form as a renderable array. - */ -function comment_reply(EntityInterface $node, $pid = NULL) { - // Set the breadcrumb trail. - drupal_set_breadcrumb(array(l(t('Home'), NULL), l($node->label(), 'node/' . $node->id()))); - $op = Drupal::request()->request->get('op'); - $build = array(); - - // The user is previewing a comment prior to submitting it. - if ($op == t('Preview')) { - if (user_access('post comments')) { - $build['comment_form'] = comment_add($node, $pid); - } - else { - drupal_set_message(t('You are not authorized to post comments.'), 'error'); - return new RedirectResponse(url('node/' . $node->id(), array('absolute' => TRUE))); - } - } - else { - // $pid indicates that this is a reply to a comment. - if ($pid) { - if (user_access('access comments')) { - // Load the parent comment. - $comment = comment_load($pid); - if ($comment->status->value == COMMENT_PUBLISHED) { - // If that comment exists, make sure that the current comment and the - // parent comment both belong to the same parent node. - if ($comment->nid->target_id != $node->id()) { - // Attempting to reply to a comment not belonging to the current nid. - drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - return new RedirectResponse(url('node/' . $node->id(), array('absolute' => TRUE))); - } - // Display the parent comment - $build['comment_parent'] = comment_view($comment); - } - else { - drupal_set_message(t('The comment you are replying to does not exist.'), 'error'); - return new RedirectResponse(url('node/' . $node->id(), array('absolute' => TRUE))); - } - } - else { - drupal_set_message(t('You are not authorized to view comments.'), 'error'); - return new RedirectResponse(url('node/' . $node->id(), array('absolute' => TRUE))); - } - } - // This is the case where the comment is in response to a node. Display the node. - elseif (user_access('access content')) { - $build['comment_node'] = node_view($node); - } - - // Should we show the reply box? - if ($node->comment->value != COMMENT_NODE_OPEN) { - drupal_set_message(t("This discussion is closed: you can't post new comments."), 'error'); - return new RedirectResponse(url('node/' . $node->id(), array('absolute' => TRUE))); - } - elseif (user_access('post comments')) { - $build['comment_form'] = comment_add($node, $pid); - } - else { - drupal_set_message(t('You are not authorized to post comments.'), 'error'); - return new RedirectResponse(url('node/' . $node->id(), array('absolute' => TRUE))); - } - } - - return $build; -} diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml index 7768cd07f34a..948af220de67 100644 --- a/core/modules/comment/comment.routing.yml +++ b/core/modules/comment/comment.routing.yml @@ -19,9 +19,18 @@ comment_permalink: _controller: '\Drupal\comment\Controller\CommentController::commentPermalink' requirements: _entity_access: 'comment.view' + comment_confirm_delete: pattern: '/comment/{comment}/delete' defaults: _entity_form: 'comment.delete' requirements: _entity_access: 'comment.delete' + +comment_reply: + pattern: 'comment/reply/{node}/{pid}' + defaults: + _content: '\Drupal\comment\Controller\CommentController::getReplyForm' + pid: ~ + requirements: + _entity_access: 'node.view' diff --git a/core/modules/comment/comment.services.yml b/core/modules/comment/comment.services.yml new file mode 100644 index 000000000000..074d8120fd79 --- /dev/null +++ b/core/modules/comment/comment.services.yml @@ -0,0 +1,6 @@ +services: + comment.breadcrumb: + class: Drupal\comment\CommentBreadcrumbBuilder + tags: + - { name: breadcrumb_builder, priority: 100 } + arguments: ['@string_translation'] diff --git a/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php b/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php new file mode 100644 index 000000000000..38dd91fcc8e7 --- /dev/null +++ b/core/modules/comment/lib/Drupal/comment/CommentBreadcrumbBuilder.php @@ -0,0 +1,58 @@ +<?php + +/** + * @file + * Contains \Drupal\comment\CommentBreadcrumbBuilder. + */ + +namespace Drupal\comment; + +use Drupal\Core\Breadcrumb\BreadcrumbBuilderInterface; +use Drupal\Core\StringTranslation\TranslationManager; +use Symfony\Cmf\Component\Routing\RouteObjectInterface; + +/** + * Class to define the comment breadcrumb builder. + */ +class CommentBreadcrumbBuilder implements BreadcrumbBuilderInterface { + + /** + * The translation manager service. + * + * @var \Drupal\Core\StringTranslation\TranslationManager + */ + protected $translation; + + /** + * Constructs a CommentBreadcrumbBuilder object. + * + * @param \Drupal\Core\StringTranslation\TranslationManager $translation + * The translation manager. + */ + public function __construct(TranslationManager $translation) { + $this->translation = $translation; + } + + /** + * {@inheritdoc} + */ + public function build(array $attributes) { + if (isset($attributes[RouteObjectInterface::ROUTE_NAME]) && $attributes[RouteObjectInterface::ROUTE_NAME] == 'comment_reply' && isset($attributes['node'])) { + $node = $attributes['node']; + $uri = $node->uri(); + $breadcrumb[] = l($this->t('Home'), NULL); + $breadcrumb[] = l($node->label(), $uri['path']); + return $breadcrumb; + } + } + + /** + * Translates a string to the current language or to a given language. + * + * See the t() documentation for details. + */ + protected function t($string, array $args = array(), array $options = array()) { + return $this->translation->translate($string, $args, $options); + } + +} diff --git a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php index f7ee85b56eb9..d3f41507a02f 100644 --- a/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php +++ b/core/modules/comment/lib/Drupal/comment/Controller/CommentController.php @@ -9,8 +9,10 @@ use Drupal\comment\CommentInterface; use Drupal\comment\Entity\Comment; +use Drupal\Core\Access\CsrfTokenGenerator; +use Drupal\Core\Controller\ControllerBase; use Drupal\Core\DependencyInjection\ContainerInjectionInterface; -use Drupal\Core\Routing\UrlGeneratorInterface; +use Drupal\Node\NodeInterface; use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -23,41 +25,41 @@ * * @see \Drupal\comment\Entity\Comment. */ -class CommentController implements ContainerInjectionInterface { +class CommentController extends ControllerBase implements ContainerInjectionInterface { /** - * The url generator service. + * The HTTP kernel. * - * @var \Drupal\Core\Routing\UrlGeneratorInterface + * @var \Symfony\Component\HttpKernel\HttpKernelInterface */ - protected $urlGenerator; + protected $httpKernel; /** - * The HTTP kernel. + * The CSRF token manager service. * - * @var \Symfony\Component\HttpKernel\HttpKernelInterface + * @var \Drupal\Core\Access\CsrfTokenGenerator */ - protected $httpKernel; + protected $csrfToken; /** * Constructs a CommentController object. * - * @param \Drupal\Core\Routing\UrlGeneratorInterface $url_generator - * The url generator service. * @param \Symfony\Component\HttpKernel\HttpKernelInterface $httpKernel * HTTP kernel to handle requests. + * @param \Drupal\Core\Access\CsrfTokenGenerator $csrf_token + * The CSRF token manager service. */ - public function __construct(UrlGeneratorInterface $url_generator, HttpKernelInterface $httpKernel) { - $this->urlGenerator = $url_generator; + public function __construct(HttpKernelInterface $httpKernel, CsrfTokenGenerator $csrf_token) { $this->httpKernel = $httpKernel; + $this->csrfToken = $csrf_token; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( - $container->get('url_generator'), - $container->get('http_kernel') + $container->get('http_kernel'), + $container->get('csrf_token') ); } @@ -78,17 +80,17 @@ public function commentApprove(Request $request, CommentInterface $comment) { // Integrate CSRF link token directly into routing system: // https://drupal.org/node/1798296. $token = $request->query->get('token'); - if (!isset($token) || !drupal_valid_token($token, 'comment/' . $comment->id() . '/approve')) { + if (!isset($token) || !$this->csrfToken->validate($token, 'comment/' . $comment->id() . '/approve')) { throw new AccessDeniedHttpException(); } $comment->status->value = COMMENT_PUBLISHED; $comment->save(); - drupal_set_message(t('Comment approved.')); + drupal_set_message($this->t('Comment approved.')); $permalink_uri = $comment->permalink(); $permalink_uri['options']['absolute'] = TRUE; - $url = $this->urlGenerator->generateFromPath($permalink_uri['path'], $permalink_uri['options']); + $url = $this->urlGenerator()->generateFromPath($permalink_uri['path'], $permalink_uri['options']); return new RedirectResponse($url); } @@ -132,4 +134,93 @@ public function commentPermalink(Request $request, CommentInterface $comment) { throw new NotFoundHttpException(); } + /** + * Form constructor for the comment reply form. + * + * Both replies on the node itself and replies on other comments are + * supported. To provide context, the node or comment that is being replied on + * will be displayed along the comment reply form. + * The constructor takes care of access permissions and checks whether the + * node still accepts comments. + * + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object. + * @param \Drupal\node\NodeInterface $node + * Every comment belongs to a node. This is that node. + * @param int $pid + * (optional) Some comments are replies to other comments. In those cases, + * $pid is the parent comment's ID. Defaults to NULL. + * + * @return array|\Symfony\Component\HttpFoundation\RedirectResponse + * One of the following: + * - An associative array containing: + * - An array for rendering the node or parent comment. + * - comment_node: If the comment is a reply to the node. + * - comment_parent: If the comment is a reply to another comment. + * - comment_form: The comment form as a renderable array. + * - A redirect response to current node: + * - If user is not authorized to post comments. + * - If parent comment doesn't belong to current node. + * - If user is not authorized to view comments. + * - If current node comments are disable. + */ + public function getReplyForm(Request $request, NodeInterface $node, $pid = NULL) { + $uri = $node->uri(); + $build = array(); + $account = $this->currentUser(); + + $build['#title'] = $this->t('Add new comment'); + + // Check if the user has the proper permissions. + if (!$account->hasPermission('post comments')) { + drupal_set_message($this->t('You are not authorized to post comments.'), 'error'); + return new RedirectResponse($this->urlGenerator()->generateFromPath($uri['path'], array('absolute' => TRUE))); + } + + // The user is not just previewing a comment. + if ($request->request->get('op') != $this->t('Preview')) { + if ($node->comment->value != COMMENT_NODE_OPEN) { + drupal_set_message($this->t("This discussion is closed: you can't post new comments."), 'error'); + return new RedirectResponse($this->urlGenerator()->generateFromPath($uri['path'], array('absolute' => TRUE))); + } + + // $pid indicates that this is a reply to a comment. + if ($pid) { + // Check if the user has the proper permissions. + if (!$account->hasPermission('access comments')) { + drupal_set_message($this->t('You are not authorized to view comments.'), 'error'); + return new RedirectResponse($this->urlGenerator()->generateFromPath($uri['path'], array('absolute' => TRUE))); + } + // Load the parent comment. + $comment = $this->entityManager()->getStorageController('comment')->load($pid); + // Check if the parent comment is published and belongs to the current nid. + if (($comment->status->value == COMMENT_NOT_PUBLISHED) || ($comment->nid->target_id != $node->id())) { + drupal_set_message($this->t('The comment you are replying to does not exist.'), 'error'); + return new RedirectResponse($this->urlGenerator()->generateFromPath($uri['path'], array('absolute' => TRUE))); + } + // Display the parent comment. + $build['comment_parent'] = $this->entityManager()->getRenderController('comment')->view($comment); + } + + // The comment is in response to a node. + elseif ($account->hasPermission('access content')) { + // Display the node. + $build['comment_node'] = $this->entityManager()->getRenderController('node')->view($node); + } + } + else { + $build['#title'] = $this->t('Preview comment'); + } + + // Show the actual reply box. + $comment = $this->entityManager()->getStorageController('comment')->create(array( + 'nid' => $node->id(), + 'pid' => $pid, + 'node_type' => 'comment_node_' . $node->getType(), + )); + $build['comment_form'] = $this->entityManager()->getForm($comment); + + return $build; + } + } -- GitLab