Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / web / modules / contrib / permissions_by_term / modules / permissions_by_entity / src / Service / AccessChecker.php
1 <?php
2
3 namespace Drupal\permissions_by_entity\Service;
4
5 use Drupal\Core\Database\Connection;
6 use Drupal\Core\Entity\FieldableEntityInterface;
7 use Drupal\Core\Entity\EntityManagerInterface;
8 use Drupal\permissions_by_entity\Event\EntityFieldValueAccessDeniedEvent;
9 use Drupal\permissions_by_entity\Event\PermissionsByEntityEvents;
10 use Drupal\permissions_by_term\Service\AccessCheck;
11 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
12
13 /**
14  * Class AccessChecker.
15  *
16  * @package Drupal\permissions_by_entity\Service
17  */
18 class AccessChecker extends AccessCheck implements AccessCheckerInterface {
19
20   /**
21    * The event dispatcher.
22    *
23    * @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
24    */
25   private $eventDispatcher;
26
27   /**
28    * The cache for checked entities.
29    *
30    * @var \Drupal\permissions_by_entity\Service\CheckedEntityCache
31    */
32   private $checkedEntityCache;
33
34   /**
35    * The entity field value access denied event.
36    *
37    * @var \Drupal\permissions_by_entity\Event\EntityFieldValueAccessDeniedEvent
38    */
39   private $event;
40
41   /**
42    * AccessChecker constructor.
43    *
44    * We override the constructor, because we do not need the entity manager.
45    *
46    * @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
47    *   The event dispatcher.
48    * @param \Drupal\permissions_by_entity\Service\CheckedEntityCache $checked_entity_cache
49    *   The cache for checked entities.
50    * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager
51    *   The core entity type manager.
52    * @param \Drupal\Core\Database\Connection $database
53    *   The database connection.
54    */
55   public function __construct(
56     EventDispatcherInterface $event_dispatcher,
57     CheckedEntityCache $checked_entity_cache,
58     EntityManagerInterface $entity_manager,
59     Connection $database
60   ) {
61     parent::__construct($database, $event_dispatcher);
62     $this->eventDispatcher = $event_dispatcher;
63     $this->checkedEntityCache = $checked_entity_cache;
64
65     $this->event = new EntityFieldValueAccessDeniedEvent();
66   }
67
68   /**
69    * {@inheritdoc}
70    */
71   public function isAccessAllowed(FieldableEntityInterface $entity, $uid = FALSE) {
72     // Iterate over the fields the entity contains.
73     foreach ($entity->getFields() as $field) {
74
75       // We only need to check for entity reference fields
76       // which references to a taxonomy term.
77       if (
78         $field->getFieldDefinition()->getType() == 'entity_reference' &&
79         $field->getFieldDefinition()->getSetting('target_type') == 'taxonomy_term'
80       ) {
81
82         // Iterate over each referenced taxonomy term.
83         /** @var \Drupal\Core\Field\FieldItemInterface $item */
84         foreach ($field->getValue() as $item) {
85           // Let "Permissions By Term" do the actual check.
86           if (
87             !empty($item['target_id']) &&
88             !$this->isAccessAllowedByDatabase($item['target_id'], $uid, $entity->language()->getId())
89           ) {
90             // Return that the user is not allowed to access this entity.
91             return FALSE;
92           }
93         }
94       }
95
96       // Check if the field contains another fieldable entity,
97       // that we need to check.
98       if ($field->entity && $field->entity instanceof FieldableEntityInterface) {
99
100         // We need to iterate over the entities.
101         $num_values = $field->count();
102         if ($num_values > 0) {
103
104           // Iterate over the field values.
105           for ($i = 0; $i < $num_values; $i++) {
106
107             // Get the value of the current field index.
108             $field_value = $field->get($i);
109
110             // If the value is null or empty we continue with the next index of
111             // the loop.
112             if (!$field_value) {
113               continue;
114             }
115
116             // Get the field entity.
117             $field_entity = $field_value->entity;
118
119             // If the field entity is null we also continue with the next index
120             // of the loop.
121             if (!$field_entity) {
122               continue;
123             }
124
125             // It is possible, that the referenced field entity creates a
126             // circular dependency to the current entity. This will cause
127             // memory limit exhausted errors because there is no way out for
128             // the script. To avoid this, we need to be able to imagine if we
129             // already checked this field entity before. If so, we ignore this
130             // field entity, if not we can securely do a recursive call.
131             //
132             // Using own method to avoid "max nesting level error" trying to
133             // check if the field entity is stored in the entitiesChecked array.
134             if ($this->checkedEntityCache->isChecked($field_entity)) {
135               continue;
136             }
137             else {
138               // Add the current entity to the list of checked entities.
139               $this->checkedEntityCache->add($field_entity);
140             }
141
142             // Do a recursive call to check if the user is allowed to access
143             // this entity.
144             if (!$this->isAccessAllowed($field_entity, $uid)) {
145
146               // Dispatch an event to allow subscribers
147               // to do something in this case.
148               $this->event->setIndex($i);
149               $this->event->setField($field);
150               $this->event->setEntity($field_entity);
151               $this->event->setUid($uid);
152
153               $this->eventDispatcher
154                 ->dispatch(
155                   PermissionsByEntityEvents::ENTITY_FIELD_VALUE_ACCESS_DENIED_EVENT,
156                   $this->event
157                 );
158               $i = $this->event->getIndex();
159             }
160           }
161         }
162       }
163     }
164
165     return TRUE;
166   }
167
168 }