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