3 namespace Drupal\entity\Controller;
5 use Drupal\Core\Entity\ContentEntityInterface;
6 use Drupal\Core\Language\LanguageInterface;
7 use Drupal\Core\Entity\EntityInterface;
10 * Defines a trait for common revision UI functionality.
12 trait RevisionControllerTrait {
15 * Returns the entity type manager.
17 * @return \Drupal\Core\Entity\EntityTypeManagerInterface
19 abstract protected function entityTypeManager();
22 * Returns the langauge manager.
24 * @return \Drupal\Core\Language\LanguageManagerInterface
26 public abstract function languageManager();
29 * Determines if the user has permission to revert revisions.
31 * @param \Drupal\Core\Entity\EntityInterface $entity
32 * The entity to check revert access for.
35 * TRUE if the user has revert access.
37 abstract protected function hasRevertRevisionAccess(EntityInterface $entity);
40 * Determines if the user has permission to delete revisions.
42 * @param \Drupal\Core\Entity\EntityInterface $entity
43 * The entity to check delete revision access for.
46 * TRUE if the user has delete revision access.
48 abstract protected function hasDeleteRevisionAccess(EntityInterface $entity);
51 * Builds a link to revert an entity revision.
53 * @param \Drupal\Core\Entity\EntityInterface $entity_revision
54 * The entity to build a revert revision link for.
57 * A link render array.
60 abstract protected function buildRevertRevisionLink(EntityInterface $entity_revision);
63 * Builds a link to delete an entity revision.
65 * @param \Drupal\Core\Entity\EntityInterface $entity_revision
66 * The entity to build a delete revision link for.
69 * A link render array.
71 abstract protected function buildDeleteRevisionLink(EntityInterface $entity_revision);
74 * Returns a string providing details of the revision.
76 * E.g. Node describes its revisions using {date} by {username}. For the
77 * non-current revision, it also provides a link to view that revision.
79 * @param \Drupal\Core\Entity\ContentEntityInterface $revision
80 * The entity revision.
81 * @param bool $is_current
82 * TRUE if the revision is the current revision.
85 * Returns a string to provide the details of the revision.
87 abstract protected function getRevisionDescription(ContentEntityInterface $revision, $is_current = FALSE);
90 * Loads all revision IDs of an entity sorted by revision ID descending.
92 * @param \Drupal\Core\Entity\ContentEntityInterface $entity
97 protected function revisionIds(ContentEntityInterface $entity) {
98 $entity_type = $entity->getEntityType();
99 $result = $this->entityTypeManager()->getStorage($entity_type->id())->getQuery()
101 ->condition($entity_type->getKey('id'), $entity->id())
102 ->sort($entity_type->getKey('revision'), 'DESC')
104 return array_keys($result);
108 * Generates an overview table of older revisions of an entity.
110 * @param \Drupal\Core\Entity\ContentEntityInterface $entity
116 protected function revisionOverview(ContentEntityInterface $entity) {
117 $langcode = $this->languageManager()
118 ->getCurrentLanguage(LanguageInterface::TYPE_CONTENT)
120 $entity_storage = $this->entityTypeManager()
121 ->getStorage($entity->getEntityTypeId());
123 $header = [$this->t('Revision'), $this->t('Operations')];
126 $revision_ids = $this->revisionIds($entity);
127 // @todo Expand the entity storage to load multiple revisions.
128 $entity_revisions = array_combine($revision_ids, array_map(function($vid) use ($entity_storage) {
129 return $entity_storage->loadRevision($vid);
132 foreach ($entity_revisions as $revision) {
134 /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
135 if ($revision->hasTranslation($langcode) && $revision->getTranslation($langcode)
136 ->isRevisionTranslationAffected()
138 $row[] = $this->getRevisionDescription($revision, $revision->isDefaultRevision());
140 if ($revision->isDefaultRevision()) {
144 '#markup' => $this->t('Current revision'),
145 '#suffix' => '</em>',
148 foreach ($row as &$current) {
149 $current['class'] = ['revision-current'];
153 $links = $this->getOperationLinks($revision);
156 '#type' => 'operations',
166 $build[$entity->getEntityTypeId() . '_revisions_table'] = [
169 '#header' => $header,
172 // We have no clue about caching yet.
173 $build['#cache']['max-age'] = 0;
179 * Get the links of the operations for an entity revision.
181 * @param \Drupal\Core\Entity\EntityInterface $entity_revision
182 * The entity to build the revision links for.
185 * The operation links.
187 protected function getOperationLinks(EntityInterface $entity_revision) {
189 if ($this->hasRevertRevisionAccess($entity_revision)) {
190 $links['revert'] = $this->buildRevertRevisionLink($entity_revision);
193 if ($this->hasDeleteRevisionAccess($entity_revision)) {
194 $links['delete'] = $this->buildDeleteRevisionLink($entity_revision);
197 return array_filter($links);