annotate core/lib/Drupal/Core/Access/CheckProvider.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Core\Access;
Chris@0 4
Chris@0 5 use Drupal\Core\Routing\Access\AccessInterface;
Chris@0 6 use Symfony\Component\DependencyInjection\ContainerAwareInterface;
Chris@0 7 use Symfony\Component\DependencyInjection\ContainerAwareTrait;
Chris@0 8 use Symfony\Component\Routing\Route;
Chris@0 9 use Symfony\Component\Routing\RouteCollection;
Chris@0 10
Chris@0 11 /**
Chris@0 12 * Loads access checkers from the container.
Chris@0 13 */
Chris@0 14 class CheckProvider implements CheckProviderInterface, ContainerAwareInterface {
Chris@0 15
Chris@0 16 use ContainerAwareTrait;
Chris@0 17
Chris@0 18 /**
Chris@0 19 * Array of registered access check service ids.
Chris@0 20 *
Chris@0 21 * @var array
Chris@0 22 */
Chris@0 23 protected $checkIds = [];
Chris@0 24
Chris@0 25 /**
Chris@0 26 * Array of access check objects keyed by service id.
Chris@0 27 *
Chris@0 28 * @var \Drupal\Core\Routing\Access\AccessInterface[]
Chris@0 29 */
Chris@0 30 protected $checks;
Chris@0 31
Chris@0 32 /**
Chris@0 33 * Array of access check method names keyed by service ID.
Chris@0 34 *
Chris@0 35 * @var array
Chris@0 36 */
Chris@0 37 protected $checkMethods = [];
Chris@0 38
Chris@0 39 /**
Chris@0 40 * Array of access checks which only will be run on the incoming request.
Chris@0 41 */
Chris@0 42 protected $checksNeedsRequest = [];
Chris@0 43
Chris@0 44 /**
Chris@0 45 * An array to map static requirement keys to service IDs.
Chris@0 46 *
Chris@0 47 * @var array
Chris@0 48 */
Chris@0 49 protected $staticRequirementMap;
Chris@0 50
Chris@0 51 /**
Chris@0 52 * An array to map dynamic requirement keys to service IDs.
Chris@0 53 *
Chris@0 54 * @var array
Chris@0 55 */
Chris@0 56 protected $dynamicRequirementMap;
Chris@0 57
Chris@0 58 /**
Chris@0 59 * {@inheritdoc}
Chris@0 60 */
Chris@0 61 public function addCheckService($service_id, $service_method, array $applies_checks = [], $needs_incoming_request = FALSE) {
Chris@0 62 $this->checkIds[] = $service_id;
Chris@0 63 $this->checkMethods[$service_id] = $service_method;
Chris@0 64 if ($needs_incoming_request) {
Chris@0 65 $this->checksNeedsRequest[$service_id] = $service_id;
Chris@0 66 }
Chris@0 67 foreach ($applies_checks as $applies_check) {
Chris@0 68 $this->staticRequirementMap[$applies_check][] = $service_id;
Chris@0 69 }
Chris@0 70 }
Chris@0 71
Chris@0 72 /**
Chris@0 73 * {@inheritdoc}
Chris@0 74 */
Chris@0 75 public function getChecksNeedRequest() {
Chris@0 76 return $this->checksNeedsRequest;
Chris@0 77 }
Chris@0 78
Chris@0 79 /**
Chris@0 80 * {@inheritdoc}
Chris@0 81 */
Chris@0 82 public function setChecks(RouteCollection $routes) {
Chris@0 83 $this->loadDynamicRequirementMap();
Chris@0 84 foreach ($routes as $route) {
Chris@0 85 if ($checks = $this->applies($route)) {
Chris@0 86 $route->setOption('_access_checks', $checks);
Chris@0 87 }
Chris@0 88 }
Chris@0 89 }
Chris@0 90
Chris@0 91 /**
Chris@0 92 * {@inheritdoc}
Chris@0 93 */
Chris@0 94 public function loadCheck($service_id) {
Chris@0 95 if (empty($this->checks[$service_id])) {
Chris@0 96 if (!in_array($service_id, $this->checkIds)) {
Chris@0 97 throw new \InvalidArgumentException(sprintf('No check has been registered for %s', $service_id));
Chris@0 98 }
Chris@0 99
Chris@0 100 $check = $this->container->get($service_id);
Chris@0 101
Chris@0 102 if (!($check instanceof AccessInterface)) {
Chris@0 103 throw new AccessException('All access checks must implement AccessInterface.');
Chris@0 104 }
Chris@0 105 if (!is_callable([$check, $this->checkMethods[$service_id]])) {
Chris@0 106 throw new AccessException(sprintf('Access check method %s in service %s must be callable.', $this->checkMethods[$service_id], $service_id));
Chris@0 107 }
Chris@0 108
Chris@0 109 $this->checks[$service_id] = $check;
Chris@0 110 }
Chris@0 111 return [$this->checks[$service_id], $this->checkMethods[$service_id]];
Chris@0 112 }
Chris@0 113
Chris@0 114 /**
Chris@0 115 * Determine which registered access checks apply to a route.
Chris@0 116 *
Chris@0 117 * @param \Symfony\Component\Routing\Route $route
Chris@0 118 * The route to get list of access checks for.
Chris@0 119 *
Chris@0 120 * @return array
Chris@0 121 * An array of service ids for the access checks that apply to passed
Chris@0 122 * route.
Chris@0 123 */
Chris@0 124 protected function applies(Route $route) {
Chris@0 125 $checks = [];
Chris@0 126
Chris@0 127 // Iterate through map requirements from appliesTo() on access checkers.
Chris@0 128 // Only iterate through all checkIds if this is not used.
Chris@0 129 foreach ($route->getRequirements() as $key => $value) {
Chris@0 130 if (isset($this->staticRequirementMap[$key])) {
Chris@0 131 foreach ($this->staticRequirementMap[$key] as $service_id) {
Chris@0 132 $checks[] = $service_id;
Chris@0 133 }
Chris@0 134 }
Chris@0 135 }
Chris@0 136 // Finally, see if any dynamic access checkers apply.
Chris@0 137 foreach ($this->dynamicRequirementMap as $service_id) {
Chris@0 138 if ($this->checks[$service_id]->applies($route)) {
Chris@0 139 $checks[] = $service_id;
Chris@0 140 }
Chris@0 141 }
Chris@0 142
Chris@0 143 return $checks;
Chris@0 144 }
Chris@17 145
Chris@0 146 /**
Chris@0 147 * Compiles a mapping of requirement keys to access checker service IDs.
Chris@0 148 */
Chris@0 149 protected function loadDynamicRequirementMap() {
Chris@0 150 if (isset($this->dynamicRequirementMap)) {
Chris@0 151 return;
Chris@0 152 }
Chris@0 153
Chris@0 154 // Set them here, so we can use the isset() check above.
Chris@0 155 $this->dynamicRequirementMap = [];
Chris@0 156
Chris@0 157 foreach ($this->checkIds as $service_id) {
Chris@0 158 if (empty($this->checks[$service_id])) {
Chris@0 159 $this->loadCheck($service_id);
Chris@0 160 }
Chris@0 161
Chris@0 162 // Add the service ID to an array that will be iterated over.
Chris@0 163 if ($this->checks[$service_id] instanceof AccessCheckInterface) {
Chris@0 164 $this->dynamicRequirementMap[] = $service_id;
Chris@0 165 }
Chris@0 166 }
Chris@0 167 }
Chris@0 168
Chris@0 169 }