Added Entity and Entity Reference Revisions which got dropped somewhere along the...
[yaffs-website] / web / modules / contrib / entity / src / QueryAccess / ConditionGroup.php
1 <?php
2
3 namespace Drupal\entity\QueryAccess;
4
5 use Drupal\Core\Cache\Cache;
6 use Drupal\Core\Cache\RefinableCacheableDependencyInterface;
7 use Drupal\Core\Cache\RefinableCacheableDependencyTrait;
8
9 /**
10  * Represents a group of query access conditions.
11  *
12  * Used by query access handlers for filtering lists of entities based on
13  * granted permissions.
14  *
15  * Examples:
16  * @code
17  *   // Filter by node type and uid.
18  *   $condition_group = new ConditionGroup();
19  *   $condition_group->addCondition('type', ['article', 'page']);
20  *   $condition_group->addCondition('uid', '1');
21  *
22  *   // Filter by node type or status.
23  *   $condition_group = new ConditionGroup('OR');
24  *   $condition_group->addCondition('type', ['article', 'page']);
25  *   $condition_group->addCondition('status', '1', '<>');
26  *
27  *   // Nested condition groups: node type AND (uid OR status).
28  *   $condition_group = new ConditionGroup();
29  *   $condition_group->addCondition('type', ['article', 'page']);
30  *   $condition_group->addCondition((new ConditionGroup('OR'))
31  *     ->addCondition('uid', 1)
32  *     ->addCondition('status', '1')
33  *   );
34  * @endcode
35  */
36 final class ConditionGroup implements \Countable, RefinableCacheableDependencyInterface {
37
38   use RefinableCacheableDependencyTrait;
39
40   /**
41    * The conjunction.
42    *
43    * @var string
44    */
45   protected $conjunction;
46
47   /**
48    * The conditions.
49    *
50    * @var \Drupal\entity\QueryAccess\Condition[]|\Drupal\entity\QueryAccess\ConditionGroup[]
51    */
52   protected $conditions = [];
53
54   /**
55    * Whether the condition group is always FALSE.
56    *
57    * @var bool
58    */
59   protected $alwaysFalse = FALSE;
60
61   /**
62    * Constructs a new ConditionGroup object.
63    *
64    * @param string $conjunction
65    *   The conjunction.
66    */
67   public function __construct($conjunction = 'AND') {
68     $this->conjunction = $conjunction;
69   }
70
71   /**
72    * Gets the conjunction.
73    *
74    * @return string
75    *   The conjunction. Possible values: AND, OR.
76    */
77   public function getConjunction() {
78     return $this->conjunction;
79   }
80
81   /**
82    * Gets all conditions and nested condition groups.
83    *
84    * @return \Drupal\entity\QueryAccess\Condition[]|\Drupal\entity\QueryAccess\ConditionGroup[]
85    *   The conditions, where each one is either a Condition or a nested
86    *   ConditionGroup. Returned by reference, to allow callers to replace
87    *   or remove conditions.
88    */
89   public function &getConditions() {
90     return $this->conditions;
91   }
92
93   /**
94    * Adds a condition.
95    *
96    * @param string|\Drupal\entity\QueryAccess\ConditionGroup $field
97    *   Either a condition group (for nested AND/OR conditions), or a
98    *   field name with an optional column name. E.g: 'uid', 'address.locality'.
99    * @param mixed $value
100    *   The value.
101    * @param string $operator
102    *   The operator.
103    *   Possible values: =, <>, <, <=, >, >=, BETWEEN, NOT BETWEEN,
104    *                   IN, NOT IN, IS NULL, IS NOT NULL.
105    *
106    * @return $this
107    */
108   public function addCondition($field, $value = NULL, $operator = NULL) {
109     if ($field instanceof ConditionGroup) {
110       if ($field->count() === 1) {
111         // The condition group only has a single condition, merge it.
112         $this->conditions[] = reset($field->getConditions());
113         $this->addCacheTags($field->getCacheTags());
114         $this->addCacheContexts($field->getCacheContexts());
115         $this->mergeCacheMaxAge($field->getCacheMaxAge());
116       }
117       elseif ($field->count() > 1) {
118         $this->conditions[] = $field;
119       }
120     }
121     else {
122       $this->conditions[] = new Condition($field, $value, $operator);
123     }
124
125     return $this;
126   }
127
128   /**
129    * Gets whether the condition group is always FALSE.
130    *
131    * Used when the user doesn't have access to any entities, to ensure that a
132    * query returns no results.
133    *
134    * @return bool
135    *   Whether the condition group is always FALSE.
136    */
137   public function isAlwaysFalse() {
138     return $this->alwaysFalse;
139   }
140
141   /**
142    * Sets whether the condition group should always be FALSE.
143    *
144    * @param bool $always_false
145    *   Whether the condition group should always be FALSE.
146    *
147    * @return $this
148    */
149   public function alwaysFalse($always_false = TRUE) {
150     $this->alwaysFalse = $always_false;
151     return $this;
152   }
153
154   /**
155    * Clones the contained conditions when the condition group is cloned.
156    */
157   public function __clone() {
158     foreach ($this->conditions as $i => $condition) {
159       $this->conditions[$i] = clone $condition;
160     }
161   }
162
163   /**
164    * Gets the string representation of the condition group.
165    *
166    * @return string
167    *   The string representation of the condition group.
168    */
169   public function __toString() {
170     // Special case for a single, nested condition group:
171     if (count($this->conditions) == 1) {
172       return (string) reset($this->conditions);
173     }
174     $lines = [];
175     foreach ($this->conditions as $condition) {
176       $lines[] = str_replace("\n", "\n  ", (string) $condition);
177     }
178     return $lines ? "(\n  " . implode("\n    {$this->conjunction}\n  ", $lines) . "\n)" : '';
179   }
180
181   /**
182    * {@inheritdoc}
183    */
184   public function count() {
185     return count($this->conditions);
186   }
187
188   /**
189    * {@inheritdoc}
190    */
191   public function getCacheTags() {
192     $tags = $this->cacheTags;
193     foreach ($this->conditions as $condition) {
194       if ($condition instanceof ConditionGroup) {
195         $tags = array_merge($tags, $condition->getCacheTags());
196       }
197     }
198     return Cache::mergeTags($tags, []);
199   }
200
201   /**
202    * {@inheritdoc}
203    */
204   public function getCacheContexts() {
205     $cache_contexts = $this->cacheContexts;
206     foreach ($this->conditions as $condition) {
207       if ($condition instanceof ConditionGroup) {
208         $cache_contexts = array_merge($cache_contexts, $condition->getCacheContexts());
209       }
210     }
211     return Cache::mergeContexts($cache_contexts);
212   }
213
214   /**
215    * {@inheritdoc}
216    */
217   public function getCacheMaxAge() {
218     $max_age = $this->cacheMaxAge;
219     foreach ($this->conditions as $condition) {
220       if ($condition instanceof ConditionGroup) {
221         $max_age = Cache::mergeMaxAges($max_age, $condition->getCacheMaxAge());
222       }
223     }
224     return $max_age;
225   }
226
227 }