annotate core/modules/node/src/Controller/NodeController.php @ 0:4c8ae668cc8c

Initial import (non-working)
author Chris Cannam
date Wed, 29 Nov 2017 16:09:58 +0000
parents
children 1fec387a4317
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\node\Controller;
Chris@0 4
Chris@0 5 use Drupal\Component\Utility\Xss;
Chris@0 6 use Drupal\Core\Controller\ControllerBase;
Chris@0 7 use Drupal\Core\Datetime\DateFormatterInterface;
Chris@0 8 use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
Chris@0 9 use Drupal\Core\Render\RendererInterface;
Chris@0 10 use Drupal\Core\Url;
Chris@0 11 use Drupal\node\NodeStorageInterface;
Chris@0 12 use Drupal\node\NodeTypeInterface;
Chris@0 13 use Drupal\node\NodeInterface;
Chris@0 14 use Symfony\Component\DependencyInjection\ContainerInterface;
Chris@0 15
Chris@0 16 /**
Chris@0 17 * Returns responses for Node routes.
Chris@0 18 */
Chris@0 19 class NodeController extends ControllerBase implements ContainerInjectionInterface {
Chris@0 20
Chris@0 21 /**
Chris@0 22 * The date formatter service.
Chris@0 23 *
Chris@0 24 * @var \Drupal\Core\Datetime\DateFormatterInterface
Chris@0 25 */
Chris@0 26 protected $dateFormatter;
Chris@0 27
Chris@0 28 /**
Chris@0 29 * The renderer service.
Chris@0 30 *
Chris@0 31 * @var \Drupal\Core\Render\RendererInterface
Chris@0 32 */
Chris@0 33 protected $renderer;
Chris@0 34
Chris@0 35 /**
Chris@0 36 * Constructs a NodeController object.
Chris@0 37 *
Chris@0 38 * @param \Drupal\Core\Datetime\DateFormatterInterface $date_formatter
Chris@0 39 * The date formatter service.
Chris@0 40 * @param \Drupal\Core\Render\RendererInterface $renderer
Chris@0 41 * The renderer service.
Chris@0 42 */
Chris@0 43 public function __construct(DateFormatterInterface $date_formatter, RendererInterface $renderer) {
Chris@0 44 $this->dateFormatter = $date_formatter;
Chris@0 45 $this->renderer = $renderer;
Chris@0 46 }
Chris@0 47
Chris@0 48 /**
Chris@0 49 * {@inheritdoc}
Chris@0 50 */
Chris@0 51 public static function create(ContainerInterface $container) {
Chris@0 52 return new static(
Chris@0 53 $container->get('date.formatter'),
Chris@0 54 $container->get('renderer')
Chris@0 55 );
Chris@0 56 }
Chris@0 57
Chris@0 58 /**
Chris@0 59 * Displays add content links for available content types.
Chris@0 60 *
Chris@0 61 * Redirects to node/add/[type] if only one content type is available.
Chris@0 62 *
Chris@0 63 * @return array|\Symfony\Component\HttpFoundation\RedirectResponse
Chris@0 64 * A render array for a list of the node types that can be added; however,
Chris@0 65 * if there is only one node type defined for the site, the function
Chris@0 66 * will return a RedirectResponse to the node add page for that one node
Chris@0 67 * type.
Chris@0 68 */
Chris@0 69 public function addPage() {
Chris@0 70 $build = [
Chris@0 71 '#theme' => 'node_add_list',
Chris@0 72 '#cache' => [
Chris@0 73 'tags' => $this->entityManager()->getDefinition('node_type')->getListCacheTags(),
Chris@0 74 ],
Chris@0 75 ];
Chris@0 76
Chris@0 77 $content = [];
Chris@0 78
Chris@0 79 // Only use node types the user has access to.
Chris@0 80 foreach ($this->entityManager()->getStorage('node_type')->loadMultiple() as $type) {
Chris@0 81 $access = $this->entityManager()->getAccessControlHandler('node')->createAccess($type->id(), NULL, [], TRUE);
Chris@0 82 if ($access->isAllowed()) {
Chris@0 83 $content[$type->id()] = $type;
Chris@0 84 }
Chris@0 85 $this->renderer->addCacheableDependency($build, $access);
Chris@0 86 }
Chris@0 87
Chris@0 88 // Bypass the node/add listing if only one content type is available.
Chris@0 89 if (count($content) == 1) {
Chris@0 90 $type = array_shift($content);
Chris@0 91 return $this->redirect('node.add', ['node_type' => $type->id()]);
Chris@0 92 }
Chris@0 93
Chris@0 94 $build['#content'] = $content;
Chris@0 95
Chris@0 96 return $build;
Chris@0 97 }
Chris@0 98
Chris@0 99 /**
Chris@0 100 * Provides the node submission form.
Chris@0 101 *
Chris@0 102 * @param \Drupal\node\NodeTypeInterface $node_type
Chris@0 103 * The node type entity for the node.
Chris@0 104 *
Chris@0 105 * @return array
Chris@0 106 * A node submission form.
Chris@0 107 */
Chris@0 108 public function add(NodeTypeInterface $node_type) {
Chris@0 109 $node = $this->entityManager()->getStorage('node')->create([
Chris@0 110 'type' => $node_type->id(),
Chris@0 111 ]);
Chris@0 112
Chris@0 113 $form = $this->entityFormBuilder()->getForm($node);
Chris@0 114
Chris@0 115 return $form;
Chris@0 116 }
Chris@0 117
Chris@0 118 /**
Chris@0 119 * Displays a node revision.
Chris@0 120 *
Chris@0 121 * @param int $node_revision
Chris@0 122 * The node revision ID.
Chris@0 123 *
Chris@0 124 * @return array
Chris@0 125 * An array suitable for drupal_render().
Chris@0 126 */
Chris@0 127 public function revisionShow($node_revision) {
Chris@0 128 $node = $this->entityManager()->getStorage('node')->loadRevision($node_revision);
Chris@0 129 $node = $this->entityManager()->getTranslationFromContext($node);
Chris@0 130 $node_view_controller = new NodeViewController($this->entityManager, $this->renderer, $this->currentUser());
Chris@0 131 $page = $node_view_controller->view($node);
Chris@0 132 unset($page['nodes'][$node->id()]['#cache']);
Chris@0 133 return $page;
Chris@0 134 }
Chris@0 135
Chris@0 136 /**
Chris@0 137 * Page title callback for a node revision.
Chris@0 138 *
Chris@0 139 * @param int $node_revision
Chris@0 140 * The node revision ID.
Chris@0 141 *
Chris@0 142 * @return string
Chris@0 143 * The page title.
Chris@0 144 */
Chris@0 145 public function revisionPageTitle($node_revision) {
Chris@0 146 $node = $this->entityManager()->getStorage('node')->loadRevision($node_revision);
Chris@0 147 return $this->t('Revision of %title from %date', ['%title' => $node->label(), '%date' => format_date($node->getRevisionCreationTime())]);
Chris@0 148 }
Chris@0 149
Chris@0 150 /**
Chris@0 151 * Generates an overview table of older revisions of a node.
Chris@0 152 *
Chris@0 153 * @param \Drupal\node\NodeInterface $node
Chris@0 154 * A node object.
Chris@0 155 *
Chris@0 156 * @return array
Chris@0 157 * An array as expected by drupal_render().
Chris@0 158 */
Chris@0 159 public function revisionOverview(NodeInterface $node) {
Chris@0 160 $account = $this->currentUser();
Chris@0 161 $langcode = $node->language()->getId();
Chris@0 162 $langname = $node->language()->getName();
Chris@0 163 $languages = $node->getTranslationLanguages();
Chris@0 164 $has_translations = (count($languages) > 1);
Chris@0 165 $node_storage = $this->entityManager()->getStorage('node');
Chris@0 166 $type = $node->getType();
Chris@0 167
Chris@0 168 $build['#title'] = $has_translations ? $this->t('@langname revisions for %title', ['@langname' => $langname, '%title' => $node->label()]) : $this->t('Revisions for %title', ['%title' => $node->label()]);
Chris@0 169 $header = [$this->t('Revision'), $this->t('Operations')];
Chris@0 170
Chris@0 171 $revert_permission = (($account->hasPermission("revert $type revisions") || $account->hasPermission('revert all revisions') || $account->hasPermission('administer nodes')) && $node->access('update'));
Chris@0 172 $delete_permission = (($account->hasPermission("delete $type revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete'));
Chris@0 173
Chris@0 174 $rows = [];
Chris@0 175 $default_revision = $node->getRevisionId();
Chris@0 176
Chris@0 177 foreach ($this->getRevisionIds($node, $node_storage) as $vid) {
Chris@0 178 /** @var \Drupal\node\NodeInterface $revision */
Chris@0 179 $revision = $node_storage->loadRevision($vid);
Chris@0 180 // Only show revisions that are affected by the language that is being
Chris@0 181 // displayed.
Chris@0 182 if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) {
Chris@0 183 $username = [
Chris@0 184 '#theme' => 'username',
Chris@0 185 '#account' => $revision->getRevisionUser(),
Chris@0 186 ];
Chris@0 187
Chris@0 188 // Use revision link to link to revisions that are not active.
Chris@0 189 $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short');
Chris@0 190 if ($vid != $node->getRevisionId()) {
Chris@0 191 $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
Chris@0 192 }
Chris@0 193 else {
Chris@0 194 $link = $node->link($date);
Chris@0 195 }
Chris@0 196
Chris@0 197 $row = [];
Chris@0 198 $column = [
Chris@0 199 'data' => [
Chris@0 200 '#type' => 'inline_template',
Chris@0 201 '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}',
Chris@0 202 '#context' => [
Chris@0 203 'date' => $link,
Chris@0 204 'username' => $this->renderer->renderPlain($username),
Chris@0 205 'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()],
Chris@0 206 ],
Chris@0 207 ],
Chris@0 208 ];
Chris@0 209 // @todo Simplify once https://www.drupal.org/node/2334319 lands.
Chris@0 210 $this->renderer->addCacheableDependency($column['data'], $username);
Chris@0 211 $row[] = $column;
Chris@0 212
Chris@0 213 if ($vid == $default_revision) {
Chris@0 214 $row[] = [
Chris@0 215 'data' => [
Chris@0 216 '#prefix' => '<em>',
Chris@0 217 '#markup' => $this->t('Current revision'),
Chris@0 218 '#suffix' => '</em>',
Chris@0 219 ],
Chris@0 220 ];
Chris@0 221
Chris@0 222 $rows[] = [
Chris@0 223 'data' => $row,
Chris@0 224 'class' => ['revision-current'],
Chris@0 225 ];
Chris@0 226 }
Chris@0 227 else {
Chris@0 228 $links = [];
Chris@0 229 if ($revert_permission) {
Chris@0 230 $links['revert'] = [
Chris@0 231 'title' => $vid < $node->getRevisionId() ? $this->t('Revert') : $this->t('Set as current revision'),
Chris@0 232 'url' => $has_translations ?
Chris@0 233 Url::fromRoute('node.revision_revert_translation_confirm', ['node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode]) :
Chris@0 234 Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid]),
Chris@0 235 ];
Chris@0 236 }
Chris@0 237
Chris@0 238 if ($delete_permission) {
Chris@0 239 $links['delete'] = [
Chris@0 240 'title' => $this->t('Delete'),
Chris@0 241 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid]),
Chris@0 242 ];
Chris@0 243 }
Chris@0 244
Chris@0 245 $row[] = [
Chris@0 246 'data' => [
Chris@0 247 '#type' => 'operations',
Chris@0 248 '#links' => $links,
Chris@0 249 ],
Chris@0 250 ];
Chris@0 251
Chris@0 252 $rows[] = $row;
Chris@0 253 }
Chris@0 254 }
Chris@0 255 }
Chris@0 256
Chris@0 257 $build['node_revisions_table'] = [
Chris@0 258 '#theme' => 'table',
Chris@0 259 '#rows' => $rows,
Chris@0 260 '#header' => $header,
Chris@0 261 '#attached' => [
Chris@0 262 'library' => ['node/drupal.node.admin'],
Chris@0 263 ],
Chris@0 264 '#attributes' => ['class' => 'node-revision-table'],
Chris@0 265 ];
Chris@0 266
Chris@0 267 $build['pager'] = ['#type' => 'pager'];
Chris@0 268
Chris@0 269 return $build;
Chris@0 270 }
Chris@0 271
Chris@0 272 /**
Chris@0 273 * The _title_callback for the node.add route.
Chris@0 274 *
Chris@0 275 * @param \Drupal\node\NodeTypeInterface $node_type
Chris@0 276 * The current node.
Chris@0 277 *
Chris@0 278 * @return string
Chris@0 279 * The page title.
Chris@0 280 */
Chris@0 281 public function addPageTitle(NodeTypeInterface $node_type) {
Chris@0 282 return $this->t('Create @name', ['@name' => $node_type->label()]);
Chris@0 283 }
Chris@0 284
Chris@0 285 /**
Chris@0 286 * Gets a list of node revision IDs for a specific node.
Chris@0 287 *
Chris@0 288 * @param \Drupal\node\NodeInterface $node
Chris@0 289 * The node entity.
Chris@0 290 * @param \Drupal\node\NodeStorageInterface $node_storage
Chris@0 291 * The node storage handler.
Chris@0 292 *
Chris@0 293 * @return int[]
Chris@0 294 * Node revision IDs (in descending order).
Chris@0 295 */
Chris@0 296 protected function getRevisionIds(NodeInterface $node, NodeStorageInterface $node_storage) {
Chris@0 297 $result = $node_storage->getQuery()
Chris@0 298 ->allRevisions()
Chris@0 299 ->condition($node->getEntityType()->getKey('id'), $node->id())
Chris@0 300 ->sort($node->getEntityType()->getKey('revision'), 'DESC')
Chris@0 301 ->pager(50)
Chris@0 302 ->execute();
Chris@0 303 return array_keys($result);
Chris@0 304 }
Chris@0 305
Chris@0 306 }