Updated all the contrib modules to their latest versions.
[yaffs-website] / web / modules / contrib / diff / src / Controller / PluginRevisionController.php
1 <?php
2
3 namespace Drupal\diff\Controller;
4
5 use Drupal\Core\Entity\ContentEntityInterface;
6 use Symfony\Component\HttpFoundation\RequestStack;
7 use Symfony\Component\DependencyInjection\ContainerInterface;
8 use Drupal\Component\Utility\UrlHelper;
9 use Drupal\Core\Entity\EntityStorageInterface;
10 use Drupal\Core\Link;
11 use Drupal\Core\Routing\RouteMatchInterface;
12 use Drupal\Core\Url;
13 use Drupal\Core\Controller\ControllerBase;
14 use Drupal\diff\DiffLayoutManager;
15 use Drupal\diff\DiffEntityComparison;
16
17 /**
18  * Base class for controllers that return responses on entity revision routes.
19  */
20 class PluginRevisionController extends ControllerBase {
21
22   /**
23    * Wrapper object for writing/reading configuration from diff.plugins.yml.
24    *
25    * @var \Drupal\Core\Config\ImmutableConfig
26    */
27   protected $config;
28
29   /**
30    * The diff entity comparison service.
31    *
32    * @var \Drupal\diff\DiffEntityComparison
33    */
34   protected $entityComparison;
35
36   /**
37    * The field diff layout plugin manager service.
38    *
39    * @var \Drupal\diff\DiffLayoutManager
40    */
41   protected $diffLayoutManager;
42
43   /**
44    * The request stack.
45    *
46    * @var \Symfony\Component\HttpFoundation\RequestStack
47    */
48   protected $requestStack;
49
50   /**
51    * Constructs a PluginRevisionController object.
52    *
53    * @param \Drupal\diff\DiffEntityComparison $entity_comparison
54    *   The diff entity comparison service.
55    * @param \Drupal\diff\DiffLayoutManager $diff_layout_manager
56    *   The diff layout service.
57    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
58    *   The request stack.
59    */
60   public function __construct(DiffEntityComparison $entity_comparison, DiffLayoutManager $diff_layout_manager, RequestStack $request_stack) {
61     $this->config = $this->config('diff.settings');
62     $this->diffLayoutManager = $diff_layout_manager;
63     $this->entityComparison = $entity_comparison;
64     $this->requestStack = $request_stack;
65   }
66
67   /**
68    * {@inheritdoc}
69    */
70   public static function create(ContainerInterface $container) {
71     return new static(
72       $container->get('diff.entity_comparison'),
73       $container->get('plugin.manager.diff.layout'),
74       $container->get('request_stack')
75     );
76   }
77
78   /**
79    * Get all the revision ids of given entity id.
80    *
81    * @param \Drupal\Core\Entity\EntityStorageInterface $storage
82    *   The entity storage manager.
83    * @param int $entity_id
84    *   The entity to find revisions of.
85    *
86    * @return int[]
87    *   The revision ids.
88    */
89   public function getRevisionIds(EntityStorageInterface $storage, $entity_id) {
90     $result = $storage->getQuery()
91       ->allRevisions()
92       ->condition($storage->getEntityType()->getKey('id'), $entity_id)
93       ->accessCheck(FALSE)
94       ->execute();
95     $result_array = array_keys($result);
96     sort($result_array);
97     return $result_array;
98   }
99
100   /**
101    * Returns a table which shows the differences between two entity revisions.
102    *
103    * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
104    *   The route match.
105    * @param \Drupal\Core\Entity\ContentEntityInterface $left_revision
106    *   The left revision.
107    * @param \Drupal\Core\Entity\ContentEntityInterface $right_revision
108    *   The right revision.
109    * @param string $filter
110    *   If $filter == 'raw' raw text is compared (including html tags)
111    *   If filter == 'raw-plain' markdown function is applied to the text before comparison.
112    *
113    * @return array
114    *   Table showing the diff between the two entity revisions.
115    */
116   public function compareEntityRevisions(RouteMatchInterface $route_match, ContentEntityInterface $left_revision, ContentEntityInterface $right_revision, $filter) {
117     $entity_type_id = $left_revision->getEntityTypeId();
118     /** @var \Drupal\Core\Entity\EntityInterface $entity */
119     $entity = $route_match->getParameter($entity_type_id);
120
121     $entity_type_id = $entity->getEntityTypeId();
122     $storage = $this->entityTypeManager()->getStorage($entity_type_id);
123     // Get language from the entity context.
124     $langcode = $entity->language()->getId();
125
126     // Get left and right revision in current language.
127     $left_revision = $left_revision->getTranslation($langcode);
128     $right_revision = $right_revision->getTranslation($langcode);
129
130     $revisions_ids = [];
131     // Filter revisions of current translation and where the translation is
132     // affected.
133     foreach ($this->getRevisionIds($storage, $entity->id()) as $revision_id) {
134       /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
135       $revision = $storage->loadRevision($revision_id);
136       if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)->isRevisionTranslationAffected()) {
137         $revisions_ids[] = $revision_id;
138       }
139     }
140
141     $build = [
142       '#title' => $this->t('Changes to %title', ['%title' => $entity->label()]),
143       'header' => [
144         '#prefix' => '<header class="diff-header">',
145         '#suffix' => '</header>',
146       ],
147       'controls' => [
148         '#prefix' => '<div class="diff-controls">',
149         '#suffix' => '</div>',
150       ],
151     ];
152
153     // Build the navigation links.
154     $build['header']['diff_navigation'] = $this->buildRevisionsNavigation($entity, $revisions_ids, $left_revision->getRevisionId(), $right_revision->getRevisionId(), $filter);
155
156     // Build the layout filter.
157     $build['controls']['diff_layout'] = [
158       '#type' => 'item',
159       '#title' => $this->t('Layout'),
160       '#wrapper_attributes' => ['class' => 'diff-controls__item'],
161       'filter' => $this->buildLayoutNavigation($entity, $left_revision->getRevisionId(), $right_revision->getRevisionId(), $filter),
162     ];
163
164     // Perform comparison only if both entity revisions loaded successfully.
165     if ($left_revision != FALSE && $right_revision != FALSE) {
166       // Build the diff comparison with the plugin.
167       if ($plugin = $this->diffLayoutManager->createInstance($filter)) {
168         $build = array_merge_recursive($build, $plugin->build($left_revision, $right_revision, $entity));
169         $build['diff']['#prefix'] = '<div class="diff-responsive-table-wrapper">';
170         $build['diff']['#suffix'] = '</div>';
171         $build['diff']['#attributes']['class'][] = 'diff-responsive-table';
172       }
173     }
174
175     $build['#attached']['library'][] = 'diff/diff.general';
176     return $build;
177   }
178
179   /**
180    * Builds a navigation dropdown button between the layout plugins.
181    *
182    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
183    *   The entity to be compared.
184    * @param int $left_revision_id
185    *   Revision id of the left revision.
186    * @param int $right_revision_id
187    *   Revision id of the right revision.
188    * @param string $active_filter
189    *   The active filter.
190    *
191    * @return array
192    *   The layout filter.
193    */
194   protected function buildLayoutNavigation(ContentEntityInterface $entity, $left_revision_id, $right_revision_id, $active_filter) {
195     $links = [];
196     $layouts = $this->diffLayoutManager->getPluginOptions();
197     foreach ($layouts as $key => $value) {
198       $links[$key] = array(
199         'title' => $value,
200         'url' => $this->diffRoute($entity, $left_revision_id, $right_revision_id, $key),
201       );
202     }
203
204     // Set as the first element the current filter.
205     $filter = $links[$active_filter];
206     unset($links[$active_filter]);
207     array_unshift($links, $filter);
208
209     $filter = [
210       '#type' => 'operations',
211       '#links' => $links,
212     ];
213
214     return $filter;
215   }
216
217   /**
218    * Creates navigation links between the previous changes and the new ones.
219    *
220    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
221    *   The entity to be compared.
222    * @param array $revision_ids
223    *   The revision ids.
224    * @param int $left_revision_id
225    *   Revision id of the left revision.
226    * @param int $right_revision_id
227    *   Revision id of the right revision.
228    * @param string $filter
229    *   The filter.
230    *
231    * @return array
232    *   The revision navigation links.
233    */
234   protected function buildRevisionsNavigation(ContentEntityInterface $entity, array $revision_ids, $left_revision_id, $right_revision_id, $filter) {
235     $revisions_count = count($revision_ids);
236     $layout_options = &drupal_static(__FUNCTION__);
237     if (!isset($layout_options)) {
238       $layout_options = UrlHelper::filterQueryParameters($this->requestStack->getCurrentRequest()->query->all(), ['page']);
239     }
240     // If there are only 2 revision return an empty row.
241     if ($revisions_count == 2) {
242       return [];
243     }
244     else {
245       $left_link = $right_link = '';
246       $element = [
247         '#type' => 'item',
248         '#title' => $this->t('Navigation'),
249         '#wrapper_attributes' => ['class' => 'diff-navigation'],
250       ];
251       $i = 0;
252       // Find the previous revision.
253       while ($left_revision_id > $revision_ids[$i]) {
254         $i += 1;
255       }
256       if ($i != 0) {
257         // Build the left link.
258         $left_link = Link::fromTextAndUrl($this->t('Previous change'), $this->diffRoute($entity, $revision_ids[$i - 1], $left_revision_id, $filter, $layout_options))->toString();
259       }
260       $element['left'] = [
261         '#type' => 'markup',
262         '#markup' => $left_link,
263         '#prefix' => '<div class="diff-navigation__link prev-link">',
264         '#suffix' => '</div>',
265       ];
266       // Find the next revision.
267       $i = 0;
268       while ($i < $revisions_count && $right_revision_id >= $revision_ids[$i]) {
269         $i += 1;
270       }
271       if ($revisions_count != $i && $revision_ids[$i - 1] != $revision_ids[$revisions_count - 1]) {
272         // Build the right link.
273         $right_link = Link::fromTextAndUrl($this->t('Next change'), $this->diffRoute($entity, $right_revision_id, $revision_ids[$i], $filter, $layout_options))->toString();
274       }
275       $element['right'] = [
276         '#type' => 'markup',
277         '#markup' => $right_link,
278         '#prefix' => '<div class="diff-navigation__link next-link">',
279         '#suffix' => '</div>',
280       ];
281       return $element;
282     }
283   }
284
285   /**
286    * Creates an url object for diff.
287    *
288    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
289    *   The entity to be compared.
290    * @param int $left_revision_id
291    *   Revision id of the left revision.
292    * @param int $right_revision_id
293    *   Revision id of the right revision.
294    * @param string $layout
295    *   (optional) The filter/layout added to the route.
296    * @param array $layout_options
297    *   (optional) The layout options provided by the selected layout.
298    *
299    * @return \Drupal\Core\Url
300    *   The URL object.
301    */
302   public static function diffRoute(ContentEntityInterface $entity, $left_revision_id, $right_revision_id, $layout = NULL, array $layout_options = NULL) {
303     $entity_type_id = $entity->getEntityTypeId();
304     // @todo Remove the diff.revisions_diff route so we avoid adding extra cases.
305     if ($entity->getEntityTypeId() == 'node') {
306       $route_name = 'diff.revisions_diff';
307     }
308     else {
309       $route_name = "entity.$entity_type_id.revisions_diff";
310     }
311     $route_parameters = [
312       $entity_type_id => $entity->id(),
313       'left_revision' => $left_revision_id,
314       'right_revision' => $right_revision_id,
315     ];
316     if ($layout) {
317       $route_parameters['filter'] = $layout;
318     }
319     $options = [];
320     if ($layout_options) {
321       $options = [
322         'query' => $layout_options,
323       ];
324     }
325     return Url::fromRoute($route_name, $route_parameters, $options);
326   }
327
328 }