Version 1
[yaffs-website] / web / modules / contrib / entity / src / Access / EntityRevisionRouteAccessChecker.php
1 <?php
2
3 namespace Drupal\entity\Access;
4
5 use Drupal\Core\Access\AccessResult;
6 use Drupal\Core\Entity\ContentEntityInterface;
7 use Drupal\Core\Entity\EntityStorageInterface;
8 use Drupal\Core\Entity\EntityTypeManagerInterface;
9 use Drupal\Core\Routing\Access\AccessInterface;
10 use Drupal\Core\Session\AccountInterface;
11 use Symfony\Component\HttpFoundation\Request;
12 use Symfony\Component\HttpFoundation\RequestStack;
13 use Symfony\Component\Routing\Route;
14
15 /**
16  * Checks access to a entity revision.
17  */
18 class EntityRevisionRouteAccessChecker implements AccessInterface {
19
20   /**
21    * @var \Drupal\Core\Entity\EntityTypeManagerInterface
22    */
23   protected $entityTypeManager;
24
25   /**
26    * Stores calculated access check results.
27    *
28    * @var array
29    */
30   protected $accessCache = array();
31
32   /**
33    * The request stack.
34    *
35    * @var \Symfony\Component\HttpFoundation\RequestStack
36    */
37   protected $requestStack;
38
39   /**
40    * Creates a new EntityRevisionRouteAccessChecker instance.
41    *
42    * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
43    *   The entity manager.
44    * @param \Symfony\Component\HttpFoundation\RequestStack $request_stack
45    *   The request stack.
46    */
47   public function __construct(EntityTypeManagerInterface $entity_type_manager, RequestStack $request_stack) {
48     $this->entityTypeManager = $entity_type_manager;
49     $this->requestStack = $request_stack;
50   }
51
52   /**
53    * {@inheritdoc}
54    */
55   public function access(Route $route, AccountInterface $account, Request $request = NULL) {
56     if (empty($request)) {
57       $request = $this->requestStack->getCurrentRequest();
58     }
59
60     $operation = $route->getRequirement('_entity_access_revision');
61     list(, $operation) = explode('.', $operation, 2);
62
63     if ($operation === 'list') {
64       $_entity = $request->attributes->get('_entity', $request->attributes->get($route->getOption('entity_type_id')));
65       return AccessResult::allowedIf($this->checkAccess($_entity, $account, $operation))->cachePerPermissions();
66     }
67     else {
68       $_entity_revision = $request->attributes->get('_entity_revision');
69       return AccessResult::allowedIf($_entity_revision && $this->checkAccess($_entity_revision, $account, $operation))->cachePerPermissions();
70     }
71   }
72
73   protected function checkAccess(ContentEntityInterface $entity, AccountInterface $account, $operation = 'view') {
74     $entity_type = $entity->getEntityType();
75     $entity_type_id = $entity->getEntityTypeId();
76     $entity_access = $this->entityTypeManager->getAccessControlHandler($entity_type_id);
77
78     /** @var \Drupal\Core\Entity\EntityStorageInterface $entity_storage */
79     $entity_storage = $this->entityTypeManager->getStorage($entity_type_id);
80
81     $map = [
82       'view' => "view all $entity_type_id revisions",
83       'list' => "view all $entity_type_id revisions",
84       'update' => "revert all $entity_type_id revisions",
85       'delete' => "delete all $entity_type_id revisions",
86     ];
87     $bundle = $entity->bundle();
88     $type_map = [
89       'view' => "view $entity_type_id $bundle revisions",
90       'list' => "view $entity_type_id $bundle revisions",
91       'update' => "revert $entity_type_id $bundle revisions",
92       'delete' => "delete $entity_type_id $bundle revisions",
93     ];
94
95     if (!$entity || !isset($map[$operation]) || !isset($type_map[$operation])) {
96       // If there was no node to check against, or the $op was not one of the
97       // supported ones, we return access denied.
98       return FALSE;
99     }
100
101     // Statically cache access by revision ID, language code, user account ID,
102     // and operation.
103     $langcode = $entity->language()->getId();
104     $cid = $entity->getRevisionId() . ':' . $langcode . ':' . $account->id() . ':' . $operation;
105
106     if (!isset($this->accessCache[$cid])) {
107       // Perform basic permission checks first.
108       if (!$account->hasPermission($map[$operation]) && !$account->hasPermission($type_map[$operation]) && !$account->hasPermission('administer nodes')) {
109         $this->accessCache[$cid] = FALSE;
110         return FALSE;
111       }
112
113       if (($admin_permission = $entity_type->getAdminPermission()) && $account->hasPermission($admin_permission)) {
114         $this->accessCache[$cid] = TRUE;
115       }
116       else {
117         // First check the access to the default revision and finally, if the
118         // node passed in is not the default revision then access to that, too.
119         $this->accessCache[$cid] = $entity_access->access($entity_storage->load($entity->id()), $operation, $account) && ($entity->isDefaultRevision() || $entity_access->access($entity, $operation, $account));
120       }
121     }
122
123     return $this->accessCache[$cid];
124   }
125
126
127   /**
128    * Counts the number of revisions in the default language.
129    *
130    * @param \Drupal\Core\Entity\ContentEntityInterface $entity
131    *   The entity.
132    * @param \Drupal\Core\Entity\EntityStorageInterface $entity_storage
133    *   The entity storage.
134    *
135    * @return int
136    *   The number of revisions in the default language.
137    */
138   protected function countDefaultLanguageRevisions(ContentEntityInterface $entity, EntityStorageInterface $entity_storage) {
139     $entity_type = $entity->getEntityType();
140     $count = $entity_storage->getQuery()
141       ->allRevisions()
142       ->condition($entity_type->getKey('id'), $entity->id())
143       ->condition($entity_type->getKey('default_langcode'), 1)
144       ->count()
145       ->execute();
146     return $count;
147   }
148
149   /**
150    * Resets the access cache.
151    *
152    * @return $this
153    */
154   public function resetAccessCache() {
155     $this->accessCache = [];
156     return $this;
157   }
158
159 }