core/lib/Drupal/Core/Access/AccessManager.php | 4 ---- core/lib/Drupal/Core/Access/AccessResult.php | 20 ++++++++++++++------ core/lib/Drupal/Core/Access/AccessResultAllowed.php | 3 +++ .../lib/Drupal/Core/Access/AccessResultForbidden.php | 3 +++ .../lib/Drupal/Core/Access/AccessResultInterface.php | 4 ++-- core/lib/Drupal/Core/Access/AccessResultNeutral.php | 3 +++ .../Drupal/Tests/Core/Access/AccessResultTest.php | 10 ++++++++-- 7 files changed, 33 insertions(+), 14 deletions(-) diff --git a/core/lib/Drupal/Core/Access/AccessManager.php b/core/lib/Drupal/Core/Access/AccessManager.php index 99417af..eb177ad 100644 --- a/core/lib/Drupal/Core/Access/AccessManager.php +++ b/core/lib/Drupal/Core/Access/AccessManager.php @@ -296,10 +296,6 @@ protected function checkAny(array $checks, ArgumentsResolverInterface $arguments $this->loadCheck($service_id); } $result = $result->orIf($this->performCheck($service_id, $arguments_resolver)); - // Stop as soon as the first forbidden check is encountered. - if ($result->isForbidden()) { - break; - } } return $result; diff --git a/core/lib/Drupal/Core/Access/AccessResult.php b/core/lib/Drupal/Core/Access/AccessResult.php index e65447b..9180435 100644 --- a/core/lib/Drupal/Core/Access/AccessResult.php +++ b/core/lib/Drupal/Core/Access/AccessResult.php @@ -14,6 +14,14 @@ /** * 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 * accordingly as well. */ @@ -150,7 +158,7 @@ public function isAllowed() { /** * {@inheritdoc} * - * \Drupal\Core\Access\AccessResultForbidden + * @see \Drupal\Core\Access\AccessResultForbidden */ public function isForbidden() { return FALSE; @@ -328,10 +336,11 @@ public function cacheUntilEntityChanges(EntityInterface $entity) { * {@inheritdoc} */ public function orIf(AccessResultInterface $other) { - // The other access result's cacheability metadata is merged if $merge_other - // gets set to TRUE. It gets set to TRUE in two cases: - // 1. The other access result is used. - // 2. This access result is not cacheable and the other access result is the + // $other's cacheability metadata is merged if $merge_other gets set to TRUE + // and this happens in two cases: + // 1. $other's access result is the one that determines the combined access + // 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()) { @@ -383,7 +392,6 @@ public function andIf(AccessResultInterface $other) { $merge_other = TRUE; } } - // Only when this access result already was isAllowed(), the second $result->inheritCacheability($this); if ($merge_other) { $result->inheritCacheability($other); diff --git a/core/lib/Drupal/Core/Access/AccessResultAllowed.php b/core/lib/Drupal/Core/Access/AccessResultAllowed.php index f9e892c..abc2147 100644 --- a/core/lib/Drupal/Core/Access/AccessResultAllowed.php +++ b/core/lib/Drupal/Core/Access/AccessResultAllowed.php @@ -7,6 +7,9 @@ namespace Drupal\Core\Access; +/** + * Value object indicating an allowed access result, with cacheability metadata. + */ class AccessResultAllowed extends AccessResult { /** diff --git a/core/lib/Drupal/Core/Access/AccessResultForbidden.php b/core/lib/Drupal/Core/Access/AccessResultForbidden.php index ca57d77..821bef9 100644 --- a/core/lib/Drupal/Core/Access/AccessResultForbidden.php +++ b/core/lib/Drupal/Core/Access/AccessResultForbidden.php @@ -7,6 +7,9 @@ namespace Drupal\Core\Access; +/** + * Value object indicating a forbidden access result, with cacheability metadata. + */ class AccessResultForbidden extends AccessResult { /** diff --git a/core/lib/Drupal/Core/Access/AccessResultInterface.php b/core/lib/Drupal/Core/Access/AccessResultInterface.php index aa39c01..7d02314 100644 --- a/core/lib/Drupal/Core/Access/AccessResultInterface.php +++ b/core/lib/Drupal/Core/Access/AccessResultInterface.php @@ -68,7 +68,7 @@ public function isNeutral(); * @param \Drupal\Core\Access\AccessResultInterface $other * The other access result to OR this one with. * - * @return \Drupal\Core\Access\AccessResultInterface + * @return static */ public function orIf(AccessResultInterface $other); @@ -83,7 +83,7 @@ public function orIf(AccessResultInterface $other); * @param \Drupal\Core\Access\AccessResultInterface $other * The other access result to AND this one with. * - * @return \Drupal\Core\Access\AccessResultInterface + * @return static */ public function andIf(AccessResultInterface $other); diff --git a/core/lib/Drupal/Core/Access/AccessResultNeutral.php b/core/lib/Drupal/Core/Access/AccessResultNeutral.php index 030ebda..2b38806 100644 --- a/core/lib/Drupal/Core/Access/AccessResultNeutral.php +++ b/core/lib/Drupal/Core/Access/AccessResultNeutral.php @@ -7,6 +7,9 @@ namespace Drupal\Core\Access; +/** + * Value object indicating a neutral access result, with cacheability metadata. + */ class AccessResultNeutral extends AccessResult { /** diff --git a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php index e20805f..15b8599 100644 --- a/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php +++ b/core/tests/Drupal/Tests/Core/Access/AccessResultTest.php @@ -520,8 +520,14 @@ public function testInheritCacheability() { * 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 testAndOrCacheabilityPropagationProvider() { + 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'); @@ -787,7 +793,7 @@ public function testAndOrCacheabilityPropagationProvider() { * @covers ::orIf * @covers ::inheritCacheability * - * @dataProvider testAndOrCacheabilityPropagationProvider + * @dataProvider andOrCacheabilityPropagationProvider */ public function testAndOrCacheabilityPropagation(AccessResultInterface $first, $op, AccessResultInterface $second, $implements_cacheable_interface, $is_cacheable) { if ($op === 'OR') {