3 namespace Drupal\node\Controller;
5 use Drupal\Core\Entity\EntityInterface;
6 use Drupal\Core\Entity\Controller\EntityViewController;
7 use Drupal\Core\Entity\EntityManagerInterface;
8 use Drupal\Core\Render\RendererInterface;
9 use Drupal\Core\Session\AccountInterface;
10 use Symfony\Component\DependencyInjection\ContainerInterface;
13 * Defines a controller to render a single node.
15 class NodeViewController extends EntityViewController {
20 * @var \Drupal\Core\Session\AccountInterface
22 protected $currentUser;
25 * Creates an NodeViewController object.
27 * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
29 * @param \Drupal\Core\Render\RendererInterface $renderer
30 * The renderer service.
31 * @param \Drupal\Core\Session\AccountInterface $current_user
32 * The current user. For backwards compatibility this is optional, however
33 * this will be removed before Drupal 9.0.0.
35 public function __construct(EntityManagerInterface $entity_manager, RendererInterface $renderer, AccountInterface $current_user = NULL) {
36 parent::__construct($entity_manager, $renderer);
37 $this->currentUser = $current_user ?: \Drupal::currentUser();
43 public static function create(ContainerInterface $container) {
45 $container->get('entity.manager'),
46 $container->get('renderer'),
47 $container->get('current_user')
54 public function view(EntityInterface $node, $view_mode = 'full', $langcode = NULL) {
55 $build = parent::view($node, $view_mode, $langcode);
57 foreach ($node->uriRelationships() as $rel) {
58 $url = $node->toUrl($rel);
59 // Add link relationships if the user is authenticated or if the anonymous
60 // user has access. Access checking must be done for anonymous users to
61 // avoid traffic to inaccessible pages from web crawlers. For
62 // authenticated users, showing the links in HTML head does not impact
63 // user experience or security, since the routes are access checked when
64 // visited and only visible via view source. This prevents doing
65 // potentially expensive and hard to cache access checks on every request.
66 // This means that the page will vary by user.permissions. We also rely on
67 // the access checking fallback to ensure the correct cacheability
68 // metadata if we have to check access.
69 if ($this->currentUser->isAuthenticated() || $url->access($this->currentUser)) {
70 // Set the node path as the canonical URL to prevent duplicate content.
71 $build['#attached']['html_head_link'][] = [
74 'href' => $url->toString(),
80 if ($rel == 'canonical') {
81 // Set the non-aliased canonical path as a default shortlink.
82 $build['#attached']['html_head_link'][] = [
85 'href' => $url->setOption('alias', TRUE)->toString(),
92 // Given this varies by $this->currentUser->isAuthenticated(), add a cache
93 // context based on the anonymous role.
94 $build['#cache']['contexts'][] = 'user.roles:anonymous';
100 * The _title_callback for the page that renders a single node.
102 * @param \Drupal\Core\Entity\EntityInterface $node
108 public function title(EntityInterface $node) {
109 return $this->entityManager->getTranslationFromContext($node)->label();