Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / diff / src / Form / RevisionOverviewForm.php
1 <?php
2
3 namespace Drupal\diff\Form;
4
5 use Drupal\Component\Utility\Xss;
6 use Drupal\Core\Entity\ContentEntityInterface;
7 use Drupal\Core\Entity\EntityTypeManagerInterface;
8 use Drupal\Core\Language\LanguageManagerInterface;
9 use Drupal\Core\Link;
10 use Drupal\diff\DiffEntityComparison;
11 use Drupal\diff\DiffLayoutManager;
12 use Symfony\Component\DependencyInjection\ContainerInterface;
13 use Drupal\Core\Form\FormBase;
14 use Drupal\Core\Session\AccountInterface;
15 use Drupal\Core\Datetime\DateFormatter;
16 use Drupal\Core\Form\FormStateInterface;
17 use Drupal\Core\Url;
18 use Drupal\Core\Render\RendererInterface;
19
20 /**
21  * Provides a form for revision overview page.
22  */
23 class RevisionOverviewForm extends FormBase {
24
25   /**
26    * The entity type manager.
27    *
28    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
29    */
30   protected $entityTypeManager;
31
32   /**
33    * The current user service.
34    *
35    * @var \Drupal\Core\Session\AccountInterface
36    */
37   protected $currentUser;
38
39   /**
40    * The date service.
41    *
42    * @var \Drupal\Core\Datetime\DateFormatter
43    */
44   protected $date;
45
46   /**
47    * The renderer service.
48    *
49    * @var \Drupal\Core\Render\RendererInterface
50    */
51   protected $renderer;
52
53   /**
54    * The language manager.
55    *
56    * @var \Drupal\Core\Language\LanguageManagerInterface
57    */
58   protected $languageManager;
59
60   /**
61    * Wrapper object for simple configuration from diff.settings.yml.
62    *
63    * @var \Drupal\Core\Config\ImmutableConfig
64    */
65   protected $config;
66
67   /**
68    * The field diff layout plugin manager service.
69    *
70    * @var \Drupal\diff\DiffLayoutManager
71    */
72   protected $diffLayoutManager;
73
74   /**
75    * The diff entity comparison service.
76    *
77    * @var \Drupal\diff\DiffEntityComparison
78    */
79   protected $entityComparison;
80
81   /**
82    * Constructs a RevisionOverviewForm object.
83    *
84    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
85    *   The entity type manager.
86    * @param \Drupal\Core\Session\AccountInterface $current_user
87    *   The current user.
88    * @param \Drupal\Core\Datetime\DateFormatter $date
89    *   The date service.
90    * @param \Drupal\Core\Render\RendererInterface $renderer
91    *   The renderer service.
92    * @param \Drupal\Core\Language\LanguageManagerInterface $language_manager
93    *   The language manager.
94    * @param \Drupal\diff\DiffLayoutManager $diff_layout_manager
95    *   The diff layout service.
96    * @param \Drupal\diff\DiffEntityComparison $entity_comparison
97    *   The diff entity comparison service.
98    */
99   public function __construct(EntityTypeManagerInterface $entity_type_manager, AccountInterface $current_user, DateFormatter $date, RendererInterface $renderer, LanguageManagerInterface $language_manager, DiffLayoutManager $diff_layout_manager, DiffEntityComparison $entity_comparison) {
100     $this->entityTypeManager = $entity_type_manager;
101     $this->currentUser = $current_user;
102     $this->date = $date;
103     $this->renderer = $renderer;
104     $this->languageManager = $language_manager;
105     $this->config = $this->config('diff.settings');
106     $this->diffLayoutManager = $diff_layout_manager;
107     $this->entityComparison = $entity_comparison;
108   }
109
110   /**
111    * {@inheritdoc}
112    */
113   public static function create(ContainerInterface $container) {
114     return new static(
115       $container->get('entity_type.manager'),
116       $container->get('current_user'),
117       $container->get('date.formatter'),
118       $container->get('renderer'),
119       $container->get('language_manager'),
120       $container->get('plugin.manager.diff.layout'),
121       $container->get('diff.entity_comparison')
122     );
123   }
124
125   /**
126    * {@inheritdoc}
127    */
128   public function getFormId() {
129     return 'revision_overview_form';
130   }
131
132   /**
133    * {@inheritdoc}
134    */
135   public function buildForm(array $form, FormStateInterface $form_state, $node = NULL) {
136     $account = $this->currentUser;
137     /** @var \Drupal\node\NodeInterface $node */
138     $langcode = $node->language()->getId();
139     $langname = $node->language()->getName();
140     $languages = $node->getTranslationLanguages();
141     $has_translations = (count($languages) > 1);
142     $node_storage = $this->entityTypeManager->getStorage('node');
143     $type = $node->getType();
144
145     $pagerLimit = $this->config->get('general_settings.revision_pager_limit');
146
147     $query = $this->entityTypeManager->getStorage('node')->getQuery()
148       ->condition($node->getEntityType()->getKey('id'), $node->id())
149       ->pager($pagerLimit)
150       ->allRevisions()
151       ->sort($node->getEntityType()->getKey('revision'), 'DESC')
152       // Access to the content has already been verified. Disable query-level
153       // access checking so that revisions for unpublished content still
154       //appear.
155       ->accessCheck(FALSE)
156       ->execute();
157     $vids = array_keys($query);
158
159     $revision_count = count($vids);
160
161     $build['#title'] = $has_translations ? $this->t('@langname revisions for %title', [
162       '@langname' => $langname,
163       '%title' => $node->label(),
164     ]) : $this->t('Revisions for %title', [
165       '%title' => $node->label(),
166     ]);
167     $build['nid'] = array(
168       '#type' => 'hidden',
169       '#value' => $node->id(),
170     );
171
172     $table_header = [];
173     $table_header['revision'] = $this->t('Revision');
174
175     // Allow comparisons only if there are 2 or more revisions.
176     if ($revision_count > 1) {
177       $table_header += array(
178         'select_column_one' => '',
179         'select_column_two' => '',
180       );
181     }
182     $table_header['operations'] = $this->t('Operations');
183
184     $rev_revert_perm = $account->hasPermission("revert $type revisions") ||
185       $account->hasPermission('revert all revisions') ||
186       $account->hasPermission('administer nodes');
187     $rev_delete_perm = $account->hasPermission("delete $type revisions") ||
188       $account->hasPermission('delete all revisions') ||
189       $account->hasPermission('administer nodes');
190     $revert_permission = $rev_revert_perm && $node->access('update');
191     $delete_permission = $rev_delete_perm && $node->access('delete');
192
193     // Contains the table listing the revisions.
194     $build['node_revisions_table'] = array(
195       '#type' => 'table',
196       '#header' => $table_header,
197       '#attributes' => array('class' => array('diff-revisions')),
198     );
199
200     $build['node_revisions_table']['#attached']['library'][] = 'diff/diff.general';
201     $build['node_revisions_table']['#attached']['drupalSettings']['diffRevisionRadios'] = $this->config->get('general_settings.radio_behavior');
202
203     $default_revision = $node->getRevisionId();
204     // Add rows to the table.
205     foreach ($vids as $key => $vid) {
206       $previous_revision = NULL;
207       if (isset($vids[$key + 1])) {
208         $previous_revision = $node_storage->loadRevision($vids[$key + 1]);
209       }
210       /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
211       if ($revision = $node_storage->loadRevision($vid)) {
212         if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) {
213           $username = array(
214             '#theme' => 'username',
215             '#account' => $revision->getRevisionAuthor(),
216           );
217           $revision_date = $this->date->format($revision->getRevisionCreationTime(), 'short');
218           // Use revision link to link to revisions that are not active.
219           if ($vid != $node->getRevisionId()) {
220             $link = Link::fromTextAndUrl($revision_date, new Url('entity.node.revision', ['node' => $node->id(), 'node_revision' => $vid]));
221           }
222           else {
223             $link = $node->toLink($revision_date);
224           }
225
226           if ($vid == $default_revision) {
227             $row = [
228               'revision' => $this->buildRevision($link, $username, $revision, $previous_revision),
229             ];
230
231             // Allow comparisons only if there are 2 or more revisions.
232             if ($revision_count > 1) {
233               $row += [
234                 'select_column_one' => $this->buildSelectColumn('radios_left', $vid, FALSE),
235                 'select_column_two' => $this->buildSelectColumn('radios_right', $vid, $vid),
236               ];
237             }
238             $row['operations'] = array(
239               '#prefix' => '<em>',
240               '#markup' => $this->t('Current revision'),
241               '#suffix' => '</em>',
242               '#attributes' => array(
243                 'class' => array('revision-current'),
244               ),
245             );
246             $row['#attributes'] = [
247               'class' => ['revision-current'],
248             ];
249           }
250           else {
251             $route_params = array(
252               'node' => $node->id(),
253               'node_revision' => $vid,
254               'langcode' => $langcode,
255             );
256             $links = array();
257             if ($revert_permission) {
258               $links['revert'] = [
259                 'title' => $vid < $node->getRevisionId() ? $this->t('Revert') : $this->t('Set as current revision'),
260                 'url' => $has_translations ?
261                   Url::fromRoute('node.revision_revert_translation_confirm', ['node' => $node->id(), 'node_revision' => $vid, 'langcode' => $langcode]) :
262                   Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $vid]),
263               ];
264             }
265             if ($delete_permission) {
266               $links['delete'] = array(
267                 'title' => $this->t('Delete'),
268                 'url' => Url::fromRoute('node.revision_delete_confirm', $route_params),
269               );
270             }
271
272             // Here we don't have to deal with 'only one revision' case because
273             // if there's only one revision it will also be the default one,
274             // entering on the first branch of this if else statement.
275             $row = [
276               'revision' => $this->buildRevision($link, $username, $revision, $previous_revision),
277               'select_column_one' => $this->buildSelectColumn('radios_left', $vid,
278                 isset($vids[1]) ? $vids[1] : FALSE),
279               'select_column_two' => $this->buildSelectColumn('radios_right', $vid, FALSE),
280               'operations' => [
281                 '#type' => 'operations',
282                 '#links' => $links,
283               ],
284             ];
285           }
286           // Add the row to the table.
287           $build['node_revisions_table'][] = $row;
288         }
289       }
290     }
291
292     // Allow comparisons only if there are 2 or more revisions.
293     if ($revision_count > 1) {
294       $build['submit'] = array(
295         '#type' => 'submit',
296         '#button_type' => 'primary',
297         '#value' => t('Compare selected revisions'),
298         '#attributes' => array(
299           'class' => array(
300             'diff-button',
301           ),
302         ),
303       );
304     }
305     $build['pager'] = array(
306       '#type' => 'pager',
307     );
308     $build['#attached']['library'][] = 'node/drupal.node.admin';
309     return $build;
310   }
311
312   /**
313    * Set column attributes and return config array.
314    *
315    * @param string $name
316    *   Name attribute.
317    * @param string $return_val
318    *   Return value attribute.
319    * @param string $default_val
320    *   Default value attribute.
321    *
322    * @return array
323    *   Configuration array.
324    */
325   protected function buildSelectColumn($name, $return_val, $default_val) {
326     return [
327       '#type' => 'radio',
328       '#title_display' => 'invisible',
329       '#name' => $name,
330       '#return_value' => $return_val,
331       '#default_value' => $default_val,
332     ];
333   }
334
335   /**
336    * Set and return configuration for revision.
337    *
338    * @param \Drupal\Core\Link $link
339    *   Link attribute.
340    * @param string $username
341    *   Username attribute.
342    * @param \Drupal\Core\Entity\ContentEntityInterface $revision
343    *   Revision parameter for getRevisionDescription function.
344    * @param \Drupal\Core\Entity\ContentEntityInterface $previous_revision
345    *   (optional) Previous revision for getRevisionDescription function.
346    *   Defaults to NULL.
347    *
348    * @return array
349    *   Configuration for revision.
350    */
351   protected function buildRevision(Link $link, $username, ContentEntityInterface $revision, ContentEntityInterface $previous_revision = NULL) {
352     return [
353       '#type' => 'inline_template',
354       '#template' => '{% trans %}{{ date }} by {{ username }}{% endtrans %}{% if message %}<p class="revision-log">{{ message }}</p>{% endif %}',
355       '#context' => [
356         'date' => $link->toString(),
357         'username' => $this->renderer->renderPlain($username),
358         'message' => [
359           '#markup' => $this->entityComparison->getRevisionDescription($revision, $previous_revision),
360           '#allowed_tags' => Xss::getAdminTagList(),
361         ],
362       ],
363     ];
364   }
365
366   /**
367    * {@inheritdoc}
368    */
369   public function validateForm(array &$form, FormStateInterface $form_state) {
370     $input = $form_state->getUserInput();
371
372     if (count($form_state->getValue('node_revisions_table')) <= 1) {
373       $form_state->setErrorByName('node_revisions_table', $this->t('Multiple revisions are needed for comparison.'));
374     }
375     elseif (!isset($input['radios_left']) || !isset($input['radios_right'])) {
376       $form_state->setErrorByName('node_revisions_table', $this->t('Select two revisions to compare.'));
377     }
378     elseif ($input['radios_left'] == $input['radios_right']) {
379       // @todo Radio-boxes selection resets if there are errors.
380       $form_state->setErrorByName('node_revisions_table', $this->t('Select different revisions to compare.'));
381     }
382   }
383
384   /**
385    * {@inheritdoc}
386    */
387   public function submitForm(array &$form, FormStateInterface $form_state) {
388     $input = $form_state->getUserInput();
389     $vid_left = $input['radios_left'];
390     $vid_right = $input['radios_right'];
391     $nid = $input['nid'];
392
393     // Always place the older revision on the left side of the comparison
394     // and the newer revision on the right side (however revisions can be
395     // compared both ways if we manually change the order of the parameters).
396     if ($vid_left > $vid_right) {
397       $aux = $vid_left;
398       $vid_left = $vid_right;
399       $vid_right = $aux;
400     }
401     // Builds the redirect Url.
402     $redirect_url = Url::fromRoute(
403       'diff.revisions_diff',
404       array(
405         'node' => $nid,
406         'left_revision' => $vid_left,
407         'right_revision' => $vid_right,
408         'filter' => $this->diffLayoutManager->getDefaultLayout(),
409       )
410     );
411     $form_state->setRedirectUrl($redirect_url);
412   }
413
414 }