Issue #2340507 by chx, Wim Leers: Make the new AccessResult API and implementation even better.

8.0.x
Alex Pott 2014-09-22 22:08:27 +01:00
parent 9ff1ef3973
commit ff035fc4fa
48 changed files with 823 additions and 468 deletions

View File

@ -229,7 +229,7 @@ class AccessManager implements ContainerAwareInterface, AccessManagerInterface {
$checks = array_diff($checks, $this->checkNeedsRequest); $checks = array_diff($checks, $this->checkNeedsRequest);
} }
$result = AccessResult::create(); $result = AccessResult::neutral();
if (!empty($checks)) { if (!empty($checks)) {
$arguments_resolver = $this->argumentsResolverFactory->getArgumentsResolver($route_match, $account, $request); $arguments_resolver = $this->argumentsResolverFactory->getArgumentsResolver($route_match, $account, $request);
if ($conjunction == static::ACCESS_MODE_ALL) { if ($conjunction == static::ACCESS_MODE_ALL) {
@ -256,35 +256,19 @@ class AccessManager implements ContainerAwareInterface, AccessManagerInterface {
* @see \Drupal\Core\Access\AccessResultInterface::andIf() * @see \Drupal\Core\Access\AccessResultInterface::andIf()
*/ */
protected function checkAll(array $checks, ArgumentsResolverInterface $arguments_resolver) { protected function checkAll(array $checks, ArgumentsResolverInterface $arguments_resolver) {
$results = array(); // Without checks no opinion can be formed.
if (!$checks) {
return AccessResult::neutral();
}
$result = AccessResult::allowed();
foreach ($checks as $service_id) { foreach ($checks as $service_id) {
if (empty($this->checks[$service_id])) { if (empty($this->checks[$service_id])) {
$this->loadCheck($service_id); $this->loadCheck($service_id);
} }
$result = $result->andIf($this->performCheck($service_id, $arguments_resolver));
$result = $this->performCheck($service_id, $arguments_resolver);
$results[] = $result;
// Stop as soon as the first non-allowed check is encountered.
if (!$result->isAllowed()) {
break;
}
}
if (empty($results)) {
// No opinion.
return AccessResult::create();
}
else {
/** @var \Drupal\Core\Access\AccessResultInterface $result */
$result = array_shift($results);
foreach ($results as $other) {
$result->andIf($other);
} }
return $result; return $result;
} }
}
/** /**
* Checks access so that at least one checker should allow access. * Checks access so that at least one checker should allow access.
@ -301,7 +285,7 @@ class AccessManager implements ContainerAwareInterface, AccessManagerInterface {
*/ */
protected function checkAny(array $checks, ArgumentsResolverInterface $arguments_resolver) { protected function checkAny(array $checks, ArgumentsResolverInterface $arguments_resolver) {
// No opinion by default. // No opinion by default.
$result = AccessResult::create(); $result = AccessResult::neutral();
foreach ($checks as $service_id) { foreach ($checks as $service_id) {
if (empty($this->checks[$service_id])) { if (empty($this->checks[$service_id])) {

View File

@ -14,34 +14,18 @@ use Drupal\Core\Session\AccountInterface;
/** /**
* Value object for passing an access result with cacheability metadata. * Value object for passing an access result with cacheability metadata.
* *
* The access result itself excluding the cacheability metadata  is
* immutable. There are subclasses for each of the three possible access results
* themselves:
*
* @see \Drupal\Core\Access\AccessResultAllowed
* @see \Drupal\Core\Access\AccessResultForbidden
* @see \Drupal\Core\Access\AccessResultNeutral
*
* When using ::orIf() and ::andIf(), cacheability metadata will be merged * When using ::orIf() and ::andIf(), cacheability metadata will be merged
* accordingly as well. * accordingly as well.
*/ */
class AccessResult implements AccessResultInterface, CacheableInterface { abstract class AccessResult implements AccessResultInterface, CacheableInterface {
/**
* The value that explicitly allows access.
*/
const ALLOW = 'ALLOW';
/**
* The value that neither explicitly allows nor explicitly forbids access.
*/
const DENY = 'DENY';
/**
* The value that explicitly forbids access.
*/
const KILL = 'KILL';
/**
* The access result value.
*
* A \Drupal\Core\Access\AccessResultInterface constant value.
*
* @var string
*/
protected $value;
/** /**
* Whether the access result is cacheable. * Whether the access result is cacheable.
@ -78,7 +62,6 @@ class AccessResult implements AccessResultInterface, CacheableInterface {
* Constructs a new AccessResult object. * Constructs a new AccessResult object.
*/ */
public function __construct() { public function __construct() {
$this->resetAccess();
$this->setCacheable(TRUE) $this->setCacheable(TRUE)
->resetCacheContexts() ->resetCacheContexts()
->resetCacheTags() ->resetCacheTags()
@ -88,64 +71,67 @@ class AccessResult implements AccessResultInterface, CacheableInterface {
} }
/** /**
* Instantiates a new AccessResult object. * Creates an AccessResultInterface object with isNeutral() === TRUE.
*
* This factory method exists to improve DX; it allows developers to fluently
* create access results.
*
* Defaults to a cacheable access result that neither explicitly allows nor
* explicitly forbids access.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* isNeutral() will be TRUE.
*/ */
public static function create() { public static function neutral() {
return new static(); return new AccessResultNeutral();
} }
/** /**
* Convenience method, creates an AccessResult object and calls allow(). * Creates an AccessResultInterface object with isAllowed() === TRUE.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* isAllowed() will be TRUE.
*/ */
public static function allowed() { public static function allowed() {
return static::create()->allow(); return new AccessResultAllowed();
} }
/** /**
* Convenience method, creates an AccessResult object and calls forbid(). * Creates an AccessResultInterface object with isForbidden() === TRUE.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* isForbidden() will be TRUE.
*/ */
public static function forbidden() { public static function forbidden() {
return static::create()->forbid(); return new AccessResultForbidden();
} }
/** /**
* Convenience method, creates an AccessResult object and calls allowIf(). * Creates an allowed or neutral access result.
* *
* @param bool $condition * @param bool $condition
* The condition to evaluate. If TRUE, ::allow() will be called. * The condition to evaluate.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* If $condition is TRUE, isAllowed() will be TRUE, otherwise isNeutral()
* will be TRUE.
*/ */
public static function allowedIf($condition) { public static function allowedIf($condition) {
return static::create()->allowIf($condition); return $condition ? static::allowed() : static::neutral();
} }
/** /**
* Convenience method, creates an AccessResult object and calls forbiddenIf(). * Creates a forbidden or neutral access result.
* *
* @param bool $condition * @param bool $condition
* The condition to evaluate. If TRUE, ::forbid() will be called. * The condition to evaluate.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* If $condition is TRUE, isForbidden() will be TRUE, otherwise isNeutral()
* will be TRUE.
*/ */
public static function forbiddenIf($condition) { public static function forbiddenIf($condition) {
return static::create()->forbidIf($condition); return $condition ? static::forbidden(): static::neutral();
} }
/** /**
* Convenience method, creates an AccessResult object and calls allowIfHasPermission(). * Creates an allowed access result if the permission is present, neutral otherwise.
*
* Convenience method, checks the permission and calls ::cachePerRole().
* *
* @param \Drupal\Core\Session\AccountInterface $account * @param \Drupal\Core\Session\AccountInterface $account
* The account for which to check a permission. * The account for which to check a permission.
@ -153,83 +139,38 @@ class AccessResult implements AccessResultInterface, CacheableInterface {
* The permission to check for. * The permission to check for.
* *
* @return \Drupal\Core\Access\AccessResult * @return \Drupal\Core\Access\AccessResult
* If the account has the permission, isAlowed() will be TRUE, otherwise
* isNeutral() will be TRUE.
*/ */
public static function allowedIfHasPermission(AccountInterface $account, $permission) { public static function allowedIfHasPermission(AccountInterface $account, $permission) {
return static::create()->allowIfHasPermission($account, $permission); return static::allowedIf($account->hasPermission($permission))->cachePerRole();
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @see \Drupal\Core\Access\AccessResultAllowed
*/ */
public function isAllowed() { public function isAllowed() {
return $this->value === static::ALLOW; return FALSE;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*
* @see \Drupal\Core\Access\AccessResultForbidden
*/ */
public function isForbidden() { public function isForbidden() {
return $this->value === static::KILL; return FALSE;
} }
/** /**
* Explicitly allows access. * {@inheritdoc}
* *
* @return $this * @see \Drupal\Core\Access\AccessResultNeutral
*/ */
public function allow() { public function isNeutral() {
$this->value = static::ALLOW; return FALSE;
return $this;
}
/**
* Explicitly forbids access.
*
* @return $this
*/
public function forbid() {
$this->value = static::KILL;
return $this;
}
/**
* Neither explicitly allows nor explicitly forbids access.
*
* @return $this
*/
public function resetAccess() {
$this->value = static::DENY;
return $this;
}
/**
* Conditionally calls ::allow().
*
* @param bool $condition
* The condition to evaluate. If TRUE, ::allow() will be called.
*
* @return $this
*/
public function allowIf($condition) {
if ($condition) {
$this->allow();
}
return $this;
}
/**
* Conditionally calls ::forbid().
*
* @param bool $condition
* The condition to evaluate. If TRUE, ::forbid() will be called.
*
* @return $this
*/
public function forbidIf($condition) {
if ($condition) {
$this->forbid();
}
return $this;
} }
/** /**
@ -391,77 +332,89 @@ class AccessResult implements AccessResultInterface, CacheableInterface {
return $this; return $this;
} }
/**
* Convenience method, checks permission and calls ::cachePerRole().
*
* @param \Drupal\Core\Session\AccountInterface $account
* The account for which to check a permission.
* @param string $permission
* The permission to check for.
*
* @return $this
*/
public function allowIfHasPermission(AccountInterface $account, $permission) {
$this->allowIf($account->hasPermission($permission))->cachePerRole();
return $this;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function orIf(AccessResultInterface $other) { public function orIf(AccessResultInterface $other) {
// If this AccessResult already is forbidden, then that already is the // $other's cacheability metadata is merged if $merge_other gets set to TRUE
// conclusion. We can completely disregard $other. // and this happens in two cases:
if ($this->isForbidden()) { // 1. $other's access result is the one that determines the combined access
return $this; // result.
// 2. This access result is not cacheable and $other's access result is the
// same. i.e. attempt to return a cacheable access result.
$merge_other = FALSE;
if ($this->isForbidden() || $other->isForbidden()) {
$result = static::forbidden();
if (!$this->isForbidden() || (!$this->isCacheable() && $other->isForbidden())) {
$merge_other = TRUE;
}
}
elseif ($this->isAllowed() || $other->isAllowed()) {
$result = static::allowed();
if (!$this->isAllowed() || (!$this->isCacheable() && $other->isAllowed())) {
$merge_other = TRUE;
}
} }
// Otherwise, we make this AccessResult forbidden if the other is, or
// allowed if the other is, and we merge in the cacheability metadata if the
// other access result also has cacheability metadata.
else { else {
if ($other->isForbidden()) { $result = static::neutral();
$this->forbid(); if (!$this->isNeutral() || (!$this->isCacheable() && $other->isNeutral())) {
$merge_other = TRUE;
} }
else if ($other->isAllowed()) {
$this->allow();
} }
$this->mergeCacheabilityMetadata($other); $result->inheritCacheability($this);
return $this; if ($merge_other) {
$result->inheritCacheability($other);
} }
return $result;
} }
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */
public function andIf(AccessResultInterface $other) { public function andIf(AccessResultInterface $other) {
// If this AccessResult already is forbidden or is merely not explicitly // The other access result's cacheability metadata is merged if $merge_other
// allowed, then that already is the conclusion. We can completely disregard // gets set to TRUE. It gets set to TRUE in one case: if the other access
// $other. // result is used.
if ($this->isForbidden() || !$this->isAllowed()) { $merge_other = FALSE;
return $this; if ($this->isForbidden() || $other->isForbidden()) {
$result = static::forbidden();
if (!$this->isForbidden()) {
$merge_other = TRUE;
}
}
elseif ($this->isAllowed() && $other->isAllowed()) {
$result = static::allowed();
$merge_other = TRUE;
} }
// Otherwise, we make this AccessResult forbidden if the other is, or not
// explicitly allowed if the other isn't, and we merge in the cacheability
// metadata if the other access result also has cacheability metadata.
else { else {
if ($other->isForbidden()) { $result = static::neutral();
$this->forbid(); if (!$this->isNeutral()) {
$merge_other = TRUE;
} }
else if (!$other->isAllowed()) {
$this->resetAccess();
} }
$this->mergeCacheabilityMetadata($other); $result->inheritCacheability($this);
return $this; if ($merge_other) {
$result->inheritCacheability($other);
// If this access result is not cacheable, then an AND with another access
// result must also not be cacheable, except if the other access result
// has isForbidden() === TRUE. isForbidden() access results are contagious
// in that they propagate regardless of the other value.
if (!$this->isCacheable() && !$result->isForbidden()) {
$result->setCacheable(FALSE);
} }
} }
return $result;
}
/** /**
* Merges the cacheability metadata of the other access result, if any. * Inherits the cacheability of the other access result, if any.
* *
* @param \Drupal\Core\Access\AccessResultInterface $other * @param \Drupal\Core\Access\AccessResultInterface $other
* The other access result, whose cacheability data (if any) to merge. * The other access result, whose cacheability (if any) to inherit.
*
* @return $this
*/ */
protected function mergeCacheabilityMetadata(AccessResultInterface $other) { public function inheritCacheability(AccessResultInterface $other) {
if ($other instanceof CacheableInterface) { if ($other instanceof CacheableInterface) {
$this->setCacheable($other->isCacheable()); $this->setCacheable($other->isCacheable());
$this->addCacheContexts($other->getCacheKeys()); $this->addCacheContexts($other->getCacheKeys());
@ -481,6 +434,7 @@ class AccessResult implements AccessResultInterface, CacheableInterface {
else { else {
$this->setCacheable(FALSE); $this->setCacheable(FALSE);
} }
return $this;
} }
} }

View File

@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains \Drupal\Core\Access\AccessResultAllowed.
*/
namespace Drupal\Core\Access;
/**
* Value object indicating an allowed access result, with cacheability metadata.
*/
class AccessResultAllowed extends AccessResult {
/**
* {@inheritdoc}
*/
public function isAllowed() {
return TRUE;
}
}

View File

@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains \Drupal\Core\Access\AccessResultForbidden.
*/
namespace Drupal\Core\Access;
/**
* Value object indicating a forbidden access result, with cacheability metadata.
*/
class AccessResultForbidden extends AccessResult {
/**
* {@inheritdoc}
*/
public function isForbidden() {
return TRUE;
}
}

View File

@ -23,12 +23,10 @@ namespace Drupal\Core\Access;
* would never enter the else-statement and hence introduce a critical security * would never enter the else-statement and hence introduce a critical security
* issue. * issue.
* *
* Note: you can check whether access is neither explicitly allowed nor * Objects implementing this interface are using Kleene's weak three-valued
* explicitly forbidden: * logic with the isAllowed() state being TRUE, the isForbidden() state being
* * the intermediate truth value and isNeutral() being FALSE. See
* @code * http://en.wikipedia.org/wiki/Many-valued_logic for more.
* $no_opinion = !$access->isAllowed() && !$access->isForbidden();
* @endcode
*/ */
interface AccessResultInterface { interface AccessResultInterface {
@ -36,43 +34,56 @@ interface AccessResultInterface {
* Checks whether this access result indicates access is explicitly allowed. * Checks whether this access result indicates access is explicitly allowed.
* *
* @return bool * @return bool
* When TRUE then isForbidden() and isNeutral() are FALSE.
*/ */
public function isAllowed(); public function isAllowed();
/** /**
* Checks whether this access result indicates access is explicitly forbidden. * Checks whether this access result indicates access is explicitly forbidden.
* *
* This is a kill switch both orIf() and andIf() will result in
* isForbidden() if either results are isForbidden().
*
* @return bool * @return bool
* When TRUE then isAllowed() and isNeutral() are FALSE.
*/ */
public function isForbidden(); public function isForbidden();
/**
* Checks whether this access result indicates access is not yet determined.
*
* @return bool
* When TRUE then isAllowed() and isForbidden() are FALSE.
*/
public function isNeutral();
/** /**
* Combine this access result with another using OR. * Combine this access result with another using OR.
* *
* When OR-ing two access results, the result is: * When OR-ing two access results, the result is:
* - isForbidden() in either isForbidden() * - isForbidden() in either isForbidden()
* - isAllowed() in either isAllowed() * - otherwise if isAllowed() in either isAllowed()
* - neither isForbidden() nor isAllowed() => !isAllowed() && !isForbidden() * - otherwise both must be isNeutral() isNeutral()
* *
* @param \Drupal\Core\Access\AccessResultInterface $other * @param \Drupal\Core\Access\AccessResultInterface $other
* The other access result to OR this one with. * The other access result to OR this one with.
* *
* @return $this * @return static
*/ */
public function orIf(AccessResultInterface $other); public function orIf(AccessResultInterface $other);
/** /**
* Combine this access result with another using AND. * Combine this access result with another using AND.
* *
* When OR-ing two access results, the result is: * When AND-ing two access results, the result is:
* - isForbidden() in either isForbidden() * - isForbidden() in either isForbidden()
* - isAllowed() in both isAllowed() * - otherwise, if isAllowed() in both isAllowed()
* - neither isForbidden() nor isAllowed() => !isAllowed() && !isForbidden() * - otherwise, one of them is isNeutral() isNeutral()
* *
* @param \Drupal\Core\Access\AccessResultInterface $other * @param \Drupal\Core\Access\AccessResultInterface $other
* The other access result to AND this one with. * The other access result to AND this one with.
* *
* @return $this * @return static
*/ */
public function andIf(AccessResultInterface $other); public function andIf(AccessResultInterface $other);

View File

@ -0,0 +1,22 @@
<?php
/**
* @file
* Contains \Drupal\Core\Access\AccessResultNeutral.
*/
namespace Drupal\Core\Access;
/**
* Value object indicating a neutral access result, with cacheability metadata.
*/
class AccessResultNeutral extends AccessResult {
/**
* {@inheritdoc}
*/
public function isNeutral() {
return TRUE;
}
}

View File

@ -49,17 +49,16 @@ class CsrfAccessCheck implements RoutingAccessInterface {
* The access result. * The access result.
*/ */
public function access(Route $route, Request $request) { public function access(Route $route, Request $request) {
// Not cacheable because the CSRF token is highly dynamic.
$access = AccessResult::create()->setCacheable(FALSE);
// @todo Remove dependency on the internal _system_path attribute: // @todo Remove dependency on the internal _system_path attribute:
// https://www.drupal.org/node/2293501. // https://www.drupal.org/node/2293501.
if ($this->csrfToken->validate($request->query->get('token'), $request->attributes->get('_system_path'))) { if ($this->csrfToken->validate($request->query->get('token'), $request->attributes->get('_system_path'))) {
$access->allow(); $result = AccessResult::allowed();
} }
else { else {
$access->forbid(); $result = AccessResult::forbidden();
} }
return $access; // Not cacheable because the CSRF token is highly dynamic.
return $result->setCacheable(FALSE);
} }
} }

View File

@ -32,7 +32,7 @@ class DefaultAccessCheck implements RoutingAccessInterface {
return AccessResult::forbidden(); return AccessResult::forbidden();
} }
else { else {
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -170,18 +170,13 @@ abstract class BlockBase extends ContextAwarePluginBase implements BlockPluginIn
// in order to fix that, we need condition plugins to return cache contexts, // in order to fix that, we need condition plugins to return cache contexts,
// otherwise it will be impossible to determine by which cache contexts the // otherwise it will be impossible to determine by which cache contexts the
// result should be varied. // result should be varied.
$access = AccessResult::create()->setCacheable(FALSE); if ($this->resolveConditions($conditions, 'and', $contexts, $mappings) !== FALSE && $this->blockAccess($account)) {
if ($this->resolveConditions($conditions, 'and', $contexts, $mappings) === FALSE) { $access = AccessResult::allowed();
$access->forbid();
return $access;
}
if ($this->blockAccess($account)) {
$access->allow();
} }
else { else {
$access->forbid(); $access = AccessResult::forbidden();
} }
return $access; return $access->setCacheable(FALSE);
} }
/** /**

View File

@ -55,7 +55,7 @@ class EntityAccessCheck implements AccessInterface {
} }
// No opinion, so other access checks should decide if access should be // No opinion, so other access checks should decide if access should be
// allowed or not. // allowed or not.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -76,10 +76,10 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
); );
$return = $this->processAccessHookResults($access); $return = $this->processAccessHookResults($access);
if (!$return->isAllowed() && !$return->isForbidden()) { if ($return->isNeutral()) {
// No module had an opinion about the access, so let's the access // No module had an opinion about the access, so let's the access
// handler check access. // handler check access.
$return->orIf($this->checkAccess($entity, $operation, $langcode, $account)); $return = $return->orIf($this->checkAccess($entity, $operation, $langcode, $account));
} }
$result = $this->setCache($return, $entity->uuid(), $operation, $langcode, $account); $result = $this->setCache($return, $entity->uuid(), $operation, $langcode, $account);
return $return_as_object ? $result : $result->isAllowed(); return $return_as_object ? $result : $result->isAllowed();
@ -102,7 +102,7 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
protected function processAccessHookResults(array $access) { protected function processAccessHookResults(array $access) {
// No results means no opinion. // No results means no opinion.
if (empty($access)) { if (empty($access)) {
return AccessResult::create(); return AccessResult::neutral();
} }
/** @var \Drupal\Core\Access\AccessResultInterface $result */ /** @var \Drupal\Core\Access\AccessResultInterface $result */
@ -141,7 +141,7 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
} }
else { else {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }
@ -231,10 +231,10 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
); );
$return = $this->processAccessHookResults($access); $return = $this->processAccessHookResults($access);
if (!$return->isAllowed() && !$return->isForbidden()) { if ($return->isNeutral()) {
// No module had an opinion about the access, so let's the access // No module had an opinion about the access, so let's the access
// handler check create access. // handler check create access.
$return->orIf($this->checkCreateAccess($account, $context, $entity_bundle)); $return = $return->orIf($this->checkCreateAccess($account, $context, $entity_bundle));
} }
$result = $this->setCache($return, $cid, 'create', $context['langcode'], $account); $result = $this->setCache($return, $cid, 'create', $context['langcode'], $account);
return $return_as_object ? $result : $result->isAllowed(); return $return_as_object ? $result : $result->isAllowed();
@ -263,7 +263,7 @@ class EntityAccessControlHandler extends EntityHandlerBase implements EntityAcce
} }
else { else {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -67,7 +67,7 @@ class EntityCreateAccessCheck implements AccessInterface {
} }
// If we were unable to replace all placeholders, deny access. // If we were unable to replace all placeholders, deny access.
if (strpos($bundle, '{') !== FALSE) { if (strpos($bundle, '{') !== FALSE) {
return AccessResult::create(); return AccessResult::neutral();
} }
} }
return $this->entityManager->getAccessControlHandler($entity_type)->createAccess($bundle, $account, [], TRUE); return $this->entityManager->getAccessControlHandler($entity_type)->createAccess($bundle, $account, [], TRUE);

View File

@ -159,7 +159,7 @@ function hook_block_access(\Drupal\block\Entity\Block $block, $operation, \Drupa
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**

View File

@ -42,7 +42,7 @@ class CommentAccessControlHandler extends EntityAccessControlHandler {
default: default:
// No opinion. // No opinion.
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
} }

View File

@ -71,9 +71,10 @@ class ContactPageAccess implements AccessInterface {
} }
// User administrators should always have access to personal contact forms. // User administrators should always have access to personal contact forms.
$access = AccessResult::create()->cachePerRole(); $access = AccessResult::neutral()->cachePerRole();
if ($account->hasPermission('administer users')) { $permission_access = AccessResult::allowedIfHasPermission($account, 'administer users');
return $access->allow(); if ($permission_access->isAllowed()) {
return $access->orIf($permission_access);
} }
// If requested user has been blocked, do not allow users to contact them. // If requested user has been blocked, do not allow users to contact them.
@ -94,7 +95,7 @@ class ContactPageAccess implements AccessInterface {
return $access; return $access;
} }
return $access->allowIfHasPermission($account, 'access user contact forms'); return $access->orIf(AccessResult::allowedIfHasPermission($account, 'access user contact forms'));
} }
} }

View File

@ -106,7 +106,7 @@ class ContentTranslationManageAccessCheck implements AccessInterface {
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -66,7 +66,7 @@ class ContentTranslationOverviewAccess implements AccessInterface {
// Check "translate any entity" permission. // Check "translate any entity" permission.
if ($account->hasPermission('translate any entity')) { if ($account->hasPermission('translate any entity')) {
return $access->allow()->cachePerRole(); return AccessResult::allowed()->cachePerRole()->inheritCacheability($access);
} }
// Check per entity permission. // Check per entity permission.
@ -74,10 +74,10 @@ class ContentTranslationOverviewAccess implements AccessInterface {
if ($definition->getPermissionGranularity() == 'bundle') { if ($definition->getPermissionGranularity() == 'bundle') {
$permission = "translate {$bundle} {$entity_type_id}"; $permission = "translate {$bundle} {$entity_type_id}";
} }
return $access->allowIfHasPermission($account, $permission); return AccessResult::allowedIfHasPermission($account, $permission)->inheritCacheability($access);
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -62,6 +62,7 @@ class FormModeAccessCheck implements AccessInterface {
* The access result. * The access result.
*/ */
public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $form_mode_name = 'default', $bundle = NULL) { public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $form_mode_name = 'default', $bundle = NULL) {
$access = AccessResult::neutral();
if ($entity_type_id = $route->getDefault('entity_type_id')) { if ($entity_type_id = $route->getDefault('entity_type_id')) {
if (!isset($bundle)) { if (!isset($bundle)) {
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityManager->getDefinition($entity_type_id);
@ -76,21 +77,16 @@ class FormModeAccessCheck implements AccessInterface {
$visibility = $entity_display->status(); $visibility = $entity_display->status();
} }
$access = AccessResult::create();
if ($form_mode_name != 'default' && $entity_display) { if ($form_mode_name != 'default' && $entity_display) {
$access->cacheUntilEntityChanges($entity_display); $access->cacheUntilEntityChanges($entity_display);
} }
if ($visibility) { if ($visibility) {
$permission = $route->getRequirement('_field_ui_form_mode_access'); $permission = $route->getRequirement('_field_ui_form_mode_access');
$access->allowIfHasPermission($account, $permission); $access = $access->orIf(AccessResult::allowedIfHasPermission($account, $permission));
}
} }
return $access; return $access;
} }
else {
// No opinion.
return AccessResult::create();
}
}
} }

View File

@ -62,6 +62,7 @@ class ViewModeAccessCheck implements AccessInterface {
* The access result. * The access result.
*/ */
public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $view_mode_name = 'default', $bundle = NULL) { public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account, $view_mode_name = 'default', $bundle = NULL) {
$access = AccessResult::neutral();
if ($entity_type_id = $route->getDefault('entity_type_id')) { if ($entity_type_id = $route->getDefault('entity_type_id')) {
if (!isset($bundle)) { if (!isset($bundle)) {
$entity_type = $this->entityManager->getDefinition($entity_type_id); $entity_type = $this->entityManager->getDefinition($entity_type_id);
@ -76,21 +77,16 @@ class ViewModeAccessCheck implements AccessInterface {
$visibility = $entity_display->status(); $visibility = $entity_display->status();
} }
$access = AccessResult::create();
if ($view_mode_name != 'default' && $entity_display) { if ($view_mode_name != 'default' && $entity_display) {
$access->cacheUntilEntityChanges($entity_display); $access->cacheUntilEntityChanges($entity_display);
} }
if ($visibility) { if ($visibility) {
$permission = $route->getRequirement('_field_ui_view_mode_access'); $permission = $route->getRequirement('_field_ui_view_mode_access');
$access->allowIfHasPermission($account, $permission); $access = $access->orIf(AccessResult::allowedIfHasPermission($account, $permission));
}
} }
return $access; return $access;
} }
else {
// No opinion.
return AccessResult::create();
}
}
} }

View File

@ -38,7 +38,7 @@ class FileAccessControlHandler extends EntityAccessControlHandler {
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**

View File

@ -51,7 +51,7 @@ class FilterFormatAccessControlHandler extends EntityAccessControlHandler {
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -125,7 +125,7 @@ class FilterFormatAccessTest extends WebTestBase {
$this->assertTrue($this->allowed_format->access('use', $this->web_user), 'A regular user has access to use a text format they were granted access to.'); $this->assertTrue($this->allowed_format->access('use', $this->web_user), 'A regular user has access to use a text format they were granted access to.');
$this->assertEqual(AccessResult::allowed()->cachePerRole(), $this->allowed_format->access('use', $this->web_user, TRUE), 'A regular user has access to use a text format they were granted access to.'); $this->assertEqual(AccessResult::allowed()->cachePerRole(), $this->allowed_format->access('use', $this->web_user, TRUE), 'A regular user has access to use a text format they were granted access to.');
$this->assertFalse($this->disallowed_format->access('use', $this->web_user), 'A regular user does not have access to use a text format they were not granted access to.'); $this->assertFalse($this->disallowed_format->access('use', $this->web_user), 'A regular user does not have access to use a text format they were not granted access to.');
$this->assertEqual(AccessResult::create()->cachePerRole(), $this->disallowed_format->access('use', $this->web_user, TRUE), 'A regular user does not have access to use a text format they were not granted access to.'); $this->assertEqual(AccessResult::neutral(), $this->disallowed_format->access('use', $this->web_user, TRUE)); //, 'A regular user does not have access to use a text format they were not granted access to.');
$this->assertTrue($fallback_format->access('use', $this->web_user), 'A regular user has access to use the fallback format.'); $this->assertTrue($fallback_format->access('use', $this->web_user), 'A regular user has access to use the fallback format.');
$this->assertEqual(AccessResult::allowed(), $fallback_format->access('use', $this->web_user, TRUE), 'A regular user has access to use the fallback format.'); $this->assertEqual(AccessResult::allowed(), $fallback_format->access('use', $this->web_user, TRUE), 'A regular user has access to use the fallback format.');

View File

@ -31,7 +31,7 @@ class LanguageAccessControlHandler extends EntityAccessControlHandler {
default: default:
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -55,23 +55,21 @@ class MenuLinkContentAccessControlHandler extends EntityAccessControlHandler imp
switch ($operation) { switch ($operation) {
case 'view': case 'view':
// There is no direct view. // There is no direct view.
return AccessResult::create(); return AccessResult::neutral();
case 'update': case 'update':
if (!$account->hasPermission('administer menu')) { if (!$account->hasPermission('administer menu')) {
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
else { else {
$access = AccessResult::create()->cachePerRole()->cacheUntilEntityChanges($entity);
// If there is a URL, this is an external link so always accessible. // If there is a URL, this is an external link so always accessible.
if ($entity->getUrl()) { $access = AccessResult::allowed()->cachePerRole()->cacheUntilEntityChanges($entity);
return $access->allow(); if (!$entity->getUrl()) {
}
else {
// We allow access, but only if the link is accessible as well. // We allow access, but only if the link is accessible as well.
$link_access = $this->accessManager->checkNamedRoute($entity->getRouteName(), $entity->getRouteParameters(), $account, TRUE); $link_access = $this->accessManager->checkNamedRoute($entity->getRouteName(), $entity->getRouteParameters(), $account, TRUE);
return $access->allow()->andIf($link_access); return $access->andIf($link_access);
} }
return $access;
} }
case 'delete': case 'delete':

View File

@ -348,7 +348,7 @@ function hook_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Se
default: default:
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -1042,7 +1042,7 @@ function node_node_access(NodeInterface $node, $op, $account) {
default: default:
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -61,7 +61,7 @@ class NodeAddAccessCheck implements AccessInterface {
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -123,7 +123,7 @@ class NodeAccessControlHandler extends EntityAccessControlHandler implements Nod
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**

View File

@ -59,7 +59,7 @@ class NodeGrantDatabaseStorage implements NodeGrantDatabaseStorageInterface {
// no point in querying the database for access grants. // no point in querying the database for access grants.
if (!$this->moduleHandler->getImplementations('node_grants') || !$node->id()) { if (!$this->moduleHandler->getImplementations('node_grants') || !$node->id()) {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
// Check the database for potential access grants. // Check the database for potential access grants.

View File

@ -151,5 +151,5 @@ function node_access_test_node_access(\Drupal\node\NodeInterface $node, $op, \Dr
return AccessResult::forbidden()->setCacheable(FALSE); return AccessResult::forbidden()->setCacheable(FALSE);
} }
// No opinion. // No opinion.
return AccessResult::create()->setCacheable(FALSE); return AccessResult::neutral()->setCacheable(FALSE);
} }

View File

@ -49,7 +49,7 @@ class EditEntityFieldAccessCheckTest extends UnitTestCase {
$non_editable_entity = $this->createMockEntity(); $non_editable_entity = $this->createMockEntity();
$non_editable_entity->expects($this->any()) $non_editable_entity->expects($this->any())
->method('access') ->method('access')
->will($this->returnValue(AccessResult::create()->cachePerRole())); ->will($this->returnValue(AccessResult::neutral()->cachePerRole()));
$field_storage_with_access = $this->getMockBuilder('Drupal\field\Entity\FieldStorageConfig') $field_storage_with_access = $this->getMockBuilder('Drupal\field\Entity\FieldStorageConfig')
->disableOriginalConstructor() ->disableOriginalConstructor()
@ -62,13 +62,13 @@ class EditEntityFieldAccessCheckTest extends UnitTestCase {
->getMock(); ->getMock();
$field_storage_without_access->expects($this->any()) $field_storage_without_access->expects($this->any())
->method('access') ->method('access')
->will($this->returnValue(AccessResult::create())); ->will($this->returnValue(AccessResult::neutral()));
$data = array(); $data = array();
$data[] = array($editable_entity, $field_storage_with_access, AccessResult::allowed()->cachePerRole()); $data[] = array($editable_entity, $field_storage_with_access, AccessResult::allowed()->cachePerRole());
$data[] = array($non_editable_entity, $field_storage_with_access, AccessResult::create()->cachePerRole()); $data[] = array($non_editable_entity, $field_storage_with_access, AccessResult::neutral()->cachePerRole());
$data[] = array($editable_entity, $field_storage_without_access, AccessResult::create()->cachePerRole()); $data[] = array($editable_entity, $field_storage_without_access, AccessResult::neutral()->cachePerRole());
$data[] = array($non_editable_entity, $field_storage_without_access, AccessResult::create()->cachePerRole()); $data[] = array($non_editable_entity, $field_storage_without_access, AccessResult::neutral()->cachePerRole());
return $data; return $data;
} }

View File

@ -90,12 +90,12 @@ function shortcut_set_switch_access($account = NULL) {
if (!$user->hasPermission('access shortcuts')) { if (!$user->hasPermission('access shortcuts')) {
// The user has no permission to use shortcuts. // The user has no permission to use shortcuts.
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
if (!$user->hasPermission('switch shortcut sets')) { if (!$user->hasPermission('switch shortcut sets')) {
// The user has no permission to switch anyone's shortcut set. // The user has no permission to switch anyone's shortcut set.
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
// Users with the 'switch shortcut sets' permission can switch their own // Users with the 'switch shortcut sets' permission can switch their own
@ -108,7 +108,7 @@ function shortcut_set_switch_access($account = NULL) {
} }
// No opinion. // No opinion.
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
/** /**

View File

@ -61,7 +61,7 @@ class ShortcutAccessControlHandler extends EntityAccessControlHandler implements
} }
// @todo Fix this bizarre code: how can a shortcut exist without a shortcut // @todo Fix this bizarre code: how can a shortcut exist without a shortcut
// set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903. // set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903.
return AccessResult::create()->cacheUntilEntityChanges($entity); return AccessResult::neutral()->cacheUntilEntityChanges($entity);
} }
/** /**
@ -73,7 +73,7 @@ class ShortcutAccessControlHandler extends EntityAccessControlHandler implements
} }
// @todo Fix this bizarre code: how can a shortcut exist without a shortcut // @todo Fix this bizarre code: how can a shortcut exist without a shortcut
// set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903. // set? The above if-test is unnecessary. See https://www.drupal.org/node/2339903.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -29,7 +29,7 @@ class ShortcutSetAccessControlHandler extends EntityAccessControlHandler {
return AccessResult::allowed()->cachePerRole(); return AccessResult::allowed()->cachePerRole();
} }
if (!$account->hasPermission('access shortcuts')) { if (!$account->hasPermission('access shortcuts')) {
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
return AccessResult::allowedIf($account->hasPermission('customize shortcut links') && $entity == shortcut_current_displayed_set($account))->cachePerRole()->cacheUntilEntityChanges($entity); return AccessResult::allowedIf($account->hasPermission('customize shortcut links') && $entity == shortcut_current_displayed_set($account))->cachePerRole()->cacheUntilEntityChanges($entity);
@ -38,7 +38,7 @@ class ShortcutSetAccessControlHandler extends EntityAccessControlHandler {
default: default:
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -532,7 +532,7 @@ use Drupal\Core\Render\Element;
*/ */
function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) { function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -558,7 +558,7 @@ function hook_entity_access(\Drupal\Core\Entity\EntityInterface $entity, $operat
*/ */
function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) { function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $operation, \Drupal\Core\Session\AccountInterface $account, $langcode) {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -584,7 +584,7 @@ function hook_ENTITY_TYPE_access(\Drupal\Core\Entity\EntityInterface $entity, $o
*/ */
function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) { function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -610,7 +610,7 @@ function hook_entity_create_access(\Drupal\Core\Session\AccountInterface $accoun
*/ */
function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) { function hook_ENTITY_TYPE_create_access(\Drupal\Core\Session\AccountInterface $account, array $context, $entity_bundle) {
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -1868,7 +1868,7 @@ function hook_entity_field_access_alter(array &$grants, array $context) {
// don't want to switch node module's grant to // don't want to switch node module's grant to
// AccessResultInterface::isAllowed() , because the grants of other modules // AccessResultInterface::isAllowed() , because the grants of other modules
// should still decide on their own if this field is accessible or not // should still decide on their own if this field is accessible or not
$grants['node']->resetAccess(); $grants['node'] = AccessResult::neutral()->inheritCacheability($grants['node']);
} }
} }

View File

@ -331,7 +331,7 @@ function entity_test_entity_field_access($operation, FieldDefinitionInterface $f
} }
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -341,7 +341,7 @@ function entity_test_entity_field_access($operation, FieldDefinitionInterface $f
*/ */
function entity_test_entity_field_access_alter(array &$grants, array $context) { function entity_test_entity_field_access_alter(array &$grants, array $context) {
if ($context['field_definition']->getName() == 'field_test_text' && $context['items'][0]->value == 'access alter value') { if ($context['field_definition']->getName() == 'field_test_text' && $context['items'][0]->value == 'access alter value') {
$grants[':default']->forbid()->cacheUntilEntityChanges($context['items']->getEntity()); $grants[':default'] = AccessResult::forbidden()->inheritCacheability($grants[':default'])->cacheUntilEntityChanges($context['items']->getEntity());
} }
} }
@ -488,7 +488,7 @@ function entity_test_entity_test_access(EntityInterface $entity, $operation, Acc
\Drupal::state()->set('entity_test_entity_test_access', TRUE); \Drupal::state()->set('entity_test_entity_test_access', TRUE);
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -498,7 +498,7 @@ function entity_test_entity_create_access(AccountInterface $account, $context, $
\Drupal::state()->set('entity_test_entity_create_access', TRUE); \Drupal::state()->set('entity_test_entity_create_access', TRUE);
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
/** /**
@ -508,5 +508,5 @@ function entity_test_entity_test_create_access(AccountInterface $account, $conte
\Drupal::state()->set('entity_test_entity_test_create_access', TRUE); \Drupal::state()->set('entity_test_entity_test_create_access', TRUE);
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }

View File

@ -41,7 +41,7 @@ class EntityTestAccessControlHandler extends EntityAccessControlHandler {
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }

View File

@ -33,7 +33,7 @@ class DefinedTestAccessCheck implements AccessInterface {
return AccessResult::forbidden(); return AccessResult::forbidden();
} }
else { else {
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -24,6 +24,6 @@ class TestAccessCheck implements AccessInterface {
public function access() { public function access() {
// No opinion, so other access checks should decide if access should be // No opinion, so other access checks should decide if access should be
// allowed or not. // allowed or not.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -38,7 +38,7 @@ class TermAccessControlHandler extends EntityAccessControlHandler {
default: default:
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -52,7 +52,7 @@ class RoleAccessCheck implements AccessInterface {
} }
// If there is no allowed role, give other access checks a chance. // If there is no allowed role, give other access checks a chance.
return AccessResult::create()->cachePerRole(); return AccessResult::neutral()->cachePerRole();
} }
} }

View File

@ -57,7 +57,7 @@ class UserAccessControlHandler extends EntityAccessControlHandler {
} }
// No opinion. // No opinion.
return AccessResult::create(); return AccessResult::neutral();
} }
} }

View File

@ -186,7 +186,7 @@ class AccessManagerTest extends UnitTestCase {
// Check route access without any access checker defined yet. // Check route access without any access checker defined yet.
foreach ($route_matches as $route_match) { foreach ($route_matches as $route_match) {
$this->assertEquals(FALSE, $this->accessManager->check($route_match, $this->account)); $this->assertEquals(FALSE, $this->accessManager->check($route_match, $this->account));
$this->assertEquals(AccessResult::create(), $this->accessManager->check($route_match, $this->account, NULL, TRUE)); $this->assertEquals(AccessResult::neutral(), $this->accessManager->check($route_match, $this->account, NULL, TRUE));
} }
$this->setupAccessChecker(); $this->setupAccessChecker();
@ -195,7 +195,7 @@ class AccessManagerTest extends UnitTestCase {
// setChecks. // setChecks.
foreach ($route_matches as $route_match) { foreach ($route_matches as $route_match) {
$this->assertEquals(FALSE, $this->accessManager->check($route_match, $this->account)); $this->assertEquals(FALSE, $this->accessManager->check($route_match, $this->account));
$this->assertEquals(AccessResult::create(), $this->accessManager->check($route_match, $this->account, NULL, TRUE)); $this->assertEquals(AccessResult::neutral(), $this->accessManager->check($route_match, $this->account, NULL, TRUE));
} }
// Now applicable access checks have been saved on each route object. // Now applicable access checks have been saved on each route object.
@ -206,7 +206,7 @@ class AccessManagerTest extends UnitTestCase {
$this->assertEquals(TRUE, $this->accessManager->check($route_matches['test_route_2'], $this->account)); $this->assertEquals(TRUE, $this->accessManager->check($route_matches['test_route_2'], $this->account));
$this->assertEquals(FALSE, $this->accessManager->check($route_matches['test_route_3'], $this->account)); $this->assertEquals(FALSE, $this->accessManager->check($route_matches['test_route_3'], $this->account));
$this->assertEquals(TRUE, $this->accessManager->check($route_matches['test_route_4'], $this->account)); $this->assertEquals(TRUE, $this->accessManager->check($route_matches['test_route_4'], $this->account));
$this->assertEquals(AccessResult::create(), $this->accessManager->check($route_matches['test_route_1'], $this->account, NULL, TRUE)); $this->assertEquals(AccessResult::neutral(), $this->accessManager->check($route_matches['test_route_1'], $this->account, NULL, TRUE));
$this->assertEquals(AccessResult::allowed(), $this->accessManager->check($route_matches['test_route_2'], $this->account, NULL, TRUE)); $this->assertEquals(AccessResult::allowed(), $this->accessManager->check($route_matches['test_route_2'], $this->account, NULL, TRUE));
$this->assertEquals(AccessResult::forbidden(), $this->accessManager->check($route_matches['test_route_3'], $this->account, NULL, TRUE)); $this->assertEquals(AccessResult::forbidden(), $this->accessManager->check($route_matches['test_route_3'], $this->account, NULL, TRUE));
$this->assertEquals(AccessResult::allowed(), $this->accessManager->check($route_matches['test_route_4'], $this->account, NULL, TRUE)); $this->assertEquals(AccessResult::allowed(), $this->accessManager->check($route_matches['test_route_4'], $this->account, NULL, TRUE));
@ -242,7 +242,7 @@ class AccessManagerTest extends UnitTestCase {
*/ */
public function providerTestCheckConjunctions() { public function providerTestCheckConjunctions() {
$access_allow = AccessResult::allowed(); $access_allow = AccessResult::allowed();
$access_deny = AccessResult::create(); $access_deny = AccessResult::neutral();
$access_kill = AccessResult::forbidden(); $access_kill = AccessResult::forbidden();
$access_configurations = array(); $access_configurations = array();

View File

@ -8,7 +8,10 @@
namespace Drupal\Tests\Core\Access; namespace Drupal\Tests\Core\Access;
use Drupal\Core\Access\AccessResult; use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Access\AccessResultNeutral;
use Drupal\Core\Cache\Cache; use Drupal\Core\Cache\Cache;
use Drupal\Core\Cache\CacheableInterface;
use Drupal\Tests\UnitTestCase; use Drupal\Tests\UnitTestCase;
/** /**
@ -36,15 +39,16 @@ class AccessResultTest extends UnitTestCase {
$verify = function (AccessResult $access) { $verify = function (AccessResult $access) {
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
}; };
// Verify the object when using the constructor. // Verify the object when using the constructor.
$a = new AccessResult(); $a = new AccessResultNeutral();
$verify($a); $verify($a);
// Verify the object when using the ::create() convenience method. // Verify the object when using the ::create() convenience method.
$b = AccessResult::create(); $b = AccessResult::neutral();
$verify($b); $verify($b);
$this->assertEquals($a, $b); $this->assertEquals($a, $b);
@ -55,23 +59,19 @@ class AccessResultTest extends UnitTestCase {
* @covers ::allowed * @covers ::allowed
* @covers ::isAllowed * @covers ::isAllowed
* @covers ::isForbidden * @covers ::isForbidden
* @covers ::isNeutral
*/ */
public function testAccessAllowed() { public function testAccessAllowed() {
$verify = function (AccessResult $access) { $verify = function (AccessResult $access) {
$this->assertTrue($access->isAllowed()); $this->assertTrue($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
}; };
// Verify the object when using the ::allow() instance method.
$a = AccessResult::create()->allow();
$verify($a);
// Verify the object when using the ::allowed() convenience static method. // Verify the object when using the ::allowed() convenience static method.
$b = AccessResult::allowed(); $b = AccessResult::allowed();
$verify($b); $verify($b);
$this->assertEquals($a, $b);
} }
/** /**
@ -79,44 +79,19 @@ class AccessResultTest extends UnitTestCase {
* @covers ::forbidden * @covers ::forbidden
* @covers ::isAllowed * @covers ::isAllowed
* @covers ::isForbidden * @covers ::isForbidden
* @covers ::isNeutral
*/ */
public function testAccessForbidden() { public function testAccessForbidden() {
$verify = function (AccessResult $access) { $verify = function (AccessResult $access) {
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden()); $this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
}; };
// Verify the object when using the ::forbid() instance method.
$a = AccessResult::create()->forbid();
$verify($a);
// Verify the object when using the ::forbidden() convenience static method. // Verify the object when using the ::forbidden() convenience static method.
$b = AccessResult::forbidden(); $b = AccessResult::forbidden();
$verify($b); $verify($b);
$this->assertEquals($a, $b);
}
/**
* @covers ::reset
* @covers ::isAllowed
* @covers ::isForbidden
*/
public function testAccessReset() {
$verify = function (AccessResult $access) {
$this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden());
$this->assertDefaultCacheability($access);
};
$a = AccessResult::allowed()->resetAccess();
$verify($a);
$b = AccessResult::forbidden()->resetAccess();
$verify($b);
$this->assertEquals($a, $b);
} }
/** /**
@ -124,34 +99,20 @@ class AccessResultTest extends UnitTestCase {
* @covers ::allowedIf * @covers ::allowedIf
* @covers ::isAllowed * @covers ::isAllowed
* @covers ::isForbidden * @covers ::isForbidden
* @covers ::isNeutral
*/ */
public function testAccessConditionallyAllowed() { public function testAccessConditionallyAllowed() {
$verify = function (AccessResult $access, $allowed, $forbidden = FALSE) { $verify = function (AccessResult $access, $allowed) {
$this->assertSame($allowed, $access->isAllowed()); $this->assertSame($allowed, $access->isAllowed());
$this->assertSame($forbidden, $access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertSame(!$allowed, $access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
}; };
// Verify the object when using the ::allowIf() instance method.
$a1 = AccessResult::create()->allowIf(TRUE);
$verify($a1, TRUE);
$a2 = AccessResult::create()->allowIf(FALSE);
$verify($a2, FALSE);
$b1 = AccessResult::allowedIf(TRUE); $b1 = AccessResult::allowedIf(TRUE);
$verify($b1, TRUE); $verify($b1, TRUE);
$b2 = AccessResult::allowedIf(FALSE); $b2 = AccessResult::allowedIf(FALSE);
$verify($b2, FALSE); $verify($b2, FALSE);
$this->assertEquals($a1, $b1);
$this->assertEquals($a2, $b2);
// Verify that ::allowIf() does not overwrite an existing value when the
// condition does not evaluate to TRUE.
$a1 = AccessResult::forbidden()->allowIf(TRUE);
$verify($a1, TRUE);
$a2 = AccessResult::forbidden()->allowIf(FALSE);
$verify($a2, FALSE, TRUE);
} }
/** /**
@ -159,80 +120,101 @@ class AccessResultTest extends UnitTestCase {
* @covers ::forbiddenIf * @covers ::forbiddenIf
* @covers ::isAllowed * @covers ::isAllowed
* @covers ::isForbidden * @covers ::isForbidden
* @covers ::isNeutral
*/ */
public function testAccessConditionallyForbidden() { public function testAccessConditionallyForbidden() {
$verify = function (AccessResult $access, $forbidden, $allowed = FALSE) { $verify = function (AccessResult $access, $forbidden) {
$this->assertSame($allowed, $access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertSame($forbidden, $access->isForbidden()); $this->assertSame($forbidden, $access->isForbidden());
$this->assertSame(!$forbidden, $access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
}; };
// Verify the object when using the ::allowIf() instance method.
$a1 = AccessResult::create()->forbidIf(TRUE);
$verify($a1, TRUE);
$a2 = AccessResult::create()->forbidIf(FALSE);
$verify($a2, FALSE);
$b1 = AccessResult::forbiddenIf(TRUE); $b1 = AccessResult::forbiddenIf(TRUE);
$verify($b1, TRUE); $verify($b1, TRUE);
$b2 = AccessResult::forbiddenIf(FALSE); $b2 = AccessResult::forbiddenIf(FALSE);
$verify($b2, FALSE); $verify($b2, FALSE);
$this->assertEquals($a1, $b1);
$this->assertEquals($a2, $b2);
// Verify that ::forbidIf() does not overwrite an existing value when the
// condition does not evaluate to TRUE.
$a1 = AccessResult::allowed()->forbidIf(TRUE);
$verify($a1, TRUE);
$a2 = AccessResult::allowed()->forbidIf(FALSE);
$verify($a2, FALSE, TRUE);
} }
/** /**
* @covers ::andIf * @covers ::andIf
*/ */
public function testAndIf() { public function testAndIf() {
$no_opinion = AccessResult::create(); $neutral = AccessResult::neutral();
$allowed = AccessResult::allowed(); $allowed = AccessResult::allowed();
$forbidden = AccessResult::forbidden(); $forbidden = AccessResult::forbidden();
$unused_access_result_due_to_lazy_evaluation = $this->getMock('\Drupal\Core\Access\AccessResultInterface'); $unused_access_result_due_to_lazy_evaluation = $this->getMock('\Drupal\Core\Access\AccessResultInterface');
$unused_access_result_due_to_lazy_evaluation->expects($this->never()) $unused_access_result_due_to_lazy_evaluation->expects($this->never())
->method($this->anything()); ->method($this->anything());
// ALLOW && ALLOW === ALLOW. // ALLOWED && ALLOWED === ALLOWED.
$access = clone $allowed; $access = $allowed->andIf($allowed);
$access->andIf($allowed);
$this->assertTrue($access->isAllowed()); $this->assertTrue($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// ALLOW && DENY === DENY. // ALLOWED && NEUTRAL === NEUTRAL.
$access = clone $allowed; $access = $allowed->andIf($neutral);
$access->andIf($no_opinion);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// ALLOW && KILL === KILL. // ALLOWED && FORBIDDEN === FORBIDDEN.
$access = clone $allowed; $access = $allowed->andIf($forbidden);
$access->andIf($forbidden);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden()); $this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// DENY && * === DENY. // NEUTRAL && ALLOW == NEUTRAL
$access = clone $no_opinion; $access = $neutral->andIf($allowed);
$access->andIf($unused_access_result_due_to_lazy_evaluation);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// KILL && * === KILL. // NEUTRAL && NEUTRAL === NEUTRAL.
$access = clone $forbidden; $access = $neutral->andIf($neutral);
$access->andIf($unused_access_result_due_to_lazy_evaluation); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertDefaultCacheability($access);
// NEUTRAL && FORBIDDEN === FORBIDDEN.
$access = $neutral->andIf($forbidden);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden()); $this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN && ALLOWED = FORBIDDEN
$access = $forbidden->andif($allowed);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN && NEUTRAL = FORBIDDEN
$access = $forbidden->andif($neutral);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN && FORBIDDEN = FORBIDDEN
$access = $forbidden->andif($forbidden);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN && * === FORBIDDEN: lazy evaluation verification.
$access = $forbidden->andIf($unused_access_result_due_to_lazy_evaluation);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
} }
@ -240,60 +222,81 @@ class AccessResultTest extends UnitTestCase {
* @covers ::orIf * @covers ::orIf
*/ */
public function testOrIf() { public function testOrIf() {
$no_opinion = AccessResult::create(); $neutral = AccessResult::neutral();
$allowed = AccessResult::allowed(); $allowed = AccessResult::allowed();
$forbidden = AccessResult::forbidden(); $forbidden = AccessResult::forbidden();
$unused_access_result_due_to_lazy_evaluation = $this->getMock('\Drupal\Core\Access\AccessResultInterface'); $unused_access_result_due_to_lazy_evaluation = $this->getMock('\Drupal\Core\Access\AccessResultInterface');
$unused_access_result_due_to_lazy_evaluation->expects($this->never()) $unused_access_result_due_to_lazy_evaluation->expects($this->never())
->method($this->anything()); ->method($this->anything());
// ALLOW || ALLOW === ALLOW. // ALLOWED || ALLOWED === ALLOWED.
$access = clone $allowed; $access = $allowed->orIf($allowed);
$access->orIf($allowed);
$this->assertTrue($access->isAllowed()); $this->assertTrue($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// ALLOW || DENY === ALLOW. // ALLOWED || NEUTRAL === ALLOWED.
$access = clone $allowed; $access = $allowed->orIf($neutral);
$access->orIf($no_opinion);
$this->assertTrue($access->isAllowed()); $this->assertTrue($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// ALLOW || KILL === KILL. // ALLOWED || FORBIDDEN === FORBIDDEN.
$access = clone $allowed; $access = $allowed->orIf($forbidden);
$access->orIf($forbidden);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden()); $this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// DENY || DENY === DENY. // NEUTRAL || NEUTRAL === NEUTRAL.
$access = clone $no_opinion; $access = $neutral->orIf($neutral);
$access->orIf($no_opinion);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// DENY || ALLOW === ALLOW. // NEUTRAL || ALLOWED === ALLOWED.
$access = clone $no_opinion; $access = $neutral->orIf($allowed);
$access->orIf($allowed);
$this->assertTrue($access->isAllowed()); $this->assertTrue($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// DENY || KILL === KILL. // NEUTRAL || FORBIDDEN === FORBIDDEN.
$access = clone $no_opinion; $access = $neutral->orIf($forbidden);
$access->orIf($forbidden);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden()); $this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
// KILL || * === KILL. // FORBIDDEN || ALLOWED === FORBIDDEN.
$access = clone $forbidden; $access = $forbidden->orIf($allowed);
$access->orIf($unused_access_result_due_to_lazy_evaluation);
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden()); $this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN || NEUTRAL === FORBIDDEN.
$access = $forbidden->orIf($allowed);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN || FORBIDDEN === FORBIDDEN.
$access = $forbidden->orIf($allowed);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access);
// FORBIDDEN || * === FORBIDDEN.
$access = $forbidden->orIf($unused_access_result_due_to_lazy_evaluation);
$this->assertFalse($access->isAllowed());
$this->assertTrue($access->isForbidden());
$this->assertFalse($access->isNeutral());
$this->assertDefaultCacheability($access); $this->assertDefaultCacheability($access);
} }
@ -302,9 +305,9 @@ class AccessResultTest extends UnitTestCase {
* @covers ::isCacheable * @covers ::isCacheable
*/ */
public function testCacheable() { public function testCacheable() {
$this->assertTrue(AccessResult::create()->isCacheable()); $this->assertTrue(AccessResult::neutral()->isCacheable());
$this->assertTrue(AccessResult::create()->setCacheable(TRUE)->isCacheable()); $this->assertTrue(AccessResult::neutral()->setCacheable(TRUE)->isCacheable());
$this->assertFalse(AccessResult::create()->setCacheable(FALSE)->isCacheable()); $this->assertFalse(AccessResult::neutral()->setCacheable(FALSE)->isCacheable());
} }
/** /**
@ -312,8 +315,8 @@ class AccessResultTest extends UnitTestCase {
* @covers ::getCacheMaxAge * @covers ::getCacheMaxAge
*/ */
public function testCacheMaxAge() { public function testCacheMaxAge() {
$this->assertSame(Cache::PERMANENT, AccessResult::create()->getCacheMaxAge()); $this->assertSame(Cache::PERMANENT, AccessResult::neutral()->getCacheMaxAge());
$this->assertSame(1337, AccessResult::create()->setCacheMaxAge(1337)->getCacheMaxAge()); $this->assertSame(1337, AccessResult::neutral()->setCacheMaxAge(1337)->getCacheMaxAge());
} }
/** /**
@ -329,6 +332,7 @@ class AccessResultTest extends UnitTestCase {
$verify = function (AccessResult $access, array $contexts) { $verify = function (AccessResult $access, array $contexts) {
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertTrue($access->isCacheable()); $this->assertTrue($access->isCacheable());
$this->assertSame('default', $access->getCacheBin()); $this->assertSame('default', $access->getCacheBin());
$this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge()); $this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge());
@ -336,7 +340,7 @@ class AccessResultTest extends UnitTestCase {
$this->assertSame([], $access->getCacheTags()); $this->assertSame([], $access->getCacheTags());
}; };
$access = AccessResult::create()->addCacheContexts(['cache_context.foo']); $access = AccessResult::neutral()->addCacheContexts(['cache_context.foo']);
$verify($access, ['cache_context.foo']); $verify($access, ['cache_context.foo']);
// Verify resetting works. // Verify resetting works.
$access->resetCacheContexts(); $access->resetCacheContexts();
@ -357,27 +361,27 @@ class AccessResultTest extends UnitTestCase {
// ::cachePerRole() convenience method. // ::cachePerRole() convenience method.
$contexts = array('cache_context.user.roles'); $contexts = array('cache_context.user.roles');
$a = AccessResult::create()->addCacheContexts($contexts); $a = AccessResult::neutral()->addCacheContexts($contexts);
$verify($a, $contexts); $verify($a, $contexts);
$b = AccessResult::create()->cachePerRole(); $b = AccessResult::neutral()->cachePerRole();
$verify($b, $contexts); $verify($b, $contexts);
$this->assertEquals($a, $b); $this->assertEquals($a, $b);
// ::cachePerUser() convenience method. // ::cachePerUser() convenience method.
$contexts = array('cache_context.user'); $contexts = array('cache_context.user');
$a = AccessResult::create()->addCacheContexts($contexts); $a = AccessResult::neutral()->addCacheContexts($contexts);
$verify($a, $contexts); $verify($a, $contexts);
$b = AccessResult::create()->cachePerUser(); $b = AccessResult::neutral()->cachePerUser();
$verify($b, $contexts); $verify($b, $contexts);
$this->assertEquals($a, $b); $this->assertEquals($a, $b);
// Both. // Both.
$contexts = array('cache_context.user', 'cache_context.user.roles'); $contexts = array('cache_context.user', 'cache_context.user.roles');
$a = AccessResult::create()->addCacheContexts($contexts); $a = AccessResult::neutral()->addCacheContexts($contexts);
$verify($a, $contexts); $verify($a, $contexts);
$b = AccessResult::create()->cachePerRole()->cachePerUser(); $b = AccessResult::neutral()->cachePerRole()->cachePerUser();
$verify($b, $contexts); $verify($b, $contexts);
$c = AccessResult::create()->cachePerUser()->cachePerRole(); $c = AccessResult::neutral()->cachePerUser()->cachePerRole();
$verify($c, $contexts); $verify($c, $contexts);
$this->assertEquals($a, $b); $this->assertEquals($a, $b);
$this->assertEquals($a, $c); $this->assertEquals($a, $c);
@ -390,17 +394,10 @@ class AccessResultTest extends UnitTestCase {
->will($this->returnValue(FALSE)); ->will($this->returnValue(FALSE));
$contexts = array('cache_context.user.roles'); $contexts = array('cache_context.user.roles');
// Verify the object when using the ::allowIfHasPermission() convenience
// instance method.
$a = AccessResult::create()->allowIfHasPermission($account, 'may herd llamas');
$verify($a, $contexts);
// Verify the object when using the ::allowedIfHasPermission() convenience // Verify the object when using the ::allowedIfHasPermission() convenience
// static method. // static method.
$b = AccessResult::allowedIfHasPermission($account, 'may herd llamas'); $b = AccessResult::allowedIfHasPermission($account, 'may herd llamas');
$verify($b, $contexts); $verify($b, $contexts);
$this->assertEquals($a, $b);
} }
/** /**
@ -413,6 +410,7 @@ class AccessResultTest extends UnitTestCase {
$verify = function (AccessResult $access, array $tags) { $verify = function (AccessResult $access, array $tags) {
$this->assertFalse($access->isAllowed()); $this->assertFalse($access->isAllowed());
$this->assertFalse($access->isForbidden()); $this->assertFalse($access->isForbidden());
$this->assertTrue($access->isNeutral());
$this->assertTrue($access->isCacheable()); $this->assertTrue($access->isCacheable());
$this->assertSame('default', $access->getCacheBin()); $this->assertSame('default', $access->getCacheBin());
$this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge()); $this->assertSame(Cache::PERMANENT, $access->getCacheMaxAge());
@ -420,7 +418,7 @@ class AccessResultTest extends UnitTestCase {
$this->assertSame($tags, $access->getCacheTags()); $this->assertSame($tags, $access->getCacheTags());
}; };
$access = AccessResult::create()->addCacheTags(['foo' => ['bar']]); $access = AccessResult::neutral()->addCacheTags(['foo' => ['bar']]);
$verify($access, ['foo' => ['bar' => 'bar']]); $verify($access, ['foo' => ['bar' => 'bar']]);
// Verify resetting works. // Verify resetting works.
$access->resetCacheTags(); $access->resetCacheTags();
@ -458,35 +456,21 @@ class AccessResultTest extends UnitTestCase {
->method('getCacheTag') ->method('getCacheTag')
->will($this->returnValue(array('node' => array(20011988)))); ->will($this->returnValue(array('node' => array(20011988))));
$tags = array('node' => array(20011988 => 20011988)); $tags = array('node' => array(20011988 => 20011988));
$a = AccessResult::create()->addCacheTags($tags); $a = AccessResult::neutral()->addCacheTags($tags);
$verify($a, $tags); $verify($a, $tags);
$b = AccessResult::create()->cacheUntilEntityChanges($node); $b = AccessResult::neutral()->cacheUntilEntityChanges($node);
$verify($b, $tags); $verify($b, $tags);
$this->assertEquals($a, $b); $this->assertEquals($a, $b);
} }
/** /**
* @covers ::andIf * @covers ::inheritCacheability
* @covers ::orIf
* @covers ::mergeCacheabilityMetadata
*/ */
public function testCacheabilityMerging() { public function testInheritCacheability() {
$access_without_cacheability = $this->getMock('\Drupal\Core\Access\AccessResultInterface');
$access_without_cacheability->expects($this->exactly(2))
->method('isAllowed')
->willReturn(TRUE);
$access_without_cacheability->expects($this->exactly(2))
->method('isForbidden')
->willReturn(FALSE);
$access_without_cacheability->expects($this->once())
->method('andIf')
->will($this->returnSelf());
// andIf(); 1st has defaults, 2nd has custom tags, contexts and max-age. // andIf(); 1st has defaults, 2nd has custom tags, contexts and max-age.
$access = AccessResult::allowed() $access = AccessResult::allowed();
->andIf(AccessResult::allowed()->setCacheMaxAge(1500)->cachePerRole()->addCacheTags(['node' => [20011988]])); $other = AccessResult::allowed()->setCacheMaxAge(1500)->cachePerRole()->addCacheTags(['node' => [20011988]]);
$this->assertTrue($access->isAllowed()); $this->assertTrue($access->inheritCacheability($other) instanceof AccessResult);
$this->assertFalse($access->isForbidden());
$this->assertTrue($access->isCacheable()); $this->assertTrue($access->isCacheable());
$this->assertSame(['cache_context.user.roles'], $access->getCacheKeys()); $this->assertSame(['cache_context.user.roles'], $access->getCacheKeys());
$this->assertSame(['node' => [20011988 => 20011988]], $access->getCacheTags()); $this->assertSame(['node' => [20011988 => 20011988]], $access->getCacheTags());
@ -494,39 +478,410 @@ class AccessResultTest extends UnitTestCase {
$this->assertSame(1500, $access->getCacheMaxAge()); $this->assertSame(1500, $access->getCacheMaxAge());
// andIf(); 1st has custom tags, max-age, 2nd has custom contexts and max-age. // andIf(); 1st has custom tags, max-age, 2nd has custom contexts and max-age.
$access = AccessResult::allowed()->cachePerUser()->setCacheMaxAge(43200) $access = AccessResult::allowed()->cachePerUser()->setCacheMaxAge(43200);
->andIf(AccessResult::forbidden()->addCacheTags(['node' => [14031991]])->setCacheMaxAge(86400)); $other = AccessResult::forbidden()->addCacheTags(['node' => [14031991]])->setCacheMaxAge(86400);
$this->assertFalse($access->isAllowed()); $this->assertTrue($access->inheritCacheability($other) instanceof AccessResult);
$this->assertTrue($access->isForbidden());
$this->assertTrue($access->isCacheable()); $this->assertTrue($access->isCacheable());
$this->assertSame(['cache_context.user'], $access->getCacheKeys()); $this->assertSame(['cache_context.user'], $access->getCacheKeys());
$this->assertSame(['node' => [14031991 => 14031991]], $access->getCacheTags()); $this->assertSame(['node' => [14031991 => 14031991]], $access->getCacheTags());
$this->assertSame('default', $access->getCacheBin()); $this->assertSame('default', $access->getCacheBin());
$this->assertSame(43200, $access->getCacheMaxAge()); $this->assertSame(43200, $access->getCacheMaxAge());
}
// orIf(); 1st is cacheable, 2nd isn't. /**
$access = AccessResult::allowed()->orIf(AccessResult::allowed()->setCacheable(FALSE)); * Provides a list of access result pairs and operations to test.
$this->assertTrue($access->isAllowed()); *
$this->assertFalse($access->isForbidden()); * This tests the propagation of cacheability metadata. Rather than testing
$this->assertFalse($access->isCacheable()); * every single bit of cacheability metadata, which would lead to a mind-
* boggling number of permutations, in this test, we only consider the
* permutations of all pairs of the following set:
* 1. Allowed, implements cacheable interface, is cacheable
* 2. Allowed, implements cacheable interface, is not cacheable
* 3. Allowed, does not implement cacheable interface (hence not cacheable)
* 4. Forbidden, implements cacheable interface, is cacheable
* 5. Forbidden, implements cacheable interface, is not cacheable
* 6. Forbidden, does not implement cacheable interface (hence not cacheable)
* 7. Neutral, implements cacheable interface, is cacheable
* 8. Neutral, implements cacheable interface, is not cacheable
* 9. Neutral, does not implement cacheable interface (hence not cacheable)
*
* This leads to 72 permutations (9!/(9-2)! = 9*8 = 72) per operation. There
* are two operations to test (AND and OR), so that leads to a grand total of
* 144 permutations, all of which are tested.
*
* There are two "contagious" patterns:
* 1. Any operation with a forbidden access result yields a forbidden result.
* This therefore also applies to the cacheability metadata associated with
* a forbidden result.
* This is the case for items 4, 5 and 6 in the set above.
* 2. Any operation yields an access result object that is of the same class
* (implementation) as the first operand. This is because operations are
* invoked on the first operand. Therefore, if the first implementation
* does not implement CacheableInterface, then the result won't either.
* This is the case for items 3, 6 and 9 in the set above.
*/
public function andOrCacheabilityPropagationProvider() {
// ct: cacheable=true, cf: cacheable=false, un: uncacheable.
// Note: the test cases that have a "un" access result as the first operand
// test UncacheableTestAccessResult, not AccessResult. However, we
// definitely want to verify that AccessResult's orIf() and andIf() methods
// work correctly when given an AccessResultInterface implementation that
// does not implement CacheableInterface, and we want to test the full gamut
// of permutations, so that's not a problem.
$allowed_ct = AccessResult::allowed();
$allowed_cf = AccessResult::allowed()->setCacheable(FALSE);
$allowed_un = new UncacheableTestAccessResult('ALLOWED');
$forbidden_ct = AccessResult::forbidden();
$forbidden_cf = AccessResult::forbidden()->setCacheable(FALSE);
$forbidden_un = new UncacheableTestAccessResult('FORBIDDEN');
$neutral_ct = AccessResult::neutral();
$neutral_cf = AccessResult::neutral()->setCacheable(FALSE);
$neutral_un = new UncacheableTestAccessResult('NEUTRAL');
// andIf(); 1st is cacheable, 2nd isn't. // Structure:
$access = AccessResult::allowed()->andIf(AccessResult::allowed()->setCacheable(FALSE)); // - First column: first access result.
$this->assertTrue($access->isAllowed()); // - Second column: operator ('OR' or 'AND').
$this->assertFalse($access->isForbidden()); // - Third column: second access result.
$this->assertFalse($access->isCacheable()); // - Fourth column: whether the result implements CacheableInterface
// - Fifth column: whether the result is cacheable (if column 4 is TRUE)
return [
// Allowed (ct) OR allowed (ct,cf,un).
[$allowed_ct, 'OR', $allowed_ct, TRUE, TRUE],
[$allowed_ct, 'OR', $allowed_cf, TRUE, TRUE],
[$allowed_ct, 'OR', $allowed_un, TRUE, TRUE],
// Allowed (cf) OR allowed (ct,cf,un).
[$allowed_cf, 'OR', $allowed_ct, TRUE, TRUE],
[$allowed_cf, 'OR', $allowed_cf, TRUE, FALSE],
[$allowed_cf, 'OR', $allowed_un, TRUE, FALSE],
// Allowed (un) OR allowed (ct,cf,un).
[$allowed_un, 'OR', $allowed_ct, FALSE, NULL],
[$allowed_un, 'OR', $allowed_cf, FALSE, NULL],
[$allowed_un, 'OR', $allowed_un, FALSE, NULL],
// andIf(); 1st implements CacheableInterface, 2nd doesn't. // Allowed (ct) OR forbidden (ct,cf,un).
$access = AccessResult::allowed()->andIf($access_without_cacheability); [$allowed_ct, 'OR', $forbidden_ct, TRUE, TRUE],
$this->assertTrue($access->isAllowed()); [$allowed_ct, 'OR', $forbidden_cf, TRUE, FALSE],
$this->assertFalse($access->isForbidden()); [$allowed_ct, 'OR', $forbidden_un, TRUE, FALSE],
$this->assertFalse($access->isCacheable()); // Allowed (cf) OR forbidden (ct,cf,un).
[$allowed_cf, 'OR', $forbidden_ct, TRUE, TRUE],
[$allowed_cf, 'OR', $forbidden_cf, TRUE, FALSE],
[$allowed_cf, 'OR', $forbidden_un, TRUE, FALSE],
// Allowed (un) OR forbidden (ct,cf,un).
[$allowed_un, 'OR', $forbidden_ct, FALSE, NULL],
[$allowed_un, 'OR', $forbidden_cf, FALSE, NULL],
[$allowed_un, 'OR', $forbidden_un, FALSE, NULL],
// andIf(); 1st doesn't implement CacheableInterface, 2nd does. // Allowed (ct) OR neutral (ct,cf,un).
$access = $access_without_cacheability->andIf(AccessResult::allowed()); [$allowed_ct, 'OR', $neutral_ct, TRUE, TRUE],
$this->assertTrue($access->isAllowed()); [$allowed_ct, 'OR', $neutral_cf, TRUE, TRUE],
$this->assertFalse($access->isForbidden()); [$allowed_ct, 'OR', $neutral_un, TRUE, TRUE],
$this->assertFalse(method_exists($access, 'isCacheable')); // Allowed (cf) OR neutral (ct,cf,un).
[$allowed_cf, 'OR', $neutral_ct, TRUE, FALSE],
[$allowed_cf, 'OR', $neutral_cf, TRUE, FALSE],
[$allowed_cf, 'OR', $neutral_un, TRUE, FALSE],
// Allowed (un) OR neutral (ct,cf,un).
[$allowed_un, 'OR', $neutral_ct, FALSE, NULL],
[$allowed_un, 'OR', $neutral_cf, FALSE, NULL],
[$allowed_un, 'OR', $neutral_un, FALSE, NULL],
// Forbidden (ct) OR allowed (ct,cf,un).
[$forbidden_ct, 'OR', $allowed_ct, TRUE, TRUE],
[$forbidden_ct, 'OR', $allowed_cf, TRUE, TRUE],
[$forbidden_ct, 'OR', $allowed_un, TRUE, TRUE],
// Forbidden (cf) OR allowed (ct,cf,un).
[$forbidden_cf, 'OR', $allowed_ct, TRUE, FALSE],
[$forbidden_cf, 'OR', $allowed_cf, TRUE, FALSE],
[$forbidden_cf, 'OR', $allowed_un, TRUE, FALSE],
// Forbidden (un) OR allowed (ct,cf,un).
[$forbidden_un, 'OR', $allowed_ct, FALSE, NULL],
[$forbidden_un, 'OR', $allowed_cf, FALSE, NULL],
[$forbidden_un, 'OR', $allowed_un, FALSE, NULL],
// Forbidden (ct) OR neutral (ct,cf,un).
[$forbidden_ct, 'OR', $neutral_ct, TRUE, TRUE],
[$forbidden_ct, 'OR', $neutral_cf, TRUE, TRUE],
[$forbidden_ct, 'OR', $neutral_un, TRUE, TRUE],
// Forbidden (cf) OR neutral (ct,cf,un).
[$forbidden_cf, 'OR', $neutral_ct, TRUE, FALSE],
[$forbidden_cf, 'OR', $neutral_cf, TRUE, FALSE],
[$forbidden_cf, 'OR', $neutral_un, TRUE, FALSE],
// Forbidden (un) OR neutral (ct,cf,un).
[$forbidden_un, 'OR', $neutral_ct, FALSE, NULL],
[$forbidden_un, 'OR', $neutral_cf, FALSE, NULL],
[$forbidden_un, 'OR', $neutral_un, FALSE, NULL],
// Forbidden (ct) OR forbidden (ct,cf,un).
[$forbidden_ct, 'OR', $forbidden_ct, TRUE, TRUE],
[$forbidden_ct, 'OR', $forbidden_cf, TRUE, TRUE],
[$forbidden_ct, 'OR', $forbidden_un, TRUE, TRUE],
// Forbidden (cf) OR forbidden (ct,cf,un).
[$forbidden_cf, 'OR', $forbidden_ct, TRUE, TRUE],
[$forbidden_cf, 'OR', $forbidden_cf, TRUE, FALSE],
[$forbidden_cf, 'OR', $forbidden_un, TRUE, FALSE],
// Forbidden (un) OR forbidden (ct,cf,un).
[$forbidden_un, 'OR', $forbidden_ct, FALSE, NULL],
[$forbidden_un, 'OR', $forbidden_cf, FALSE, NULL],
[$forbidden_un, 'OR', $forbidden_un, FALSE, NULL],
// Neutral (ct) OR allowed (ct,cf,un).
[$neutral_ct, 'OR', $allowed_ct, TRUE, TRUE],
[$neutral_ct, 'OR', $allowed_cf, TRUE, FALSE],
[$neutral_ct, 'OR', $allowed_un, TRUE, FALSE],
// Neutral (cf) OR allowed (ct,cf,un).
[$neutral_cf, 'OR', $allowed_ct, TRUE, TRUE],
[$neutral_cf, 'OR', $allowed_cf, TRUE, FALSE],
[$neutral_cf, 'OR', $allowed_un, TRUE, FALSE],
// Neutral (un) OR allowed (ct,cf,un).
[$neutral_un, 'OR', $allowed_ct, FALSE, NULL],
[$neutral_un, 'OR', $allowed_cf, FALSE, NULL],
[$neutral_un, 'OR', $allowed_un, FALSE, NULL],
// Neutral (ct) OR neutral (ct,cf,un).
[$neutral_ct, 'OR', $neutral_ct, TRUE, TRUE],
[$neutral_ct, 'OR', $neutral_cf, TRUE, TRUE],
[$neutral_ct, 'OR', $neutral_un, TRUE, TRUE],
// Neutral (cf) OR neutral (ct,cf,un).
[$neutral_cf, 'OR', $neutral_ct, TRUE, TRUE],
[$neutral_cf, 'OR', $neutral_cf, TRUE, FALSE],
[$neutral_cf, 'OR', $neutral_un, TRUE, FALSE],
// Neutral (un) OR neutral (ct,cf,un).
[$neutral_un, 'OR', $neutral_ct, FALSE, NULL],
[$neutral_un, 'OR', $neutral_cf, FALSE, NULL],
[$neutral_un, 'OR', $neutral_un, FALSE, NULL],
// Neutral (ct) OR forbidden (ct,cf,un).
[$neutral_ct, 'OR', $forbidden_ct, TRUE, TRUE],
[$neutral_ct, 'OR', $forbidden_cf, TRUE, FALSE],
[$neutral_ct, 'OR', $forbidden_un, TRUE, FALSE],
// Neutral (cf) OR forbidden (ct,cf,un).
[$neutral_cf, 'OR', $forbidden_ct, TRUE, TRUE],
[$neutral_cf, 'OR', $forbidden_cf, TRUE, FALSE],
[$neutral_cf, 'OR', $forbidden_un, TRUE, FALSE],
// Neutral (un) OR forbidden (ct,cf,un).
[$neutral_un, 'OR', $forbidden_ct, FALSE, NULL],
[$neutral_un, 'OR', $forbidden_cf, FALSE, NULL],
[$neutral_un, 'OR', $forbidden_un, FALSE, NULL],
// Allowed (ct) AND allowed (ct,cf,un).
[$allowed_ct, 'AND', $allowed_ct, TRUE, TRUE],
[$allowed_ct, 'AND', $allowed_cf, TRUE, FALSE],
[$allowed_ct, 'AND', $allowed_un, TRUE, FALSE],
// Allowed (cf) AND allowed (ct,cf,un).
[$allowed_cf, 'AND', $allowed_ct, TRUE, FALSE],
[$allowed_cf, 'AND', $allowed_cf, TRUE, FALSE],
[$allowed_cf, 'AND', $allowed_un, TRUE, FALSE],
// Allowed (un) AND allowed (ct,cf,un).
[$allowed_un, 'AND', $allowed_ct, FALSE, NULL],
[$allowed_un, 'AND', $allowed_cf, FALSE, NULL],
[$allowed_un, 'AND', $allowed_un, FALSE, NULL],
// Allowed (ct) AND forbidden (ct,cf,un).
[$allowed_ct, 'AND', $forbidden_ct, TRUE, TRUE],
[$allowed_ct, 'AND', $forbidden_cf, TRUE, FALSE],
[$allowed_ct, 'AND', $forbidden_un, TRUE, FALSE],
// Allowed (cf) AND forbidden (ct,cf,un).
[$allowed_cf, 'AND', $forbidden_ct, TRUE, TRUE],
[$allowed_cf, 'AND', $forbidden_cf, TRUE, FALSE],
[$allowed_cf, 'AND', $forbidden_un, TRUE, FALSE],
// Allowed (un) AND forbidden (ct,cf,un).
[$allowed_un, 'AND', $forbidden_ct, FALSE, NULL],
[$allowed_un, 'AND', $forbidden_cf, FALSE, NULL],
[$allowed_un, 'AND', $forbidden_un, FALSE, NULL],
// Allowed (ct) AND neutral (ct,cf,un).
[$allowed_ct, 'AND', $neutral_ct, TRUE, TRUE],
[$allowed_ct, 'AND', $neutral_cf, TRUE, FALSE],
[$allowed_ct, 'AND', $neutral_un, TRUE, FALSE],
// Allowed (cf) AND neutral (ct,cf,un).
[$allowed_cf, 'AND', $neutral_ct, TRUE, FALSE],
[$allowed_cf, 'AND', $neutral_cf, TRUE, FALSE],
[$allowed_cf, 'AND', $neutral_un, TRUE, FALSE],
// Allowed (un) AND neutral (ct,cf,un).
[$allowed_un, 'AND', $neutral_ct, FALSE, NULL],
[$allowed_un, 'AND', $neutral_cf, FALSE, NULL],
[$allowed_un, 'AND', $neutral_un, FALSE, NULL],
// Forbidden (ct) AND allowed (ct,cf,un).
[$forbidden_ct, 'AND', $allowed_ct, TRUE, TRUE],
[$forbidden_ct, 'AND', $allowed_cf, TRUE, TRUE],
[$forbidden_ct, 'AND', $allowed_un, TRUE, TRUE],
// Forbidden (cf) AND allowed (ct,cf,un).
[$forbidden_cf, 'AND', $allowed_ct, TRUE, FALSE],
[$forbidden_cf, 'AND', $allowed_cf, TRUE, FALSE],
[$forbidden_cf, 'AND', $allowed_un, TRUE, FALSE],
// Forbidden (un) AND allowed (ct,cf,un).
[$forbidden_un, 'AND', $allowed_ct, FALSE, NULL],
[$forbidden_un, 'AND', $allowed_cf, FALSE, NULL],
[$forbidden_un, 'AND', $allowed_un, FALSE, NULL],
// Forbidden (ct) AND neutral (ct,cf,un).
[$forbidden_ct, 'AND', $neutral_ct, TRUE, TRUE],
[$forbidden_ct, 'AND', $neutral_cf, TRUE, TRUE],
[$forbidden_ct, 'AND', $neutral_un, TRUE, TRUE],
// Forbidden (cf) AND neutral (ct,cf,un).
[$forbidden_cf, 'AND', $neutral_ct, TRUE, FALSE],
[$forbidden_cf, 'AND', $neutral_cf, TRUE, FALSE],
[$forbidden_cf, 'AND', $neutral_un, TRUE, FALSE],
// Forbidden (un) AND neutral (ct,cf,un).
[$forbidden_un, 'AND', $neutral_ct, FALSE, NULL],
[$forbidden_un, 'AND', $neutral_cf, FALSE, NULL],
[$forbidden_un, 'AND', $neutral_un, FALSE, NULL],
// Forbidden (ct) AND forbidden (ct,cf,un).
[$forbidden_ct, 'AND', $forbidden_ct, TRUE, TRUE],
[$forbidden_ct, 'AND', $forbidden_cf, TRUE, TRUE],
[$forbidden_ct, 'AND', $forbidden_un, TRUE, TRUE],
// Forbidden (cf) AND forbidden (ct,cf,un).
[$forbidden_cf, 'AND', $forbidden_ct, TRUE, FALSE],
[$forbidden_cf, 'AND', $forbidden_cf, TRUE, FALSE],
[$forbidden_cf, 'AND', $forbidden_un, TRUE, FALSE],
// Forbidden (un) AND forbidden (ct,cf,un).
[$forbidden_un, 'AND', $forbidden_ct, FALSE, NULL],
[$forbidden_un, 'AND', $forbidden_cf, FALSE, NULL],
[$forbidden_un, 'AND', $forbidden_un, FALSE, NULL],
// Neutral (ct) AND allowed (ct,cf,un).
[$neutral_ct, 'AND', $allowed_ct, TRUE, TRUE],
[$neutral_ct, 'AND', $allowed_cf, TRUE, TRUE],
[$neutral_ct, 'AND', $allowed_un, TRUE, TRUE],
// Neutral (cf) AND allowed (ct,cf,un).
[$neutral_cf, 'AND', $allowed_ct, TRUE, FALSE],
[$neutral_cf, 'AND', $allowed_cf, TRUE, FALSE],
[$neutral_cf, 'AND', $allowed_un, TRUE, FALSE],
// Neutral (un) AND allowed (ct,cf,un).
[$neutral_un, 'AND', $allowed_ct, FALSE, NULL],
[$neutral_un, 'AND', $allowed_cf, FALSE, NULL],
[$neutral_un, 'AND', $allowed_un, FALSE, NULL],
// Neutral (ct) AND neutral (ct,cf,un).
[$neutral_ct, 'AND', $neutral_ct, TRUE, TRUE],
[$neutral_ct, 'AND', $neutral_cf, TRUE, TRUE],
[$neutral_ct, 'AND', $neutral_un, TRUE, TRUE],
// Neutral (cf) AND neutral (ct,cf,un).
[$neutral_cf, 'AND', $neutral_ct, TRUE, FALSE],
[$neutral_cf, 'AND', $neutral_cf, TRUE, FALSE],
[$neutral_cf, 'AND', $neutral_un, TRUE, FALSE],
// Neutral (un) AND neutral (ct,cf,un).
[$neutral_un, 'AND', $neutral_ct, FALSE, NULL],
[$neutral_un, 'AND', $neutral_cf, FALSE, NULL],
[$neutral_un, 'AND', $neutral_un, FALSE, NULL],
// Neutral (ct) AND forbidden (ct,cf,un).
[$neutral_ct, 'AND', $forbidden_ct, TRUE, TRUE],
[$neutral_ct, 'AND', $forbidden_cf, TRUE, FALSE],
[$neutral_ct, 'AND', $forbidden_un, TRUE, FALSE],
// Neutral (cf) AND forbidden (ct,cf,un).
[$neutral_cf, 'AND', $forbidden_ct, TRUE, TRUE],
[$neutral_cf, 'AND', $forbidden_cf, TRUE, FALSE],
[$neutral_cf, 'AND', $forbidden_un, TRUE, FALSE],
// Neutral (un) AND forbidden (ct,cf,un).
[$neutral_un, 'AND', $forbidden_ct, FALSE, NULL],
[$neutral_un, 'AND', $forbidden_cf, FALSE, NULL],
[$neutral_un, 'AND', $forbidden_un, FALSE, NULL],
];
}
/**
* @covers ::andIf
* @covers ::orIf
* @covers ::inheritCacheability
*
* @dataProvider andOrCacheabilityPropagationProvider
*/
public function testAndOrCacheabilityPropagation(AccessResultInterface $first, $op, AccessResultInterface $second, $implements_cacheable_interface, $is_cacheable) {
if ($op === 'OR') {
$result = $first->orIf($second);
}
else if ($op === 'AND') {
$result = $first->andIf($second);
}
else {
throw new \LogicException('Invalid operator specified');
}
if ($implements_cacheable_interface) {
$this->assertTrue($result instanceof CacheableInterface, 'Result is an instance of CacheableInterface.');
if ($result instanceof CacheableInterface) {
$this->assertSame($is_cacheable, $result->isCacheable(), 'isCacheable() matches expectations.');
}
}
else {
$this->assertFalse($result instanceof CacheableInterface, 'Result is not an instance of CacheableInterface.');
}
}
}
class UncacheableTestAccessResult implements AccessResultInterface {
/**
* The access result value. 'ALLOWED', 'FORBIDDEN' or 'NEUTRAL'.
*
* @var string
*/
protected $value;
/**
* Constructs a new UncacheableTestAccessResult object.
*/
public function __construct($value) {
$this->value = $value;
}
/**
* {@inheritdoc}
*/
public function isAllowed() {
return $this->value === 'ALLOWED';
}
/**
* {@inheritdoc}
*/
public function isForbidden() {
return $this->value === 'FORBIDDEN';
}
/**
* {@inheritdoc}
*/
public function isNeutral() {
return $this->value === 'NEUTRAL';
}
/**
* {@inheritdoc}
*/
public function orIf(AccessResultInterface $other) {
if ($this->isForbidden() || $other->isForbidden()) {
return new static('FORBIDDEN');
}
elseif ($this->isAllowed() || $other->isAllowed()) {
return new static('ALLOWED');
}
else {
return new static('NEUTRAL');
}
}
/**
* {@inheritdoc}
*/
public function andIf(AccessResultInterface $other) {
if ($this->isForbidden() || $other->isForbidden()) {
return new static('FORBIDDEN');
}
elseif ($this->isAllowed() && $other->isAllowed()) {
return new static('ALLOWED');
}
else {
return new static('NEUTRAL');
}
} }
} }

View File

@ -97,7 +97,7 @@ class CustomAccessCheckTest extends UnitTestCase {
$route = new Route('/test-route', array(), array('_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessDeny')); $route = new Route('/test-route', array(), array('_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessDeny'));
$account = $this->getMock('Drupal\Core\Session\AccountInterface'); $account = $this->getMock('Drupal\Core\Session\AccountInterface');
$this->assertEquals(AccessResult::create(), $this->accessChecker->access($route, $route_match, $account)); $this->assertEquals(AccessResult::neutral(), $this->accessChecker->access($route, $route_match, $account));
$route = new Route('/test-route', array(), array('_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessAllow')); $route = new Route('/test-route', array(), array('_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessAllow'));
$this->assertEquals(AccessResult::allowed(), $this->accessChecker->access($route, $route_match, $account)); $this->assertEquals(AccessResult::allowed(), $this->accessChecker->access($route, $route_match, $account));
@ -115,7 +115,7 @@ class TestController {
} }
public function accessDeny() { public function accessDeny() {
return AccessResult::create(); return AccessResult::neutral();
} }
public function accessParameter($parameter) { public function accessParameter($parameter) {

View File

@ -50,7 +50,7 @@ class DefaultAccessCheckTest extends UnitTestCase {
$request = new Request(array()); $request = new Request(array());
$route = new Route('/test-route', array(), array('_access' => 'NULL')); $route = new Route('/test-route', array(), array('_access' => 'NULL'));
$this->assertEquals(AccessResult::create(), $this->accessChecker->access($route, $request, $this->account)); $this->assertEquals(AccessResult::neutral(), $this->accessChecker->access($route, $request, $this->account));
$route = new Route('/test-route', array(), array('_access' => 'FALSE')); $route = new Route('/test-route', array(), array('_access' => 'FALSE'));
$this->assertEquals(AccessResult::forbidden(), $this->accessChecker->access($route, $request, $this->account)); $this->assertEquals(AccessResult::forbidden(), $this->accessChecker->access($route, $request, $this->account));

View File

@ -40,9 +40,9 @@ class EntityCreateAccessCheckTest extends UnitTestCase {
* @return array * @return array
*/ */
public function providerTestAccess() { public function providerTestAccess() {
$no_access = AccessResult::create()->cachePerRole(); $no_access = AccessResult::neutral()->cachePerRole();
$access = AccessResult::allowed()->cachePerRole(); $access = AccessResult::allowed()->cachePerRole();
$no_access_due_to_errors = AccessResult::create(); $no_access_due_to_errors = AccessResult::neutral();
return array( return array(
array('', 'entity_test', $no_access, $no_access), array('', 'entity_test', $no_access, $no_access),

View File

@ -155,7 +155,7 @@ class RoleAccessCheckTest extends UnitTestCase {
foreach ($deny_accounts as $account) { foreach ($deny_accounts as $account) {
$message = sprintf('Access denied for user %s with the roles %s on path: %s', $account->id(), implode(', ', $account->getRoles()), $path); $message = sprintf('Access denied for user %s with the roles %s on path: %s', $account->id(), implode(', ', $account->getRoles()), $path);
$has_access = $role_access_check->access($collection->get($path), $account); $has_access = $role_access_check->access($collection->get($path), $account);
$this->assertEquals(AccessResult::create()->cachePerRole(), $has_access, $message); $this->assertEquals(AccessResult::neutral()->cachePerRole(), $has_access, $message);
} }
} }