ContextAccessCheck::extractContext()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 6
ccs 0
cts 6
cp 0
crap 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace Drupal\paragraphs_editor\Access;
4
5
use Drupal\Core\Access\AccessResult;
6
use Drupal\Core\Entity\EntityTypeManagerInterface;
7
use Drupal\Core\Routing\Access\AccessInterface;
8
use Drupal\Core\Routing\RouteMatchInterface;
9
use Drupal\Core\Session\AccountInterface;
10
use Symfony\Component\Routing\Route;
11
12
/**
13
 * An access check handler for checking user access to an editor context.
14
 */
15
class ContextAccessCheck implements AccessInterface {
16
17
  /**
18
   * The Drupal entity type manager.
19
   *
20
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
21
   */
22
  protected $entityTypeManager;
23
24
  /**
25
   * The key used by the routing requirement.
26
   *
27
   * @var string
28
   */
29
  protected $requirementsKey = '_paragraphs_editor_access_context';
30
31
  /**
32
   * Creates a context access check object.
33
   *
34
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
35
   *   The entity type manager service.
36
   */
37
  public function __construct(EntityTypeManagerInterface $entity_type_manager) {
38
    $this->entityTypeManager = $entity_type_manager;
39
  }
40
41
  /**
42
   * Determines if the user has access to manipulate the requested entity.
43
   *
44
   * In order to perform any command on an editor instance, the user must have
45
   * access to edit the entity the instance is attached to, or for new entities,
46
   * the user must have access to create entities.
47
   *
48
   * This method will also filter out "invalid" context objects before the
49
   * actual controller method that executes the request is called.
50
   *
51
   * @param \Symfony\Component\Routing\Route $route
52
   *   The route the user is attempting to access.
53
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
54
   *   The route match for the route the user is attempting to access.
55
   * @param \Drupal\Core\Session\AccountInterface $account
56
   *   The account to check access against.
57
   *
58
   * @return \Drupal\Core\Access\AccessResultInterface
59
   *   The access result for the user.
60
   */
61
  public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account) {
62
    // Load the context from the parameters.
63
    $requirement = $route->getRequirement($this->requirementsKey);
64
    $ands = explode('+', $requirement);
65
    $chain = [];
66
    foreach ($ands as $requirement) {
67
      $context = static::extractContext($route_match, $requirement);
68
      if (empty($context)) {
69
        return AccessResult::forbidden();
70
      }
71
72
      // If no field config could be loaded for the context, we treat this as
73
      // the user not being able to access the endpoint.
74
      $field_config = $context->getFieldConfig();
75
      if ($field_config) {
76
        $entity_type = $field_config->getTargetEntityTypeId();
77
        $entity_bundle = $field_config->getTargetBundle();
78
        $entity = $context->getEntity();
79
80
        // If the operation pertains to an existing entity, the user must have
81
        // edit access to perform editor commands. If it is a new entity, the
82
        // user must have create access.
83
        if ($entity) {
84
          $chain[] = $entity->access('edit', $account, TRUE);
85
        }
86
        else {
87
          $chain[] = $this->entityTypeManager->getAccessControlHandler($entity_type)
88
            ->createAccess($entity_bundle, $account, [], TRUE);
89
        }
90
      }
91
      else {
92
        return AccessResult::forbidden();
93
      }
94
    }
95
96
    if (!empty($chain)) {
97
      $access = AccessResult::allowed();
98
      foreach ($chain as $next_access) {
99
        $access = $access->andIf($next_access);
100
      }
101
    }
102
    else {
103
      $access = AccessResult::neutral();
104
    }
105
106
    return $access;
107
  }
108
109
  /**
110
   * Extracts the context from a route match, given a requirement.
111
   *
112
   * @param \Drupal\Core\Routing\RouteMatchInterface $route_match
113
   *   The route match for the route the user is attempting to access.
114
   * @param string $requirement
115
   *   The requirement string to get the parameter name from.
116
   *
117
   * @return \Drupal\paragraphs_editor\EditorCommand\CommandContextInterface|null
118
   *   The extracted context id or NULL if none could be extracted.
119
   */
120
  public static function extractContext(RouteMatchInterface $route_match, $requirement) {
121
    if (preg_match('/\{(.*)\}$/', $requirement, $matches)) {
122
      return $route_match->getParameter($matches[1]);
123
    }
124
    else {
125
      return NULL;
126
    }
127
  }
128
129
}
130