1<?php
2
3namespace Drupal\content_translation\Access;
4
5use Drupal\content_translation\ContentTranslationManager;
6use Drupal\content_translation\ContentTranslationManagerInterface;
7use Drupal\Core\Access\AccessResult;
8use Drupal\Core\Entity\ContentEntityInterface;
9use Drupal\Core\Entity\EntityTypeManagerInterface;
10use Drupal\Core\Routing\Access\AccessInterface;
11use Drupal\Core\Routing\RouteMatchInterface;
12use Drupal\Core\Session\AccountInterface;
13use Drupal\language\Entity\ContentLanguageSettings;
14use Drupal\workflows\Entity\Workflow;
15
16/**
17 * Access check for entity translation deletion.
18 *
19 * @internal This additional access checker only aims to prevent deletions in
20 *   pending revisions until we are able to flag revision translations as
21 *   deleted.
22 *
23 * @todo Remove this in https://www.drupal.org/node/2945956.
24 */
25class ContentTranslationDeleteAccess implements AccessInterface {
26
27  /**
28   * The entity type manager.
29   *
30   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
31   */
32  protected $entityTypeManager;
33
34  /**
35   * The content translation manager.
36   *
37   * @var \Drupal\content_translation\ContentTranslationManagerInterface
38   */
39  protected $contentTranslationManager;
40
41  /**
42   * Constructs a ContentTranslationDeleteAccess object.
43   *
44   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $manager
45   *   The entity type manager.
46   * @param \Drupal\content_translation\ContentTranslationManagerInterface $content_translation_manager
47   *   The content translation manager.
48   */
49  public function __construct(EntityTypeManagerInterface $manager, ContentTranslationManagerInterface $content_translation_manager) {
50    $this->entityTypeManager = $manager;
51    $this->contentTranslationManager = $content_translation_manager;
52  }
53
54  /**
55   * Checks access to translation deletion for the specified route match.
56   *
57   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
58   *   The parameterized route.
59   * @param \Drupal\Core\Session\AccountInterface $account
60   *   The currently logged in account.
61   *
62   * @return \Drupal\Core\Access\AccessResultInterface
63   *   The access result.
64   */
65  public function access(RouteMatchInterface $route_match, AccountInterface $account) {
66    $requirement = $route_match->getRouteObject()->getRequirement('_access_content_translation_delete');
67    $entity_type_id = current(explode('.', $requirement));
68    $entity = $route_match->getParameter($entity_type_id);
69    return $this->checkAccess($entity);
70  }
71
72  /**
73   * Checks access to translation deletion for the specified entity.
74   *
75   * @param \Drupal\Core\Entity\ContentEntityInterface $entity
76   *   The entity translation to be deleted.
77   *
78   * @return \Drupal\Core\Access\AccessResultInterface
79   *   The access result.
80   */
81  public function checkAccess(ContentEntityInterface $entity) {
82    $result = AccessResult::allowed();
83
84    $entity_type_id = $entity->getEntityTypeId();
85    $result->addCacheableDependency($entity);
86    // Add the cache dependencies used by
87    // ContentTranslationManager::isPendingRevisionSupportEnabled().
88    if (\Drupal::moduleHandler()->moduleExists('content_moderation')) {
89      foreach (Workflow::loadMultipleByType('content_moderation') as $workflow) {
90        $result->addCacheableDependency($workflow);
91      }
92    }
93    if (!ContentTranslationManager::isPendingRevisionSupportEnabled($entity_type_id, $entity->bundle())) {
94      return $result;
95    }
96
97    if ($entity->isDefaultTranslation()) {
98      return $result;
99    }
100
101    $config = ContentLanguageSettings::load($entity_type_id . '.' . $entity->bundle());
102    $result->addCacheableDependency($config);
103    if (!$this->contentTranslationManager->isEnabled($entity_type_id, $entity->bundle())) {
104      return $result;
105    }
106
107    /** @var \Drupal\Core\Entity\ContentEntityStorageInterface $storage */
108    $storage = $this->entityTypeManager->getStorage($entity_type_id);
109    $revision_id = $storage->getLatestTranslationAffectedRevisionId($entity->id(), $entity->language()->getId());
110    if (!$revision_id) {
111      return $result;
112    }
113
114    /** @var \Drupal\Core\Entity\ContentEntityInterface $revision */
115    $revision = $storage->loadRevision($revision_id);
116    if ($revision->wasDefaultRevision()) {
117      return $result;
118    }
119
120    $result = $result->andIf(AccessResult::forbidden());
121    return $result;
122  }
123
124}
125