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