dateFormatter = $date_formatter; $this->renderer = $renderer; } /** * {@inheritdoc} */ public static function create(ContainerInterface $container) { return new static( $container->get('date.formatter'), $container->get('renderer') ); } /** * Displays add content links for available content types. * * Redirects to node/add/[type] if only one content type is available. * * @return array|\Symfony\Component\HttpFoundation\RedirectResponse * A render array for a list of the node types that can be added; however, * if there is only one node type defined for the site, the function * will return a RedirectResponse to the node add page for that one node * type. */ public function addPage() { $build = [ '#theme' => 'node_add_list', '#cache' => [ 'tags' => $this->entityManager()->getDefinition('node_type')->getListCacheTags(), ], ]; $content = []; // Only use node types the user has access to. foreach ($this->entityManager()->getStorage('node_type')->loadMultiple() as $type) { $access = $this->entityManager()->getAccessControlHandler('node')->createAccess($type->id(), NULL, [], TRUE); if ($access->isAllowed()) { $content[$type->id()] = $type; } $this->renderer->addCacheableDependency($build, $access); } // Bypass the node/add listing if only one content type is available. if (count($content) == 1) { $type = array_shift($content); return $this->redirect('node.add', ['node_type' => $type->id()]); } $build['#content'] = $content; return $build; } /** * Provides the node submission form. * * @param \Drupal\node\NodeTypeInterface $node_type * The node type entity for the node. * * @return array * A node submission form. */ public function add(NodeTypeInterface $node_type) { $node = $this->entityManager()->getStorage('node')->create([ 'type' => $node_type->id(), ]); $form = $this->entityFormBuilder()->getForm($node); return $form; } /** * Displays a node revision. * * @param int $node_revision * The node revision ID. * * @return array * An array suitable for drupal_render(). */ public function revisionShow($node_revision) { $node = $this->entityManager()->getStorage('node')->loadRevision($node_revision); $node = $this->entityManager()->getTranslationFromContext($node); $node_view_controller = new NodeViewController($this->entityManager, $this->renderer, $this->currentUser()); $page = $node_view_controller->view($node); unset($page['nodes'][$node->id()]['#cache']); return $page; } /** * Page title callback for a node revision. * * @param int $node_revision * The node revision ID. * * @return string * The page title. */ public function revisionPageTitle($node_revision) { $node = $this->entityManager()->getStorage('node')->loadRevision($node_revision); return $this->t('Revision of %title from %date', ['%title' => $node->label(), '%date' => format_date($node->getRevisionCreationTime())]); } /** * Generates an overview table of older revisions of a node. * * @param \Drupal\node\NodeInterface $node * A node object. * * @return array * An array as expected by drupal_render(). */ public function revisionOverview(NodeInterface $node) { $account = $this->currentUser(); $langcode = $node->language()->getId(); $langname = $node->language()->getName(); $languages = $node->getTranslationLanguages(); $has_translations = (count($languages) > 1); $node_storage = $this->entityManager()->getStorage('node'); $type = $node->getType(); $build['#title'] = $has_translations ? $this->t('@langname revisions for %title', ['@langname' => $langname, '%title' => $node->label()]) : $this->t('Revisions for %title', ['%title' => $node->label()]); $header = [$this->t('Revision'), $this->t('Operations')]; $revert_permission = (($account->hasPermission("revert $type revisions") || $account->hasPermission('revert all revisions') || $account->hasPermission('administer nodes')) && $node->access('update')); $delete_permission = (($account->hasPermission("delete $type revisions") || $account->hasPermission('delete all revisions') || $account->hasPermission('administer nodes')) && $node->access('delete')); $rows = []; $default_revision = $node->getRevisionId(); foreach ($this->getRevisionIds($node, $node_storage) as $vid) { /** @var \Drupal\node\NodeInterface $revision */ $revision = $node_storage->loadRevision($vid); // Only show revisions that are affected by the language that is being // displayed. if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) { $username = [ '#theme' => 'username', '#account' => $revision->getRevisionUser(), ]; // Use revision link to link to revisions that are not active. $date = $this->dateFormatter->format($revision->revision_timestamp->value, 'short'); if ($vid != $node->getRevisionId()) { $link = $this->l($date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid])); } else { $link = $node->link($date); } $row = []; $column = [ 'data' => [ '#type' => 'inline_template', '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}

{{ message }}

{% endif %}', '#context' => [ 'date' => $link, 'username' => $this->renderer->renderPlain($username), 'message' => ['#markup' => $revision->revision_log->value, '#allowed_tags' => Xss::getHtmlTagList()], ], ], ]; // @todo Simplify once https://www.drupal.org/node/2334319 lands. $this->renderer->addCacheableDependency($column['data'], $username); $row[] = $column; if ($vid == $default_revision) { $row[] = [ 'data' => [ '#prefix' => '', '#markup' => $this->t('Current revision'), '#suffix' => '', ], ]; $rows[] = [ 'data' => $row, 'class' => ['revision-current'], ]; } else { $links = []; if ($revert_permission) { $links['revert'] = [ 'title' => $vid < $node->getRevisionId() ? $this->t('Revert') : $this->t('Set as current revision'), 'url' => $has_translations ? Url::fromRoute('node.revision_revert_translation_confirm', ['node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode]) : Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid]), ]; } if ($delete_permission) { $links['delete'] = [ 'title' => $this->t('Delete'), 'url' => Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $vid]), ]; } $row[] = [ 'data' => [ '#type' => 'operations', '#links' => $links, ], ]; $rows[] = $row; } } } $build['node_revisions_table'] = [ '#theme' => 'table', '#rows' => $rows, '#header' => $header, '#attached' => [ 'library' => ['node/drupal.node.admin'], ], '#attributes' => ['class' => 'node-revision-table'], ]; $build['pager'] = ['#type' => 'pager']; return $build; } /** * The _title_callback for the node.add route. * * @param \Drupal\node\NodeTypeInterface $node_type * The current node. * * @return string * The page title. */ public function addPageTitle(NodeTypeInterface $node_type) { return $this->t('Create @name', ['@name' => $node_type->label()]); } /** * Gets a list of node revision IDs for a specific node. * * @param \Drupal\node\NodeInterface $node * The node entity. * @param \Drupal\node\NodeStorageInterface $node_storage * The node storage handler. * * @return int[] * Node revision IDs (in descending order). */ protected function getRevisionIds(NodeInterface $node, NodeStorageInterface $node_storage) { $result = $node_storage->getQuery() ->allRevisions() ->condition($node->getEntityType()->getKey('id'), $node->id()) ->sort($node->getEntityType()->getKey('revision'), 'DESC') ->pager(50) ->execute(); return array_keys($result); } }