You are here

public function AccessResult::orIf in Drupal 9

Same name and namespace in other branches
  1. 8 core/lib/Drupal/Core/Access/AccessResult.php \Drupal\Core\Access\AccessResult::orIf()
  2. 10 core/lib/Drupal/Core/Access/AccessResult.php \Drupal\Core\Access\AccessResult::orIf()

Combine this access result with another using OR.

When ORing two access results, the result is:

  • isForbidden() in either ⇒ isForbidden()
  • otherwise if isAllowed() in either ⇒ isAllowed()
  • otherwise both must be isNeutral() ⇒ isNeutral()

Truth table:


  |A N F
--+-----
A |A A F
N |A N F
F |F F F

Parameters

\Drupal\Core\Access\AccessResultInterface $other: The other access result to OR this one with.

Return value

static

Overrides AccessResultInterface::orIf

File

core/lib/Drupal/Core/Access/AccessResult.php, line 282

Class

AccessResult
Value object for passing an access result with cacheability metadata.

Namespace

Drupal\Core\Access

Code

public function orIf(AccessResultInterface $other) {
  $merge_other = FALSE;

  // $other's cacheability metadata is merged if $merge_other gets set to TRUE
  // and this happens in three 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.
  // 3. Neither access result is 'forbidden' and both are cacheable: inherit
  //    the other's cacheability metadata because it may turn into a
  //    'forbidden' for another value of the cache contexts in the
  //    cacheability metadata. In other words: this is necessary to respect
  //    the contagious nature of the 'forbidden' access result.
  //    e.g. we have two access results A and B. Neither is forbidden. A is
  //    globally cacheable (no cache contexts). B is cacheable per role. If we
  //    don't have merging case 3, then A->orIf(B) will be globally cacheable,
  //    which means that even if a user of a different role logs in, the
  //    cached access result will be used, even though for that other role, B
  //    is forbidden!
  if ($this
    ->isForbidden() || $other
    ->isForbidden()) {
    $result = static::forbidden();
    if (!$this
      ->isForbidden() || $this
      ->getCacheMaxAge() === 0 && $other
      ->isForbidden()) {
      $merge_other = TRUE;
    }
    if ($this
      ->isForbidden() && $this instanceof AccessResultReasonInterface && !is_null($this
      ->getReason())) {
      $result
        ->setReason($this
        ->getReason());
    }
    elseif ($other
      ->isForbidden() && $other instanceof AccessResultReasonInterface && !is_null($other
      ->getReason())) {
      $result
        ->setReason($other
        ->getReason());
    }
  }
  elseif ($this
    ->isAllowed() || $other
    ->isAllowed()) {
    $result = static::allowed();
    if (!$this
      ->isAllowed() || $this
      ->getCacheMaxAge() === 0 && $other
      ->isAllowed() || $this
      ->getCacheMaxAge() !== 0 && $other instanceof CacheableDependencyInterface && $other
      ->getCacheMaxAge() !== 0) {
      $merge_other = TRUE;
    }
  }
  else {
    $result = static::neutral();
    if (!$this
      ->isNeutral() || $this
      ->getCacheMaxAge() === 0 && $other
      ->isNeutral() || $this
      ->getCacheMaxAge() !== 0 && $other instanceof CacheableDependencyInterface && $other
      ->getCacheMaxAge() !== 0) {
      $merge_other = TRUE;
    }
    if ($this instanceof AccessResultReasonInterface && !is_null($this
      ->getReason())) {
      $result
        ->setReason($this
        ->getReason());
    }
    elseif ($other instanceof AccessResultReasonInterface && !is_null($other
      ->getReason())) {
      $result
        ->setReason($other
        ->getReason());
    }
  }
  $result
    ->inheritCacheability($this);
  if ($merge_other) {
    $result
      ->inheritCacheability($other);
  }
  return $result;
}