Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
98.08% covered (success)
98.08%
51 / 52
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ContactAccessControlHandler
98.08% covered (success)
98.08%
51 / 52
80.00% covered (warning)
80.00%
4 / 5
16
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 createInstance
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 checkAccess
97.06% covered (success)
97.06%
33 / 34
0.00% covered (danger)
0.00%
0 / 1
11
 checkCreateAccess
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
2
 hasUserContactMapping
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace Drupal\crm\Access;
4
5use Drupal\Core\Access\AccessResult;
6use Drupal\Core\Entity\EntityAccessControlHandler;
7use Drupal\Core\Entity\EntityHandlerInterface;
8use Drupal\Core\Entity\EntityInterface;
9use Drupal\Core\Entity\EntityTypeInterface;
10use Drupal\Core\Entity\EntityTypeManagerInterface;
11use Drupal\Core\Session\AccountInterface;
12use Symfony\Component\DependencyInjection\ContainerInterface;
13
14/**
15 * Defines the access control handler for the contact entity type.
16 */
17class ContactAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
18
19  /**
20   * {@inheritdoc}
21   */
22  protected $viewLabelOperation = TRUE;
23
24  /**
25   * The entity type manager.
26   *
27   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
28   */
29  protected EntityTypeManagerInterface $entityTypeManager;
30
31  /**
32   * Constructs a ContactAccessControlHandler object.
33   *
34   * @param \Drupal\Core\Entity\EntityTypeInterface $entity_type
35   *   The entity type definition.
36   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
37   *   The entity type manager.
38   */
39  public function __construct(EntityTypeInterface $entity_type, EntityTypeManagerInterface $entity_type_manager) {
40    parent::__construct($entity_type);
41    $this->entityTypeManager = $entity_type_manager;
42  }
43
44  /**
45   * {@inheritdoc}
46   */
47  public static function createInstance(ContainerInterface $container, EntityTypeInterface $entity_type) {
48    return new static(
49      $entity_type,
50      $container->get('entity_type.manager')
51    );
52  }
53
54  /**
55   * {@inheritdoc}
56   */
57  protected function checkAccess(EntityInterface $entity, $operation, AccountInterface $account) {
58    // Check admin permission first.
59    if ($account->hasPermission($this->entityType->getAdminPermission())) {
60      return AccessResult::allowed()->cachePerPermissions();
61    }
62
63    $bundle = $entity->bundle();
64
65    switch ($operation) {
66      case 'view label':
67        $permissions = ['view any crm_contact label'];
68        $permissions[] = "view any $bundle crm_contact label";
69
70        return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
71
72      case 'view':
73        $permissions = ['view any crm_contact'];
74        $permissions[] = "view any $bundle crm_contact";
75
76        $result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
77        if ($result->isAllowed()) {
78          return $result;
79        }
80
81        // Check for user-contact mapping.
82        if ($this->hasUserContactMapping($entity, $account)) {
83          return AccessResult::allowedIfHasPermission($account, 'view mapped crm_contact')
84            ->addCacheContexts(['user'])
85            ->addCacheTags(['crm_user_contact_mapping_list']);
86        }
87
88        return $result;
89
90      case 'update':
91        $permissions = ['edit any crm_contact'];
92        $permissions[] = "edit any $bundle crm_contact";
93
94        $result = AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
95        if ($result->isAllowed()) {
96          return $result;
97        }
98
99        // Check for user-contact mapping.
100        if ($this->hasUserContactMapping($entity, $account)) {
101          return AccessResult::allowedIfHasPermission($account, 'edit mapped crm_contact')
102            ->addCacheContexts(['user'])
103            ->addCacheTags(['crm_user_contact_mapping_list']);
104        }
105
106        return $result;
107
108      case 'delete':
109        $permissions = ['delete any crm_contact'];
110        $permissions[] = "delete any $bundle crm_contact";
111
112        return AccessResult::allowedIfHasPermissions($account, $permissions, 'OR');
113
114      default:
115        // No opinion.
116        return AccessResult::neutral();
117
118    }
119
120  }
121
122  /**
123   * {@inheritdoc}
124   */
125  protected function checkCreateAccess(AccountInterface $account, array $context, $entity_bundle = NULL) {
126    // Check admin permission first.
127    if ($account->hasPermission($this->entityType->getAdminPermission())) {
128      return AccessResult::allowed()->cachePerPermissions();
129    }
130
131    return AccessResult::allowedIfHasPermissions(
132      $account,
133      ['create crm_contact', "create $entity_bundle crm_contact"],
134      'OR',
135    );
136  }
137
138  /**
139   * Checks if a user has a contact mapping to the given entity.
140   *
141   * @param \Drupal\Core\Entity\EntityInterface $entity
142   *   The contact entity.
143   * @param \Drupal\Core\Session\AccountInterface $account
144   *   The user account.
145   *
146   * @return bool
147   *   TRUE if a mapping exists, FALSE otherwise.
148   */
149  protected function hasUserContactMapping(EntityInterface $entity, AccountInterface $account): bool {
150    $query = $this->entityTypeManager->getStorage('crm_user_contact_mapping')->getQuery();
151    $query->condition('crm_contact', $entity->id());
152    $query->condition('user', $account->id());
153    $result = $query->accessCheck(FALSE)->execute();
154
155    return !empty($result);
156  }
157
158}