Mercurial > hg > cmmr2012-drupal-site
comparison core/modules/jsonapi/src/Query/EntityCondition.php @ 5:12f9dff5fda9 tip
Update to Drupal core 8.7.1
author | Chris Cannam |
---|---|
date | Thu, 09 May 2019 15:34:47 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:a9cd425dd02b | 5:12f9dff5fda9 |
---|---|
1 <?php | |
2 | |
3 namespace Drupal\jsonapi\Query; | |
4 | |
5 use Drupal\Core\Cache\CacheableMetadata; | |
6 use Drupal\Core\Http\Exception\CacheableBadRequestHttpException; | |
7 | |
8 /** | |
9 * A condition object for the EntityQuery. | |
10 * | |
11 * @internal JSON:API maintains no PHP API since its API is the HTTP API. This | |
12 * class may change at any time and this will break any dependencies on it. | |
13 * | |
14 * @see https://www.drupal.org/project/jsonapi/issues/3032787 | |
15 * @see jsonapi.api.php | |
16 */ | |
17 class EntityCondition { | |
18 | |
19 /** | |
20 * The field key in the filter condition: filter[lorem][condition][<field>]. | |
21 * | |
22 * @var string | |
23 */ | |
24 const PATH_KEY = 'path'; | |
25 | |
26 /** | |
27 * The value key in the filter condition: filter[lorem][condition][<value>]. | |
28 * | |
29 * @var string | |
30 */ | |
31 const VALUE_KEY = 'value'; | |
32 | |
33 /** | |
34 * The operator key in the condition: filter[lorem][condition][<operator>]. | |
35 * | |
36 * @var string | |
37 */ | |
38 const OPERATOR_KEY = 'operator'; | |
39 | |
40 /** | |
41 * The allowed condition operators. | |
42 * | |
43 * @var string[] | |
44 */ | |
45 public static $allowedOperators = [ | |
46 '=', '<>', | |
47 '>', '>=', '<', '<=', | |
48 'STARTS_WITH', 'CONTAINS', 'ENDS_WITH', | |
49 'IN', 'NOT IN', | |
50 'BETWEEN', 'NOT BETWEEN', | |
51 'IS NULL', 'IS NOT NULL', | |
52 ]; | |
53 | |
54 /** | |
55 * The field to be evaluated. | |
56 * | |
57 * @var string | |
58 */ | |
59 protected $field; | |
60 | |
61 /** | |
62 * The condition operator. | |
63 * | |
64 * @var string | |
65 */ | |
66 protected $operator; | |
67 | |
68 /** | |
69 * The value against which the field should be evaluated. | |
70 * | |
71 * @var mixed | |
72 */ | |
73 protected $value; | |
74 | |
75 /** | |
76 * Constructs a new EntityCondition object. | |
77 */ | |
78 public function __construct($field, $value, $operator = NULL) { | |
79 $this->field = $field; | |
80 $this->value = $value; | |
81 $this->operator = ($operator) ? $operator : '='; | |
82 } | |
83 | |
84 /** | |
85 * The field to be evaluated. | |
86 * | |
87 * @return string | |
88 * The field upon which to evaluate the condition. | |
89 */ | |
90 public function field() { | |
91 return $this->field; | |
92 } | |
93 | |
94 /** | |
95 * The comparison operator to use for the evaluation. | |
96 * | |
97 * For a list of allowed operators: | |
98 * | |
99 * @see \Drupal\jsonapi\Query\EntityCondition::allowedOperators | |
100 * | |
101 * @return string | |
102 * The condition operator. | |
103 */ | |
104 public function operator() { | |
105 return $this->operator; | |
106 } | |
107 | |
108 /** | |
109 * The value against which the condition should be evaluated. | |
110 * | |
111 * @return mixed | |
112 * The condition comparison value. | |
113 */ | |
114 public function value() { | |
115 return $this->value; | |
116 } | |
117 | |
118 /** | |
119 * Creates an EntityCondition object from a query parameter. | |
120 * | |
121 * @param mixed $parameter | |
122 * The `filter[condition]` query parameter from the request. | |
123 * | |
124 * @return self | |
125 * An EntityCondition object with defaults. | |
126 */ | |
127 public static function createFromQueryParameter($parameter) { | |
128 static::validate($parameter); | |
129 $field = $parameter[static::PATH_KEY]; | |
130 $value = (isset($parameter[static::VALUE_KEY])) ? $parameter[static::VALUE_KEY] : NULL; | |
131 $operator = (isset($parameter[static::OPERATOR_KEY])) ? $parameter[static::OPERATOR_KEY] : NULL; | |
132 return new static($field, $value, $operator); | |
133 } | |
134 | |
135 /** | |
136 * Validates the filter has the required fields. | |
137 */ | |
138 protected static function validate($parameter) { | |
139 $valid_key_combinations = [ | |
140 [static::PATH_KEY, static::VALUE_KEY], | |
141 [static::PATH_KEY, static::OPERATOR_KEY], | |
142 [static::PATH_KEY, static::VALUE_KEY, static::OPERATOR_KEY], | |
143 ]; | |
144 | |
145 $given_keys = array_keys($parameter); | |
146 $valid_key_set = array_reduce($valid_key_combinations, function ($valid, $set) use ($given_keys) { | |
147 return ($valid) ? $valid : count(array_diff($set, $given_keys)) === 0; | |
148 }, FALSE); | |
149 | |
150 $has_operator_key = isset($parameter[static::OPERATOR_KEY]); | |
151 $has_path_key = isset($parameter[static::PATH_KEY]); | |
152 $has_value_key = isset($parameter[static::VALUE_KEY]); | |
153 | |
154 $cacheability = (new CacheableMetadata())->addCacheContexts(['url.query_args:filter']); | |
155 if (!$valid_key_set) { | |
156 // Try to provide a more specific exception is a key is missing. | |
157 if (!$has_operator_key) { | |
158 if (!$has_path_key) { | |
159 throw new CacheableBadRequestHttpException($cacheability, "Filter parameter is missing a '" . static::PATH_KEY . "' key."); | |
160 } | |
161 if (!$has_value_key) { | |
162 throw new CacheableBadRequestHttpException($cacheability, "Filter parameter is missing a '" . static::VALUE_KEY . "' key."); | |
163 } | |
164 } | |
165 | |
166 // Catchall exception. | |
167 $reason = "You must provide a valid filter condition. Check that you have set the required keys for your filter."; | |
168 throw new CacheableBadRequestHttpException($cacheability, $reason); | |
169 } | |
170 | |
171 if ($has_operator_key) { | |
172 $operator = $parameter[static::OPERATOR_KEY]; | |
173 if (!in_array($operator, static::$allowedOperators)) { | |
174 $reason = "The '" . $operator . "' operator is not allowed in a filter parameter."; | |
175 throw new CacheableBadRequestHttpException($cacheability, $reason); | |
176 } | |
177 | |
178 if (in_array($operator, ['IS NULL', 'IS NOT NULL']) && $has_value_key) { | |
179 $reason = "Filters using the '" . $operator . "' operator should not provide a value."; | |
180 throw new CacheableBadRequestHttpException($cacheability, $reason); | |
181 } | |
182 } | |
183 } | |
184 | |
185 } |