Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add access groups #12

Open
wants to merge 4 commits into
base: 8.6.x
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
17 changes: 17 additions & 0 deletions core/lib/Drupal/Core/Access/AccessGroupAnd.php
@@ -0,0 +1,17 @@
<?php

namespace Drupal\Core\Access;

/**
* An access group where all the dependencies must be allowed.
*/
class AccessGroupAnd extends AccessibleGroupBase {

/**
* {@inheritdoc}
*/
protected function doCombineAccess(AccessResultInterface $accumulatedAccess, AccessResultInterface $dependencyAccess) {
return $accumulatedAccess->andIf($dependencyAccess);
}

}
18 changes: 18 additions & 0 deletions core/lib/Drupal/Core/Access/AccessGroupOr.php
@@ -0,0 +1,18 @@
<?php

namespace Drupal\Core\Access;


/**
* An access group where at least one dependencies must be allowed.
*/
class AccessGroupOr extends AccessibleGroupBase {

/**
* {@inheritdoc}
*/
protected function doCombineAccess(AccessResultInterface $accumulatedAccess, AccessResultInterface $dependencyAccess) {
return $accumulatedAccess->orIf($dependencyAccess);
}

}
57 changes: 57 additions & 0 deletions core/lib/Drupal/Core/Access/AccessibleGroupBase.php
@@ -0,0 +1,57 @@
<?php

namespace Drupal\Core\Access;

use Drupal\Core\Session\AccountInterface;

/**
* A base class for accessible groups classes.
*/
abstract class AccessibleGroupBase implements AccessibleGroupInterface {

/**
* The access dependencies.
*
* @var \Drupal\Core\Access\AccessibleInterface[]
*/
protected $dependencies = [];

/**
* {@inheritdoc}
*/
public function addDependency(AccessibleInterface $dependency) {
$this->dependencies[] = $dependency;
return $this;
}

/**
* {@inheritdoc}
*/
public function access($operation, AccountInterface $account = NULL, $return_as_object = FALSE) {
$access_result = NULL;
foreach ($this->dependencies as $dependency) {
$dependency_access_result = $dependency->access($operation, $account, TRUE);
if ($access_result === NULL) {
$access_result = $dependency_access_result;
}
else {
$access_result = $this->doCombineAccess($access_result, $dependency_access_result);
}
}
return $return_as_object ? $access_result : $access_result->isAllowed();
}

/**
* Combines the access result of one dependency to previous dependencies.
*
* @param \Drupal\Core\Access\AccessResultInterface $accumulatedAccess
* The combine access result of previous dependencies.
* @param \Drupal\Core\Access\AccessResultInterface $dependencyAccess
* The access result of the current dependency.
*
* @return \Drupal\Core\Access\AccessResultInterface
* The combined access result.
*/
abstract protected function doCombineAccess(AccessResultInterface $accumulatedAccess, AccessResultInterface $dependencyAccess);

}
21 changes: 21 additions & 0 deletions core/lib/Drupal/Core/Access/AccessibleGroupInterface.php
@@ -0,0 +1,21 @@
<?php

namespace Drupal\Core\Access;

/**
* Extends AccessibleInterface to allow for access objects that have multiple
* dependencies.
*/
interface AccessibleGroupInterface extends AccessibleInterface {

/**
* Adds an access dependency.
*
* @param \Drupal\Core\Access\AccessibleInterface $dependency
* The access dependency.
*
* @return $this
*/
public function addDependency(AccessibleInterface $dependency);

}
75 changes: 75 additions & 0 deletions core/tests/Drupal/Tests/Core/Access/AccessGroupTest.php
@@ -0,0 +1,75 @@
<?php

namespace Drupal\Tests\Core\Access;

use Drupal\Core\Access\AccessGroupAnd;
use Drupal\Core\Access\AccessGroupOr;
use Drupal\Core\Access\AccessibleInterface;
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Access\AccessResultInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Tests\UnitTestCase;

class AccessGroupTest extends UnitTestCase {

/**
* @var \Drupal\Core\Session\AccountInterface
*/
protected $account;

protected function setUp() {
parent::setUp(); // TODO: Change the autogenerated stub
$this->account = $this->prophesize(AccountInterface::class)->reveal();
}


public function testGroups() {
$allowedAccessible = $this->makeAccessbileProh(AccessResult::allowed());
$forbiddenAccessible = $this->makeAccessbileProh(AccessResult::forbidden());
$neutralAccessible = $this->makeAccessbileProh(AccessResult::neutral());



$orForbidden = new AccessGroupOr();
$orForbidden->addDependency($allowedAccessible)->addDependency($forbiddenAccessible);
$this->assertTrue($orForbidden->access('view', $this->account, TRUE)->isForbidden());

$orAllowed = new AccessGroupOr();
$orAllowed->addDependency($allowedAccessible)->addDependency($neutralAccessible);
$this->assertTrue($orAllowed->access('view', $this->account, TRUE)->isAllowed());

$andNeutral = new AccessGroupAnd();
$andNeutral->addDependency($allowedAccessible)->addDependency($neutralAccessible);
$this->assertTrue($andNeutral->access('view', $this->account, TRUE)->isNeutral());

// We can also add groups and dependencies!!!!! Nested!!!!!
$andNeutral->addDependency($orAllowed);
$this->assertTrue($andNeutral->access('view', $this->account, TRUE)->isNeutral());

$andForbidden = $andNeutral;
$andForbidden->addDependency($forbiddenAccessible);
$this->assertTrue($andForbidden->access('view', $this->account, TRUE)->isForbidden());

// We can make groups from other groups!
$andGroupsForbidden = new AccessGroupAnd();
$andGroupsForbidden->addDependency($andNeutral)->addDependency($andForbidden)->addDependency($orForbidden);
$this->assertTrue($andGroupsForbidden->access('view', $this->account, TRUE)->isForbidden());
// But then would could also add a non-group accessible.
$andGroupsForbidden->addDependency($allowedAccessible);
$this->assertTrue($andGroupsForbidden->access('view', $this->account, TRUE)->isForbidden());

}

/**
* @param \Drupal\Core\Access\AccessResultInterface $accessResult
*
* @return AccessibleInterface
*/
private function makeAccessbileProh(AccessResultInterface $accessResult) {
$accessible = $this->prophesize(AccessibleInterface::class);
$accessible->access('view', $this->account, TRUE)
->willReturn($accessResult);
return $accessible->reveal();
}

}