These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace Elgg\Database; |
||
3 | |||
4 | use Elgg\Database; |
||
5 | use Elgg\Database\EntityTable; |
||
6 | use Elgg\Cache\PluginSettingsCache; |
||
7 | |||
8 | /** |
||
9 | * Private settings for entities |
||
10 | * |
||
11 | * Private settings provide metadata like storage of settings for plugins |
||
12 | * and users. |
||
13 | * |
||
14 | * WARNING: API IN FLUX. DO NOT USE DIRECTLY. |
||
15 | * |
||
16 | * @access private |
||
17 | * @since 2.0.0 |
||
18 | */ |
||
19 | class PrivateSettingsTable { |
||
20 | |||
21 | /** |
||
22 | * @var Database |
||
23 | */ |
||
24 | protected $db; |
||
25 | |||
26 | /** |
||
27 | * @var EntityTable |
||
28 | */ |
||
29 | protected $entities; |
||
30 | |||
31 | /** |
||
32 | * @var string Name of the database table |
||
33 | */ |
||
34 | protected $table; |
||
35 | |||
36 | /** |
||
37 | * @var PluginSettingsCache cache for settings |
||
38 | */ |
||
39 | protected $cache; |
||
40 | |||
41 | /** |
||
42 | * Constructor |
||
43 | * |
||
44 | * @param Database $db The database |
||
45 | * @param EntityTable $entities Entities table |
||
46 | * @param PluginSettingsCache $cache Settings cache |
||
47 | */ |
||
48 | 197 | public function __construct(Database $db, EntityTable $entities, PluginSettingsCache $cache) { |
|
49 | 197 | $this->db = $db; |
|
50 | 197 | $this->entities = $entities; |
|
51 | 197 | $this->cache = $cache; |
|
52 | 197 | $this->table = $this->db->prefix . 'private_settings'; |
|
53 | 197 | } |
|
54 | |||
55 | /** |
||
56 | * Returns entities based upon private settings |
||
57 | * |
||
58 | * Also accepts all options available to elgg_get_entities(). Supports |
||
59 | * the singular option shortcut. |
||
60 | * |
||
61 | * @param array $options Array in format: |
||
62 | * |
||
63 | * private_setting_names => null|ARR private setting names |
||
64 | * |
||
65 | * private_setting_values => null|ARR metadata values |
||
66 | * |
||
67 | * private_setting_name_value_pairs => null|ARR ( |
||
68 | * name => 'name', |
||
69 | * value => 'value', |
||
70 | * 'operand' => '=', |
||
71 | * ) |
||
72 | * Currently if multiple values are sent via |
||
73 | * an array (value => array('value1', 'value2') |
||
74 | * the pair's operand will be forced to "IN". |
||
75 | * |
||
76 | * private_setting_name_value_pairs_operator => null|STR The operator to |
||
77 | * use for combining |
||
78 | * (name = value) OPERATOR (name = value); |
||
79 | * default AND |
||
80 | * |
||
81 | * private_setting_name_prefix => STR A prefix to apply to all private |
||
82 | * settings. Used to namespace plugin user |
||
83 | * settings or by plugins to namespace their |
||
84 | * own settings. |
||
85 | * |
||
86 | * @return mixed int If count, int. If not count, array. false on errors. |
||
87 | */ |
||
88 | 1 | public function getEntities(array $options = []) { |
|
89 | $defaults = [ |
||
90 | 1 | 'private_setting_names' => ELGG_ENTITIES_ANY_VALUE, |
|
91 | 1 | 'private_setting_values' => ELGG_ENTITIES_ANY_VALUE, |
|
92 | 1 | 'private_setting_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, |
|
93 | 1 | 'private_setting_name_value_pairs_operator' => 'AND', |
|
94 | 1 | 'private_setting_name_prefix' => '', |
|
95 | ]; |
||
96 | |||
97 | 1 | $options = array_merge($defaults, $options); |
|
98 | |||
99 | $singulars = [ |
||
100 | 1 | 'private_setting_name', |
|
101 | 'private_setting_value', |
||
102 | 'private_setting_name_value_pair', |
||
103 | ]; |
||
104 | |||
105 | 1 | $options = _elgg_normalize_plural_options_array($options, $singulars); |
|
106 | |||
107 | 1 | $clauses = $this->getWhereSql('e', |
|
108 | 1 | $options['private_setting_names'], |
|
109 | 1 | $options['private_setting_values'], |
|
110 | 1 | $options['private_setting_name_value_pairs'], |
|
111 | 1 | $options['private_setting_name_value_pairs_operator'], |
|
112 | 1 | $options['private_setting_name_prefix']); |
|
113 | |||
114 | 1 | View Code Duplication | if ($clauses) { |
1 ignored issue
–
show
The expression
$clauses of type array<string,array> is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
115 | // merge wheres to pass to get_entities() |
||
116 | 1 | if (isset($options['wheres']) && !is_array($options['wheres'])) { |
|
117 | $options['wheres'] = [$options['wheres']]; |
||
118 | 1 | } elseif (!isset($options['wheres'])) { |
|
119 | 1 | $options['wheres'] = []; |
|
120 | } |
||
121 | |||
122 | 1 | $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']); |
|
123 | |||
124 | // merge joins to pass to get_entities() |
||
125 | 1 | if (isset($options['joins']) && !is_array($options['joins'])) { |
|
126 | $options['joins'] = [$options['joins']]; |
||
127 | 1 | } elseif (!isset($options['joins'])) { |
|
128 | 1 | $options['joins'] = []; |
|
129 | } |
||
130 | |||
131 | 1 | $options['joins'] = array_merge($options['joins'], $clauses['joins']); |
|
132 | } |
||
133 | |||
134 | 1 | return $this->entities->getEntities($options); |
|
135 | } |
||
136 | |||
137 | /** |
||
138 | * Returns private setting name and value SQL where/join clauses for entities |
||
139 | * |
||
140 | * @param string $table Entities table name |
||
141 | * @param array|null $names Array of names |
||
142 | * @param array|null $values Array of values |
||
143 | * @param array|null $pairs Array of names / values / operands |
||
144 | * @param string $pair_operator Operator for joining pairs where clauses |
||
145 | * @param string $name_prefix A string to prefix all names with |
||
146 | * @return array |
||
147 | */ |
||
148 | 1 | private function getWhereSql($table, $names = null, $values = null, |
|
149 | $pairs = null, $pair_operator = 'AND', $name_prefix = '') { |
||
150 | |||
151 | // @todo short circuit test |
||
152 | |||
153 | $return = [ |
||
154 | 1 | 'joins' => [], |
|
155 | 'wheres' => [], |
||
156 | ]; |
||
157 | |||
158 | 1 | $return['joins'][] = "JOIN {$this->table} ps on |
|
159 | 1 | {$table}.guid = ps.entity_guid"; |
|
160 | |||
161 | 1 | $wheres = []; |
|
162 | |||
163 | // get names wheres |
||
164 | 1 | $names_where = ''; |
|
165 | 1 | View Code Duplication | if ($names !== null) { |
1 ignored issue
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
166 | if (!is_array($names)) { |
||
167 | $names = [$names]; |
||
168 | } |
||
169 | |||
170 | $sanitised_names = []; |
||
171 | foreach ($names as $name) { |
||
172 | $name = $name_prefix . $name; |
||
173 | $sanitised_names[] = '\'' . $this->db->sanitizeString($name) . '\''; |
||
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
174 | } |
||
175 | |||
176 | $names_str = implode(',', $sanitised_names); |
||
177 | if ($names_str) { |
||
178 | $names_where = "(ps.name IN ($names_str))"; |
||
179 | } |
||
180 | } |
||
181 | |||
182 | // get values wheres |
||
183 | 1 | $values_where = ''; |
|
184 | 1 | View Code Duplication | if ($values !== null) { |
1 ignored issue
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
185 | if (!is_array($values)) { |
||
186 | $values = [$values]; |
||
187 | } |
||
188 | |||
189 | $sanitised_values = []; |
||
190 | foreach ($values as $value) { |
||
191 | // normalize to 0 |
||
192 | if (!$value) { |
||
193 | $value = 0; |
||
194 | } |
||
195 | $sanitised_values[] = '\'' . $this->db->sanitizeString($value) . '\''; |
||
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
196 | } |
||
197 | |||
198 | $values_str = implode(',', $sanitised_values); |
||
199 | if ($values_str) { |
||
200 | $values_where = "(ps.value IN ($values_str))"; |
||
201 | } |
||
202 | } |
||
203 | |||
204 | 1 | View Code Duplication | if ($names_where && $values_where) { |
1 ignored issue
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
205 | $wheres[] = "($names_where AND $values_where)"; |
||
206 | 1 | } elseif ($names_where) { |
|
207 | $wheres[] = "($names_where)"; |
||
208 | 1 | } elseif ($values_where) { |
|
209 | $wheres[] = "($values_where)"; |
||
210 | } |
||
211 | |||
212 | // add pairs which must be in arrays. |
||
213 | 1 | if (is_array($pairs)) { |
|
214 | // join counter for incremental joins in pairs |
||
215 | 1 | $i = 1; |
|
216 | |||
217 | // check if this is an array of pairs or just a single pair. |
||
218 | 1 | if (isset($pairs['name']) || isset($pairs['value'])) { |
|
219 | $pairs = [$pairs]; |
||
220 | } |
||
221 | |||
222 | 1 | $pair_wheres = []; |
|
223 | |||
224 | 1 | foreach ($pairs as $index => $pair) { |
|
225 | // @todo move this elsewhere? |
||
226 | // support shortcut 'n' => 'v' method. |
||
227 | 1 | if (!is_array($pair)) { |
|
228 | $pair = [ |
||
229 | 'name' => $index, |
||
230 | 'value' => $pair |
||
231 | ]; |
||
232 | } |
||
233 | |||
234 | // must have at least a name and value |
||
235 | 1 | if (!isset($pair['name']) || !isset($pair['value'])) { |
|
236 | // @todo should probably return false. |
||
237 | continue; |
||
238 | } |
||
239 | |||
240 | 1 | View Code Duplication | if (isset($pair['operand'])) { |
1 ignored issue
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
241 | $operand = $this->db->sanitizeString($pair['operand']); |
||
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
242 | } else { |
||
243 | 1 | $operand = ' = '; |
|
244 | } |
||
245 | |||
246 | // for comparing |
||
247 | 1 | $trimmed_operand = trim(strtolower($operand)); |
|
248 | |||
249 | // if the value is an int, don't quote it because str '15' < str '5' |
||
250 | // if the operand is IN don't quote it because quoting should be done already. |
||
251 | 1 | if (is_numeric($pair['value'])) { |
|
252 | $value = $this->db->sanitizeString($pair['value']); |
||
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
253 | 1 | View Code Duplication | } else if (is_array($pair['value'])) { |
1 ignored issue
–
show
This code seems to be duplicated across your project.
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation. You can also find more detailed suggestions in the “Code” section of your repository.
Loading history...
|
|||
254 | $values_array = []; |
||
255 | |||
256 | foreach ($pair['value'] as $pair_value) { |
||
257 | if (is_numeric($pair_value)) { |
||
258 | $values_array[] = $this->db->sanitizeString($pair_value); |
||
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
259 | } else { |
||
260 | $values_array[] = "'" . $this->db->sanitizeString($pair_value) . "'"; |
||
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
261 | } |
||
262 | } |
||
263 | |||
264 | if ($values_array) { |
||
0 ignored issues
–
show
The expression
$values_array of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
265 | $value = '(' . implode(', ', $values_array) . ')'; |
||
266 | } |
||
267 | |||
268 | // @todo allow support for non IN operands with array of values. |
||
269 | // will have to do more silly joins. |
||
270 | $operand = 'IN'; |
||
271 | 1 | } else if ($trimmed_operand == 'in') { |
|
272 | $value = "({$pair['value']})"; |
||
273 | } else { |
||
274 | 1 | $value = "'" . $this->db->sanitizeString($pair['value']) . "'"; |
|
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
275 | } |
||
276 | |||
277 | 1 | $name = $this->db->sanitizeString($name_prefix . $pair['name']); |
|
0 ignored issues
–
show
The method
Elgg\Database::sanitizeString() has been deprecated with message: Use query parameters where possible
This method has been deprecated. The supplier of the class has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.
Loading history...
|
|||
278 | |||
279 | // @todo The multiple joins are only needed when the operator is AND |
||
280 | 1 | $return['joins'][] = "JOIN {$this->table} ps{$i} |
|
281 | 1 | on {$table}.guid = ps{$i}.entity_guid"; |
|
282 | |||
283 | 1 | $pair_wheres[] = "(ps{$i}.name = '$name' AND ps{$i}.value |
|
284 | 1 | $operand $value)"; |
|
0 ignored issues
–
show
The variable
$value does not seem to be defined for all execution paths leading up to this point.
If you define a variable conditionally, it can happen that it is not defined for all execution paths. Let’s take a look at an example: function myFunction($a) {
switch ($a) {
case 'foo':
$x = 1;
break;
case 'bar':
$x = 2;
break;
}
// $x is potentially undefined here.
echo $x;
}
In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined. Available Fixes
Loading history...
|
|||
285 | |||
286 | 1 | $i++; |
|
287 | } |
||
288 | |||
289 | 1 | $where = implode(" $pair_operator ", $pair_wheres); |
|
290 | 1 | if ($where) { |
|
291 | 1 | $wheres[] = "($where)"; |
|
292 | } |
||
293 | } |
||
294 | |||
295 | 1 | $where = implode(' AND ', $wheres); |
|
296 | 1 | if ($where) { |
|
297 | 1 | $return['wheres'][] = "($where)"; |
|
298 | } |
||
299 | |||
300 | 1 | return $return; |
|
301 | } |
||
302 | |||
303 | /** |
||
304 | * Gets a private setting for an entity |
||
305 | * |
||
306 | * Plugin authors can set private data on entities. By default private |
||
307 | * data will not be searched or exported. |
||
308 | * |
||
309 | * @param int $entity_guid The entity GUID |
||
310 | * @param string $name The name of the setting |
||
311 | * |
||
312 | * @return mixed The setting value, or null if does not exist |
||
313 | */ |
||
314 | 5 | public function get($entity_guid, $name) { |
|
315 | |||
316 | 5 | $values = $this->cache->getAll($entity_guid); |
|
317 | 5 | if (isset($values[$name])) { |
|
318 | return $values[$name]; |
||
319 | } |
||
320 | |||
321 | 5 | if (!$this->entities->exists($entity_guid)) { |
|
322 | return false; |
||
323 | } |
||
324 | |||
325 | $query = " |
||
326 | 5 | SELECT value FROM {$this->table} |
|
327 | WHERE name = :name |
||
328 | AND entity_guid = :entity_guid |
||
329 | "; |
||
330 | $params = [ |
||
331 | 5 | ':entity_guid' => (int) $entity_guid, |
|
332 | 5 | ':name' => (string) $name, |
|
333 | ]; |
||
334 | |||
335 | 5 | $setting = $this->db->getDataRow($query, null, $params); |
|
336 | |||
337 | 5 | if ($setting) { |
|
0 ignored issues
–
show
The expression
$setting of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
338 | 5 | return $setting->value; |
|
339 | } |
||
340 | |||
341 | 3 | return null; |
|
342 | } |
||
343 | |||
344 | /** |
||
345 | * Return an array of all private settings. |
||
346 | * |
||
347 | * @param int $entity_guid The entity GUID |
||
348 | * |
||
349 | * @return string[] empty array if no settings |
||
350 | */ |
||
351 | public function getAll($entity_guid) { |
||
352 | if (!$this->entities->exists($entity_guid)) { |
||
353 | return []; |
||
354 | } |
||
355 | |||
356 | $query = " |
||
357 | SELECT * FROM {$this->table} |
||
358 | WHERE entity_guid = :entity_guid |
||
359 | "; |
||
360 | $params = [ |
||
361 | ':entity_guid' => (int) $entity_guid, |
||
362 | ]; |
||
363 | |||
364 | $result = $this->db->getData($query, null, $params); |
||
365 | |||
366 | $return = []; |
||
367 | |||
368 | if ($result) { |
||
0 ignored issues
–
show
The expression
$result of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent. Consider making the comparison explicit by using
Loading history...
|
|||
369 | foreach ($result as $r) { |
||
370 | $return[$r->name] = $r->value; |
||
371 | } |
||
372 | } |
||
373 | |||
374 | return $return; |
||
375 | } |
||
376 | |||
377 | /** |
||
378 | * Sets a private setting for an entity. |
||
379 | * |
||
380 | * @param int $entity_guid The entity GUID |
||
381 | * @param string $name The name of the setting |
||
382 | * @param string $value The value of the setting |
||
383 | * @return bool |
||
384 | */ |
||
385 | 5 | public function set($entity_guid, $name, $value) { |
|
386 | 5 | $this->cache->clear($entity_guid); |
|
387 | 5 | _elgg_services()->boot->invalidateCache(); |
|
388 | |||
389 | 5 | if (!$this->entities->exists($entity_guid)) { |
|
390 | return false; |
||
391 | } |
||
392 | |||
393 | $query = " |
||
394 | 5 | INSERT into {$this->table} |
|
395 | (entity_guid, name, value) VALUES |
||
396 | (:entity_guid, :name, :value) |
||
397 | ON DUPLICATE KEY UPDATE value = :value |
||
398 | "; |
||
399 | $params = [ |
||
400 | 5 | ':entity_guid' => (int) $entity_guid, |
|
401 | 5 | ':name' => (string) $name, |
|
402 | 5 | ':value' => (string) $value, |
|
403 | ]; |
||
404 | |||
405 | 5 | $result = $this->db->insertData($query, $params); |
|
406 | |||
407 | 5 | return $result !== false; |
|
408 | } |
||
409 | |||
410 | /** |
||
411 | * Deletes a private setting for an entity. |
||
412 | * |
||
413 | * @param int $entity_guid The Entity GUID |
||
414 | * @param string $name The name of the setting |
||
415 | * @return bool |
||
416 | */ |
||
417 | View Code Duplication | public function remove($entity_guid, $name) { |
|
418 | $this->cache->clear($entity_guid); |
||
419 | _elgg_services()->boot->invalidateCache(); |
||
420 | |||
421 | $query = " |
||
422 | DELETE FROM {$this->table} |
||
423 | WHERE name = :name |
||
424 | AND entity_guid = :entity_guid |
||
425 | "; |
||
426 | $params = [ |
||
427 | ':entity_guid' => (int) $entity_guid, |
||
428 | ':name' => (string) $name, |
||
429 | ]; |
||
430 | |||
431 | return $this->db->deleteData($query, $params); |
||
432 | } |
||
433 | |||
434 | /** |
||
435 | * Deletes all private settings for an entity |
||
436 | * |
||
437 | * @param int $entity_guid The Entity GUID |
||
438 | * @return bool |
||
439 | */ |
||
440 | View Code Duplication | public function removeAllForEntity($entity_guid) { |
|
441 | $this->cache->clear($entity_guid); |
||
442 | _elgg_services()->boot->invalidateCache(); |
||
443 | |||
444 | $query = " |
||
445 | DELETE FROM {$this->table} |
||
446 | WHERE entity_guid = :entity_guid |
||
447 | "; |
||
448 | $params = [ |
||
449 | ':entity_guid' => (int) $entity_guid, |
||
450 | ]; |
||
451 | |||
452 | return $this->db->deleteData($query, $params); |
||
453 | } |
||
454 | |||
455 | } |
||
456 |
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.