diff --git a/core/modules/comment/comment.admin.inc b/core/modules/comment/comment.admin.inc index 1ca6a52..450e942 100644 --- a/core/modules/comment/comment.admin.inc +++ b/core/modules/comment/comment.admin.inc @@ -10,207 +10,6 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; /** - * Page callback: Presents an administrative comment listing. - * - * @param $type - * The type of the overview form ('approval' or 'new'). See - * comment_admin_overview() for details. - * - * @see comment_menu() - * @see comment_multiple_delete_confirm() - */ -function comment_admin($type = 'new') { - $edit = Drupal::request()->request->all(); - - if (isset($edit['operation']) && ($edit['operation'] == 'delete') && isset($edit['comments']) && $edit['comments']) { - return drupal_get_form('comment_multiple_delete_confirm'); - } - else { - return drupal_get_form('comment_admin_overview', $type); - } -} - -/** - * Form constructor for the comment overview administration form. - * - * @param $arg - * The type of overview form ('approval' or 'new'). - * - * @ingroup forms - * @see comment_admin() - * @see comment_admin_overview_validate() - * @see comment_admin_overview_submit() - * @see theme_comment_admin_overview() - */ -function comment_admin_overview($form, &$form_state, $arg) { - // Build an 'Update options' form. - $form['options'] = array( - '#type' => 'details', - '#title' => t('Update options'), - '#attributes' => array('class' => array('container-inline')), - ); - - if ($arg == 'approval') { - $options['publish'] = t('Publish the selected comments'); - } - else { - $options['unpublish'] = t('Unpublish the selected comments'); - } - $options['delete'] = t('Delete the selected comments'); - - $form['options']['operation'] = array( - '#type' => 'select', - '#title' => t('Action'), - '#title_display' => 'invisible', - '#options' => $options, - '#default_value' => 'publish', - ); - $form['options']['submit'] = array( - '#type' => 'submit', - '#value' => t('Update'), - ); - - // Load the comments that need to be displayed. - $status = ($arg == 'approval') ? COMMENT_NOT_PUBLISHED : COMMENT_PUBLISHED; - $header = array( - 'subject' => array('data' => t('Subject'), 'field' => 'subject'), - 'author' => array('data' => t('Author'), 'field' => 'name', 'class' => array(RESPONSIVE_PRIORITY_MEDIUM)), - 'posted_in' => array('data' => t('Posted in'), 'field' => 'node_title', 'class' => array(RESPONSIVE_PRIORITY_LOW)), - 'changed' => array('data' => t('Updated'), 'field' => 'c.changed', 'sort' => 'desc', 'class' => array(RESPONSIVE_PRIORITY_LOW)), - 'operations' => t('Operations'), - ); - - $query = db_select('comment', 'c') - ->extend('Drupal\Core\Database\Query\PagerSelectExtender') - ->extend('Drupal\Core\Database\Query\TableSortExtender'); - $query->join('node_field_data', 'n', 'n.nid = c.nid'); - $query->addTag('node_access'); - $result = $query - ->fields('c', array('cid', 'nid', 'subject', 'name', 'changed')) - ->condition('c.status', $status) - ->limit(50) - ->orderByHeader($header) - ->execute(); - - $nids = array(); - $cids = array(); - - // We collect a sorted list of node_titles during the query to attach to the - // comments later. - foreach ($result as $row) { - $nids[] = $row->nid; - $cids[] = $row->cid; - } - // Ensure all nodes are statically cached so that we do not have to load them - // individually when getting their labels below. - node_load_multiple($nids); - $comments = comment_load_multiple($cids); - - // Build a table listing the appropriate comments. - $options = array(); - $destination = drupal_get_destination(); - - foreach ($comments as $comment) { - // Remove the first node title from the node_titles array and attach to - // the comment. - $node_title = $comment->nid->entity->label(); - $options[$comment->id()] = array( - 'subject' => array( - 'data' => array( - '#type' => 'link', - '#title' => $comment->subject->value, - '#href' => 'comment/' . $comment->id(), - '#options' => array('attributes' => array('title' => truncate_utf8($comment->comment_body->value, 128)), 'fragment' => 'comment-' . $comment->id()), - ), - ), - 'author' => theme('username', array('account' => comment_prepare_author($comment))), - 'posted_in' => array( - 'data' => array( - '#type' => 'link', - '#title' => $node_title, - '#href' => 'node/' . $comment->nid->target_id, - ), - ), - 'changed' => format_date($comment->changed->value, 'short'), - ); - $links = array(); - $links['edit'] = array( - 'title' => t('edit'), - 'href' => 'comment/' . $comment->id() . '/edit', - 'query' => $destination, - ); - if (module_invoke('content_translation', 'translate_access', $comment)) { - $links['translate'] = array( - 'title' => t('translate'), - 'href' => 'comment/' . $comment->id() . '/translations', - 'query' => $destination, - ); - } - $options[$comment->id()]['operations']['data'] = array( - '#type' => 'operations', - '#links' => $links, - ); - } - - $form['comments'] = array( - '#type' => 'tableselect', - '#header' => $header, - '#options' => $options, - '#empty' => t('No comments available.'), - ); - - $form['pager'] = array('#theme' => 'pager'); - - return $form; -} - -/** - * Form validation handler for comment_admin_overview(). - * - * @see comment_admin_overview_submit() - */ -function comment_admin_overview_validate($form, &$form_state) { - $form_state['values']['comments'] = array_diff($form_state['values']['comments'], array(0)); - // We can't execute any 'Update options' if no comments were selected. - if (count($form_state['values']['comments']) == 0) { - form_set_error('', t('Select one or more comments to perform the update on.')); - } -} - -/** - * Form submission handler for comment_admin_overview(). - * - * Executes the chosen 'Update option' on the selected comments, such as - * publishing, unpublishing or deleting. - * - * @see comment_admin_overview_validate() - */ -function comment_admin_overview_submit($form, &$form_state) { - $operation = $form_state['values']['operation']; - $cids = $form_state['values']['comments']; - - if ($operation == 'delete') { - entity_delete_multiple('comment', $cids); - } - else { - foreach ($cids as $cid => $value) { - $comment = comment_load($value); - - if ($operation == 'unpublish') { - $comment->status->value = COMMENT_NOT_PUBLISHED; - } - elseif ($operation == 'publish') { - $comment->status->value = COMMENT_PUBLISHED; - } - $comment->save(); - } - } - drupal_set_message(t('The update has been performed.')); - $form_state['redirect'] = 'admin/content/comment'; - cache_invalidate_tags(array('content' => TRUE)); -} - -/** * Form constructor for the confirmation form for bulk comment deletion. * * @ingroup forms @@ -269,6 +68,8 @@ function comment_multiple_delete_confirm_submit($form, &$form_state) { * @param \Drupal\comment\Plugin\Core\Entity\Comment $comment * The comment entity that is about to be deleted. * + * @return array + * The confirmation form for the delete operation. * @see comment_menu() * @see comment_confirm_delete() */ @@ -279,7 +80,7 @@ function comment_confirm_delete_page(Comment $comment) { /** * Form constructor for the confirmation form for comment deletion. * - * @param Drupal\comment\Comment $comment + * @param Drupal\comment\CommentInterface $comment * The comment that is about to be deleted. * * @ingroup forms @@ -315,3 +116,153 @@ function comment_confirm_delete_submit($form, &$form_state) { $form_state['redirect'] = "node/{$comment->nid->target_id}"; } + +/* + * Build the comments overview screen. + * + * @ingroup forms + */ +function comment_admin_comments() { + drupal_set_title(t('Comments')); + // Build the sortable table header. + $header = array( + 'subject' => array( + 'data' => t('Subject'), + 'field' => 'c.subject', + ), + 'author' => array( + 'data' => t('Author'), + 'class' => array(RESPONSIVE_PRIORITY_LOW), + ), + 'posted_in' => array( + 'data' => t('Posted in'), + 'field' => 'n.title', + ), + 'status' => array( + 'data' => t('Status'), + 'field' => 'c.status', + 'class' => array(RESPONSIVE_PRIORITY_LOW) + ), + 'changed' => array( + 'data' => t('Updated'), + 'field' => 'c.changed', + 'sort' => 'desc', + 'class' => array(RESPONSIVE_PRIORITY_LOW) + ), + 'operations' => array( + 'data' => t('Operations'), + ), + ); + + $query = db_select('comment', 'c') + ->extend('Drupal\Core\Database\Query\PagerSelectExtender') + ->extend('Drupal\Core\Database\Query\TableSortExtender'); + $query->join('node_field_data', 'n', 'n.nid = c.nid'); + $query->addTag('node_access'); + $result = $query + ->fields('c', array('cid', 'nid', 'subject', 'name', 'changed', 'status')) + ->limit(50) + ->orderByHeader($header) + ->execute(); + + $nids = array(); + $cids = array(); + + // We collect a sorted list of node_titles during the query to attach to the + // comments later. + foreach ($result as $row) { + $nids[] = $row->nid; + $cids[] = $row->cid; + } + // Ensure all nodes are statically cached so that we do not have to load them + // individually when getting their labels below. + node_load_multiple($nids); + $comments = comment_load_multiple($cids); + + // Build a table listing the appropriate comments. + $destination = drupal_get_destination(); + $form['comments'] = array( + '#type' => 'table', + '#header' => $header, + '#empty' => t('No comments available.'), + ); + + foreach ($comments as $comment) { + $cid = $comment->id(); + // Get the title of the node associated with the comment. + $node_title = $comment->nid->entity->label(); + $form['comments'][$comment->id()] = array( + 'subject' => array( + 'data' => array( + '#type' => 'link', + '#title' => $comment->subject->value, + '#href' => 'comment/' . $cid, + '#options' => array('attributes' => array('title' => truncate_utf8(isset($comment->comment_body->value) ? $comment->comment_body->value : $comment->subject->title, 128)), 'fragment' => 'comment-' . $cid), + ), + ), + 'author' => array( + '#theme' => 'username', + '#account' => comment_prepare_author($comment) + ), + 'posted_in' => array( + 'data' => array( + '#type' => 'link', + '#title' => $node_title, + '#href' => 'node/' . $comment->nid->target_id, + ), + ), + 'status' => array( + '#markup' => $comment->status->value ? t('approved') : t('unapproved'), + ), + 'changed' => array( + '#markup' => format_date($comment->changed->value, 'short'), + ) + ); + $operations = array(); + + if ($comment->access('update')) { + $operations['edit'] = array( + 'title' => t('Edit'), + 'href' => 'comment/' . $cid . '/edit', + 'query' => $destination, + ); + } + if ($comment->access('delete')) { + $operations['delete'] = array( + 'title' => t('Delete'), + 'href' => 'comment/' . $cid . '/delete', + 'query' => $destination, + ); + } + if (module_invoke('content_translation', 'translate_access', $comment)) { + $operations['translate'] = array( + 'title' => t('translate'), + 'href' => 'comment/' . $cid . '/translations', + 'query' => $destination, + ); + } + + $form['comments'][$cid]['operations'] = array(); + if (count($operations) > 1) { + // Render an unordered list of operations links. + $form['comments'][$cid]['operations'] = array( + '#type' => 'operations', + '#subtype' => 'comment', + '#links' => $operations, + ); + } + elseif (!empty($operations)) { + // Render the first and only operation as a link. + $link = reset($operations); + $form['comments'][$cid]['operations'] = array( + '#type' => 'link', + '#title' => $link['title'], + '#href' => $link['href'], + '#options' => array('query' => $link['query']), + ); + } + } + + $form['pager'] = array('#theme' => 'pager'); + return $form; +} diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 7cd4e70..f9a829f 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -184,7 +184,7 @@ function comment_menu() { $items['admin/content/comment'] = array( 'title' => 'Comments', 'description' => 'List and edit site comments and the comment approval queue.', - 'page callback' => 'comment_admin', + 'page callback' => 'comment_admin_comments', 'access arguments' => array('administer comments'), 'type' => MENU_LOCAL_TASK | MENU_NORMAL_ITEM, 'file' => 'comment.admin.inc', @@ -194,13 +194,6 @@ function comment_menu() { 'title' => 'Published comments', 'type' => MENU_DEFAULT_LOCAL_TASK, ); - $items['admin/content/comment/approval'] = array( - 'title' => 'Unapproved comments', - 'title callback' => 'comment_count_unpublished', - 'page arguments' => array('approval'), - 'access arguments' => array('administer comments'), - 'type' => MENU_LOCAL_TASK, - ); $items['comment/%comment'] = array( 'title' => 'Comment permalink', 'page callback' => 'comment_permalink', diff --git a/core/modules/comment/comment.routing.yml b/core/modules/comment/comment.routing.yml index 6f786dd..08b57a7 100644 --- a/core/modules/comment/comment.routing.yml +++ b/core/modules/comment/comment.routing.yml @@ -1,7 +1,13 @@ +comment_multiple_delete_confirm: + pattern: '/admin/content/comment/delete' + defaults: + _form: '\Drupal\comment\Form\DeleteMultiple' + requirements: + _permission: 'administer comments' + comment_edit_page: pattern: 'comment/{comment}/edit' defaults: _entity_form: comment.default requirements: _entity_access: comment.update - diff --git a/core/modules/comment/lib/Drupal/comment/Form/DeleteMultiple.php b/core/modules/comment/lib/Drupal/comment/Form/DeleteMultiple.php new file mode 100644 index 0000000..7895d8b --- /dev/null +++ b/core/modules/comment/lib/Drupal/comment/Form/DeleteMultiple.php @@ -0,0 +1,127 @@ +tempStoreFactory = $temp_store_factory; + $this->storageController = $manager->getStorageController('comment'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container) { + return new static( + $container->get('user.tempstore'), + $container->get('plugin.manager.entity') + ); + } + + /** + * {@inheritdoc} + */ + public function getFormID() { + return 'comment_multiple_delete_confirm'; + } + + /** + * {@inheritdoc} + */ + public function getQuestion() { + return format_plural(count($this->comments), 'Are you sure you want to delete this item?', 'Are you sure you want to delete these items?'); + } + + /** + * {@inheritdoc} + */ + public function getCancelPath() { + return 'admin/content/comment'; + } + + /** + * {@inheritdoc} + */ + public function getConfirmText() { + return t('Delete'); + } + + /** + * {@inheritdoc} + */ + public function buildForm(array $form, array &$form_state) { + $this->comments = $this->tempStoreFactory->get('comment_multiple_delete_confirm')->get($GLOBALS['user']->uid); + if (empty($this->comments)) { + return new RedirectResponse(url($this->getCancelPath(), array('absolute' => TRUE))); + } + + $form['comments'] = array( + '#theme' => 'item_list', + '#items' => array_map(function ($comment) { + return String::checkPlain($comment->label()); + }, $this->comments), + ); + return parent::buildForm($form, $form_state); + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + if ($form_state['values']['confirm'] && !empty($this->comments)) { + $this->storageController->delete($this->comments); + $this->tempStoreFactory->get('comment_multiple_delete_confirm')->delete($GLOBALS['user']->uid); + $count = count($this->comments); + watchdog('content', 'Deleted @count posts.', array('@count' => $count)); + drupal_set_message(format_plural($count, 'Deleted 1 comment.', 'Deleted @count comments.')); + } + $form_state['redirect'] = 'admin/content/comment'; + } + +} diff --git a/core/modules/comment/lib/Drupal/comment/Plugin/Action/DeleteComment.php b/core/modules/comment/lib/Drupal/comment/Plugin/Action/DeleteComment.php index 6bfcb54..832aa30 100644 --- a/core/modules/comment/lib/Drupal/comment/Plugin/Action/DeleteComment.php +++ b/core/modules/comment/lib/Drupal/comment/Plugin/Action/DeleteComment.php @@ -11,6 +11,8 @@ use Drupal\Core\Annotation\Translation; use Drupal\Core\Action\ActionBase; use Drupal\Core\Cache\Cache; +use Drupal\user\TempStoreFactory; +use Symfony\Component\DependencyInjection\ContainerInterface; /** * Deletes a comment. @@ -18,17 +20,56 @@ * @Action( * id = "comment_delete_action", * label = @Translation("Delete comment"), - * type = "comment" + * type = "comment", + * confirm_form_path = "admin/content/comment/delete" * ) */ class DeleteComment extends ActionBase { /** + * The tempstore object. + * + * @var \Drupal\user\TempStore + */ + protected $tempStore; + + /** + * Constructs a new DeleteComment object. + * + * @param array $configuration + * A configuration array containing information about the plugin instance. + * @param string $plugin_id + * The plugin ID for the plugin instance. + * @param array $plugin_definition + * The plugin implementation definition. + * @param \Drupal\user\TempStoreFactory $temp_store_factory + * The tempstore factory. + */ + public function __construct(array $configuration, $plugin_id, array $plugin_definition, TempStoreFactory $temp_store_factory) { + parent::__construct($configuration, $plugin_id, $plugin_definition); + + $this->tempStore = $temp_store_factory->get('comment_multiple_delete_confirm'); + } + + /** + * {@inheritdoc} + */ + public static function create(ContainerInterface $container, array $configuration, $plugin_id, array $plugin_definition) { + return new static($configuration, $plugin_id, $plugin_definition, $container->get('user.tempstore')); + } + + /** + * {@inheritdoc} + */ + public function executeMultiple(array $entities) { + $this->tempStore->set($GLOBALS['user']->uid, $entities); + } + + /** * {@inheritdoc} */ - public function execute($comment = NULL) { - $comment->delete(); - Cache::invalidateTags(array('content' => TRUE)); + public function execute($object = NULL) { + $this->executeMultiple(array($object)); } }