diff --git a/core/includes/entity.inc b/core/includes/entity.inc index fe30114..2b3885e 100644 --- a/core/includes/entity.inc +++ b/core/includes/entity.inc @@ -865,21 +865,11 @@ function entity_page_access(EntityInterface $entity, $operation = 'view') { * The entity type. * @param string $bundle * (optional) The bundle of the entity. Required if the entity supports - * bundles, defaults to the entity type otherwise. + * bundles, defaults to NULL otherwise. * * @return bool * TRUE if the access is granted. FALSE if access is denied. */ function entity_page_create_access($entity_type, $bundle = NULL) { - $definition = Drupal::entityManager()->getDefinition($entity_type); - - // Pass in the entity bundle if given and required. - $values = array(); - if ($bundle && isset($definition['entity_keys']['bundle'])) { - $values[$definition['entity_keys']['bundle']] = $bundle; - } - $entity = Drupal::entityManager() - ->getStorageController($entity_type) - ->create($values); - return $entity->access('create'); + return Drupal::entityManager()->getAccessController($entity_type)->createAccess($bundle); } diff --git a/core/lib/Drupal/Core/Entity/EntityAccessController.php b/core/lib/Drupal/Core/Entity/EntityAccessController.php index 7f46933..8caa93b 100644 --- a/core/lib/Drupal/Core/Entity/EntityAccessController.php +++ b/core/lib/Drupal/Core/Entity/EntityAccessController.php @@ -43,7 +43,7 @@ public function __construct($entity_type) { public function access(EntityInterface $entity, $operation, $langcode = Language::LANGCODE_DEFAULT, AccountInterface $account = NULL) { $this->prepareUser($account); - if (($access = $this->getCache($entity, $operation, $langcode, $account)) !== NULL) { + if (($access = $this->getCache($entity->uuid(), $operation, $langcode, $account)) !== NULL) { // Cache hit, no work necessary. return $access; } @@ -59,7 +59,8 @@ public function access(EntityInterface $entity, $operation, $langcode = Language $access = module_invoke_all($entity->entityType() . '_access', $entity->getBCEntity(), $operation, $account, $langcode); if ($return = $this->processAccessHookResults($access) === NULL) { - // No result from hook, so entity checks are done. + // No module had an opinion about the access, so let's the access + // controller check create access. $return = (bool) $this->checkAccess($entity, $operation, $langcode, $account); } return $this->setCache($return, $entity, $operation, $langcode, $account); @@ -69,8 +70,15 @@ public function access(EntityInterface $entity, $operation, $langcode = Language * We grant access to the entity if both of these conditions are met: * - No modules say to deny access. * - At least one module says to grant access. + * + * @param array $access + * An array of access results of the fired access hook. + * + * @return bool|NULL + * Returns FALSE if access should be denied, TRUE if access should be + * granted and NULL if no module denied access. */ - protected function processAccessHookResults($access) { + protected function processAccessHookResults(array $access) { if (in_array(FALSE, $access, TRUE)) { return FALSE; } @@ -82,13 +90,6 @@ protected function processAccessHookResults($access) { } } - protected function prepareUser($account) { - if (!$account) { - $account = $GLOBALS['user']; - } - return $account; - } - /** * Performs access checks. * @@ -116,8 +117,9 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A /** * Tries to retrieve a previously cached access value from the static cache. * - * @param \Drupal\Core\Entity\EntityInterface|string $entity - * The entity for which to check access or a custom string. + * @param string $cid + * Unique string identifier for the entity/operation, for example the + * entity UUID or a custom string. * @param string $operation * The entity operation. Usually one of 'view', 'update', 'create' or * 'delete'. @@ -131,18 +133,9 @@ protected function checkAccess(EntityInterface $entity, $operation, $langcode, A * is no record for the given user, operation, langcode and entity in the * cache. */ - protected function getCache($entity, $operation, $langcode, AccountInterface $account) { + protected function getCache($cid, $operation, $langcode, AccountInterface $account) { $uid = $account ? $account->id() : 0; - // The cache key might be either the UUID of an existing entity or a custom - // string, for example used by the createAccess method. - if ($entity instanceof EntityInterface) { - $cid = $entity->uuid(); - } - else { - $cid = $entity; - } - // Return from cache if a value has been set for it previously. if (isset($this->accessCache[$uid][$cid][$langcode][$operation])) { return $this->accessCache[$uid][$cid][$langcode][$operation]; @@ -154,8 +147,9 @@ protected function getCache($entity, $operation, $langcode, AccountInterface $ac * * @param bool $access * TRUE if the user has access, FALSE otherwise. - * @param \Drupal\Core\Entity\EntityInterface|string $entity - * The entity for which to check access or a custom string. + * @param string $cid + * Unique string identifier for the entity/operation, for example the + * entity UUID or a custom string. * @param string $operation * The entity operation. Usually one of 'view', 'update', 'create' or * 'delete'. @@ -167,19 +161,9 @@ protected function getCache($entity, $operation, $langcode, AccountInterface $ac * @return bool * TRUE if access was granted, FALSE otherwise. */ - protected function setCache($access, $entity, $operation, $langcode, AccountInterface $account) { + protected function setCache($access, $cid, $operation, $langcode, AccountInterface $account) { $uid = $account ? $account->id() : 0; - - // The cache key might be either the UUID of an existing entity or a custom - // string, for example used by the createAccess method. - if ($entity instanceof EntityInterface) { - $cid = $entity->uuid(); - } - else { - $cid = $entity; - } - // Save the given value in the static cache and directly return it. return $this->accessCache[$uid][$cid][$langcode][$operation] = (bool) $access; } @@ -194,13 +178,14 @@ public function resetCache() { /** * {@inheritdoc} */ - public function createAccess($entity_bundle = '', AccountInterface $account = NULL, $context = array()) { + public function createAccess($entity_bundle = NULL, AccountInterface $account = NULL, $context = array()) { $account = $this->prepareUser($account); $context += array( 'langcode' => Language::LANGCODE_DEFAULT, ); - if (($access = $this->getCache('create', 'create', $context['langcode'], $account)) !== NULL) { + $cid = $entity_bundle ? 'create:' . $entity_bundle : 'create'; + if (($access = $this->getCache($cid, 'create', $context['langcode'], $account)) !== NULL) { // Cache hit, no work necessary. return $access; } @@ -216,10 +201,11 @@ public function createAccess($entity_bundle = '', AccountInterface $account = NU $access = module_invoke_all($this->entity_type . '_create_access', $account, $context['langcode']); if ($return = $this->processAccessHookResults($access) === NULL) { - // No result from hook, so entity checks are done. - $return = (bool) $this->checkCreateAccess($access, $context); + // No module had an opinion about the access, so let's the access + // controller check create access. + $return = (bool) $this->checkCreateAccess($account, $context, $entity_bundle = NULL); } - return $this->setCache($return, 'create', 'create', $context['langcode'], $account); + return $this->setCache($return, $cid, 'create', $context['langcode'], $account); } /** @@ -230,16 +216,34 @@ public function createAccess($entity_bundle = '', AccountInterface $account = NU * * @param \Drupal\Core\Session\AccountInterface $account * The user for which to check access. - * * @param array $context * An array of key-value pairs to pass additional context when needed. + * @param string|null $entity_bundle + * (optional) The bundle of the entity. Required if the entity supports + * bundles, defaults to NULL otherwise. * * @return bool|null * TRUE if access was granted, FALSE if access was denied and NULL if access * could not be determined. */ - protected function checkCreateAccess(AccountInterface $account, array $context) { + protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) { return NULL; } + /** + * Loads the current account object, if it does not exist yet. + * + * @param \Drupal\Core\Session\AccountInterface $account + * The account interface instance. + * + * @return \Drupal\Core\Session\AccountInterface + * Returns the current account object. + */ + protected function prepareUser(AccountInterface $account = NULL) { + if (!$account) { + $account = $GLOBALS['user']; + } + return $account; + } + } diff --git a/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php b/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php index 3fff27a..c8c77c1 100644 --- a/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php +++ b/core/lib/Drupal/Core/Entity/EntityAccessControllerInterface.php @@ -39,14 +39,15 @@ public function access(EntityInterface $entity, $operation, $langcode = Language * Checks access to create an entity. * * @param string $entity_bundle - * (optional) The bundle to check access for. Defaults to an empty string. + * (optional) The bundle of the entity. Required if the entity supports + * bundles, defaults to NULL otherwise. * @param \Drupal\Core\Session\AccountInterface $account * (optional) The user session for which to check access, or NULL to check * access for the current user. Defaults to NULL. * @param array $context * An array of key-value pairs to pass additional context when needed. */ - public function createAccess($entity_bundle = '', AccountInterface $account = NULL, $context = array()); + public function createAccess($entity_bundle = NULL, AccountInterface $account = NULL, $context = array()); /** * Clears all cached access checks. diff --git a/core/modules/node/lib/Drupal/node/NodeAccessController.php b/core/modules/node/lib/Drupal/node/NodeAccessController.php index e456029..8d976ee 100644 --- a/core/modules/node/lib/Drupal/node/NodeAccessController.php +++ b/core/modules/node/lib/Drupal/node/NodeAccessController.php @@ -32,15 +32,9 @@ public function access(EntityInterface $entity, $operation, $langcode = Language } /** - * @param string $entity_bundle - * The node type to check access for. - * @param \Drupal\Core\Session\AccountInterface $account - * (optional) The user session for which to check access, or NULL to check - * access for the current user. Defaults to NULL. - * @param array $context - * An array of key-value pairs to pass additional context when needed. + * {@inheritdoc} */ - public function createAccess($entity_bundle, AccountInterface $account = NULL, $context = array()) { + public function createAccess($entity_bundle = NULL, AccountInterface $account = NULL, $context = array()) { $account = $this->prepareUser($account); if (user_access('bypass node access', $account)) {