Elgg  Version master
LegacyQueryOptionsAdapter.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use Elgg\Config;
19 
26 
34  public function normalizeOptions(array $options = []): array {
35 
36  if (!isset($options['__original_options'])) {
37  $options['__original_options'] = $options;
38  }
39 
40  $options = array_merge($this->getDefaults(), $options);
41 
42  $options = $this->normalizeGuidOptions($options);
43  $options = $this->normalizeTimeOptions($options);
44  $options = $this->normalizeAccessOptions($options);
45  $options = $this->normalizeTypeSubtypeOptions($options);
46  $options = $this->normalizeRelationshipOptions($options);
47  $options = $this->normalizeAnnotationOptions($options);
48  $options = $this->normalizeMetadataOptions($options);
49  $options = $this->normalizeMetadataSearchOptions($options);
50  $options = $this->normalizeSelectClauses($options);
51  $options = $this->normalizeWhereClauses($options);
52  $options = $this->normalizeJoinClauses($options);
53  $options = $this->normalizeGroupByClauses($options);
54  $options = $this->normalizeHavingClauses($options);
55  $options = $this->normalizeOrderByClauses($options);
56 
57  return $options;
58  }
59 
65  protected function getDefaults(): array {
66  return [
67  'types' => null,
68  'subtypes' => null,
69  'type_subtype_pairs' => null,
70  'guids' => null,
71  'owner_guids' => null,
72  'container_guids' => null,
73  'access_ids' => null,
74 
75  'created_after' => null,
76  'created_before' => null,
77  'updated_after' => null,
78  'updated_before' => null,
79  'last_action_after' => null,
80  'last_action_before' => null,
81 
82  'sort_by' => [],
83  'order_by' => null,
84  'count' => false,
85  'limit' => elgg_get_config('default_limit'),
86  'offset' => 0,
87 
88  'selects' => [],
89  'wheres' => [],
90  'joins' => [],
91  'having' => null,
92  'group_by' => null,
93 
94  'metadata_name_value_pairs' => null,
95  'metadata_name_value_pairs_operator' => 'AND',
96  'metadata_case_sensitive' => true,
97  'metadata_ids' => null,
98  'metadata_created_time_lower' => null,
99  'metadata_created_time_upper' => null,
100  'metadata_calculation' => null,
101 
102  'search_name_value_pairs' => null,
103 
104  'annotation_names' => null,
105  'annotation_values' => null,
106  'annotation_name_value_pairs' => null,
107  'annotation_name_value_pairs_operator' => 'AND',
108  'annotation_case_sensitive' => true,
109  'annotation_ids' => null,
110  'annotation_created_time_lower' => null,
111  'annotation_created_time_upper' => null,
112  'annotation_owner_guids' => null,
113  'annotation_calculation' => null,
114 
115  'relationship_pairs' => [],
116 
117  'relationship' => null,
118  'relationship_guid' => null,
119  'inverse_relationship' => false,
120  'relationship_join_on' => 'guid',
121  'relationship_created_time_lower' => null,
122  'relationship_created_time_upper' => null,
123 
124  'preload_owners' => false,
125  'preload_containers' => false,
126  'callback' => null,
127  'distinct' => true,
128 
129  'batch' => false,
130  'batch_inc_offset' => true,
131  'batch_size' => 25,
132 
133  '__ElggBatch' => null,
134  ];
135  }
136 
144  protected function normalizeAccessOptions(array $options = []): array {
145  return $this->normalizePluralOptions($options, ['access_id']);
146  }
147 
156  protected function normalizeTypeSubtypeOptions(array $options = []): array {
157  $options = $this->normalizePluralOptions($options, [
158  'type',
159  'subtype',
160  ]);
161 
162  // can't use helper function with type_subtype_pair because
163  // it's already an array...just need to merge it
164  if (isset($options['type_subtype_pair']) && isset($options['type_subtype_pairs'])) {
165  $options['type_subtype_pairs'] = array_merge((array) $options['type_subtype_pairs'], (array) $options['type_subtype_pair']);
166  } else if (isset($options['type_subtype_pair'])) {
167  $options['type_subtype_pairs'] = (array) $options['type_subtype_pair'];
168  } else if (isset($options['type_subtype_pairs'])) {
169  $options['type_subtype_pairs'] = (array) $options['type_subtype_pairs'];
170  } else if (isset($options['types'])) {
171  $options['type_subtype_pairs'] = [];
172  if ($options['types']) {
173  foreach ((array) $options['types'] as $type) {
174  $options['type_subtype_pairs'][$type] = isset($options['subtypes']) ? (array) $options['subtypes'] : null;
175  }
176  }
177  } else if (isset($options['subtypes'])) {
178  throw new InvalidArgumentException('If filtering for entity subtypes it is required to provide one or more entity types.');
179  }
180 
181  if (isset($options['type_subtype_pairs']) && is_array($options['type_subtype_pairs'])) {
182  foreach ($options['type_subtype_pairs'] as $type => $subtypes) {
183  if (!in_array($type, Config::ENTITY_TYPES)) {
184  elgg_log("'$type' is not a valid entity type", 'WARNING');
185  }
186 
187  if (!empty($subtypes) && !is_array($subtypes)) {
188  $options['type_subtype_pairs'][$type] = [$subtypes];
189  }
190  }
191  }
192 
193  unset($options['type_subtype_pair']);
194  unset($options['types']);
195  unset($options['subtypes']);
196 
197  return $options;
198  }
199 
207  protected function normalizeMetadataOptions(array $options = []): array {
208  $options = $this->normalizePluralOptions($options, [
209  'metadata_id',
210  'metadata_name',
211  'metadata_value',
212  'metadata_name_value_pair',
213  ]);
214 
215  $options = $this->normalizePairedOptions('metadata', $options);
216 
217  $props = [
218  'metadata_ids',
219  'metadata_created_after',
220  'metadata_created_before',
221  ];
222 
223  foreach ($props as $prop) {
224  if (isset($options[$prop]) && empty($options['metadata_name_value_pairs'])) {
225  $options['metadata_name_value_pairs'][] = [
226  $prop => $options[$prop]
227  ];
228  }
229  }
230 
231  foreach ($options['metadata_name_value_pairs'] as $key => $pair) {
232  if ($pair instanceof Clause) {
233  continue;
234  }
235 
236  foreach ($props as $prop) {
237  if (!isset($pair[$prop])) {
238  $options['metadata_name_value_pairs'][$key][$prop] = elgg_extract($prop, $options);
239  }
240  }
241 
242  $options['metadata_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
243  }
244 
245  $options['metadata_name_value_pairs'] = $this->removeKeyPrefix('metadata_', $options['metadata_name_value_pairs']);
246 
247  $defaults = [
248  'name' => null,
249  'value' => null,
250  'comparison' => '=',
251  'type' => ELGG_VALUE_STRING,
252  'case_sensitive' => true,
253  'entity_guids' => null,
254  'ids' => null,
255  'created_after' => null,
256  'created_before' => null,
257  ];
258 
259  foreach ($options['metadata_name_value_pairs'] as $key => $pair) {
260  if ($pair instanceof WhereClause) {
261  continue;
262  }
263 
264  $pair = array_merge($defaults, $pair);
265 
266  if (in_array($pair['name'], \ElggEntity::PRIMARY_ATTR_NAMES)) {
267  $clause = new AttributeWhereClause();
268  } else {
269  $clause = new MetadataWhereClause();
270  $clause->ids = (array) $pair['ids'];
271  $clause->entity_guids = (array) $pair['entity_guids'];
272  $clause->created_after = $pair['created_after'];
273  $clause->created_before = $pair['created_before'];
274  }
275 
276  $clause->names = (array) $pair['name'];
277  $clause->values = (array) $pair['value'];
278  $clause->comparison = $pair['comparison'];
279  $clause->value_type = $pair['type'];
280  $clause->case_sensitive = $pair['case_sensitive'];
281 
282  $options['metadata_name_value_pairs'][$key] = $clause;
283  }
284 
285  return $options;
286  }
287 
296  protected function normalizeMetadataSearchOptions(array $options = []): array {
297  $options = $this->normalizePluralOptions($options, ['search_name_value_pair']);
298 
299  $options = $this->normalizePairedOptions('search', $options);
300 
301  foreach ($options['search_name_value_pairs'] as $key => $pair) {
302  if ($pair instanceof Clause) {
303  continue;
304  }
305 
306  $options['search_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
307  }
308 
309  $options['search_name_value_pairs'] = $this->removeKeyPrefix('metadata_', $options['search_name_value_pairs']);
310 
311  $defaults = [
312  'name' => null,
313  'value' => null,
314  'comparison' => '=',
315  'type' => ELGG_VALUE_STRING,
316  'case_sensitive' => true,
317  'entity_guids' => null,
318  'ids' => null,
319  'created_after' => null,
320  'created_before' => null,
321  ];
322 
323  foreach ($options['search_name_value_pairs'] as $key => $pair) {
324  if ($pair instanceof WhereClause) {
325  continue;
326  }
327 
328  $pair = array_merge($defaults, $pair);
329 
330  if (in_array($pair['name'], \ElggEntity::PRIMARY_ATTR_NAMES)) {
331  $clause = new AttributeWhereClause();
332  } else {
333  $clause = new MetadataWhereClause();
334  $clause->ids = (array) $pair['ids'];
335  $clause->entity_guids = (array) $pair['entity_guids'];
336  $clause->created_after = $pair['created_after'];
337  $clause->created_before = $pair['created_before'];
338  }
339 
340  $clause->names = (array) $pair['name'];
341  $clause->values = (array) $pair['value'];
342  $clause->comparison = $pair['comparison'];
343  $clause->value_type = $pair['type'];
344  $clause->case_sensitive = $pair['case_sensitive'];
345 
346  $options['search_name_value_pairs'][$key] = $clause;
347  }
348 
349  return $options;
350  }
351 
359  protected function normalizeAnnotationOptions(array $options = []): array {
360  $options = $this->normalizePluralOptions($options, [
361  'annotation_id',
362  'annotation_name',
363  'annotation_value',
364  'annotation_name_value_pair',
365  ]);
366 
367  $options = $this->normalizePairedOptions('annotation', $options);
368 
369  $props = [
370  'annotation_ids',
371  'annotation_owner_guids',
372  'annotation_created_after',
373  'annotation_created_before',
374  'annotation_sort_by_calculation',
375  ];
376 
377  foreach ($props as $prop) {
378  if (isset($options[$prop]) && empty($options['annotation_name_value_pairs'])) {
379  $options['annotation_name_value_pairs'][] = [
380  $prop => $options[$prop]
381  ];
382  }
383  }
384 
385  foreach ($options['annotation_name_value_pairs'] as $key => $pair) {
386  if ($pair instanceof WhereClause) {
387  continue;
388  }
389 
390  foreach ($props as $prop) {
391  if (!isset($pair[$prop])) {
392  $options['annotation_name_value_pairs'][$key][$prop] = elgg_extract($prop, $options);
393  }
394  }
395 
396  $options['annotation_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
397  }
398 
399  $options['annotation_name_value_pairs'] = $this->removeKeyPrefix('annotation_', $options['annotation_name_value_pairs']);
400 
401  $defaults = [
402  'name' => null,
403  'value' => null,
404  'comparison' => '=',
405  'type' => ELGG_VALUE_STRING,
406  'case_sensitive' => true,
407  'entity_guids' => null,
408  'owner_guids' => null,
409  'ids' => null,
410  'enabled' => null,
411  'access_ids' => null,
412  'created_after' => null,
413  'created_before' => null,
414  'sort_by_calculation' => null,
415  ];
416 
417  foreach ($options['annotation_name_value_pairs'] as $key => $pair) {
418  if ($pair instanceof WhereClause) {
419  continue;
420  }
421 
422  $pair = array_merge($defaults, $pair);
423 
424  $clause = new AnnotationWhereClause();
425  $clause->ids = (array) $pair['ids'];
426  $clause->entity_guids = (array) $pair['entity_guids'];
427  $clause->owner_guids = (array) $pair['owner_guids'];
428  $clause->created_after = $pair['created_after'];
429  $clause->created_before = $pair['created_before'];
430  $clause->names = (array) $pair['name'];
431  $clause->values = (array) $pair['value'];
432  $clause->comparison = $pair['comparison'];
433  $clause->value_type = $pair['type'];
434  $clause->case_sensitive = $pair['case_sensitive'];
435  $clause->access_ids = (array) $pair['access_ids'];
436  $clause->sort_by_calculation = $pair['sort_by_calculation'];
437 
438  if ($clause->sort_by_calculation && empty($options['order_by'])) {
439  $clause->sort_by_direction = 'desc';
440  }
441 
442  $options['annotation_name_value_pairs'][$key] = $clause;
443  }
444 
445  return $options;
446  }
447 
456  protected function normalizePairedOptions($type = 'metadata', array $options = []): array {
457  if (!is_array($options["{$type}_name_value_pairs"])) {
458  $options["{$type}_name_value_pairs"] = [];
459  }
460 
461  $case_sensitive_default = elgg_extract("{$type}_case_sensitive", $options, true);
462 
471  if (isset($options["{$type}_name_value_pairs"]['name'])) {
472  $options["{$type}_name_value_pairs"][] = [
473  'name' => $options["{$type}_name_value_pairs"]['name'],
474  'value' => elgg_extract('value', $options["{$type}_name_value_pairs"]),
475  'comparison' => elgg_extract('operand', $options["{$type}_name_value_pairs"], '='),
476  'case_sensitive' => elgg_extract('case_sensitive', $options["{$type}_name_value_pairs"], $case_sensitive_default)
477  ];
478 
479  unset($options["{$type}_name_value_pairs"]['name']);
480  unset($options["{$type}_name_value_pairs"]['value']);
481  unset($options["{$type}_name_value_pairs"]['operand']);
482  unset($options["{$type}_name_value_pairs"]['case_sensitive']);
483  }
484 
496  foreach ($options["{$type}_name_value_pairs"] as $index => $pair) {
497  if (is_array($pair)) {
498  $keys = array_keys($pair);
499  if (count($keys) === 1 && is_string($keys[0]) && $keys[0] !== 'name' && $keys[0] !== 'value') {
500  $options["{$type}_name_value_pairs"][$index] = [
501  'name' => $keys[0],
502  'value' => $pair[$keys[0]],
503  'comparison' => '=',
504  ];
505  }
506  }
507  }
508 
516  foreach ($options["{$type}_name_value_pairs"] as $index => $values) {
517  if ($values instanceof Clause) {
518  continue;
519  }
520 
521  if (is_array($values)) {
522  if (isset($values['name']) || isset($values['value'])) {
523  continue;
524  }
525  }
526 
527  $options["{$type}_name_value_pairs"][$index] = [
528  'name' => $index,
529  'value' => $values,
530  'comparison' => '=',
531  ];
532  }
533 
534  if (isset($options["{$type}_names"]) || isset($options["{$type}_values"])) {
535  $options["{$type}_name_value_pairs"][] = [
536  'name' => isset($options["{$type}_names"]) ? (array) $options["{$type}_names"] : null,
537  'value' => isset($options["{$type}_values"]) ? (array) $options["{$type}_values"] : null,
538  'comparison' => '=',
539  ];
540  }
541 
542  foreach ($options["{$type}_name_value_pairs"] as $key => $value) {
543  if ($value instanceof Clause) {
544  continue;
545  }
546 
547  if (!isset($value['case_sensitive'])) {
548  $value['case_sensitive'] = $case_sensitive_default;
549  }
550 
551  if (!isset($value['type'])) {
552  if (isset($value['value']) && is_bool($value['value'])) {
553  $value['value'] = (int) $value['value'];
554  }
555 
556  if (isset($value['value']) && is_int($value['value'])) {
557  $value['type'] = ELGG_VALUE_INTEGER;
558  } else {
559  $value['type'] = ELGG_VALUE_STRING;
560  }
561  }
562 
563  if (!isset($value['comparison']) && isset($value['operand'])) {
564  $value['comparison'] = $value['operand'];
565  unset($value['operand']);
566  }
567 
568  $options["{$type}_name_value_pairs"][$key] = $value;
569  }
570 
571  unset($options["{$type}_names"]);
572  unset($options["{$type}_values"]);
573  unset($options["{$type}_case_sensitive"]);
574 
575  return $options;
576  }
577 
585  protected function normalizeRelationshipOptions(array $options = []): array {
586  $defaults = [
587  'relationship_ids' => null,
588  'relationship' => null,
589  'relationship_guid' => null,
590  'inverse_relationship' => false,
591  'relationship_join_on' => 'guid',
592  'relationship_created_after' => null,
593  'relationship_created_before' => null,
594  ];
595 
596  $simple_pair = [];
597  foreach (array_keys($defaults) as $prop) {
598  if (isset($options[$prop])) {
599  $simple_pair[$prop] = $options[$prop];
600  }
601 
602  unset($options[$prop]);
603  }
604 
605  $options['relationship_pairs'] = (array) $options['relationship_pairs'];
606  $options['relationship_pairs'][] = $simple_pair;
607 
608  foreach ($options['relationship_pairs'] as $index => $relationship_pair) {
609  if ($relationship_pair instanceof WhereClause) {
610  continue;
611  }
612 
613  $options['relationship_pairs'][$index] = array_merge($defaults, $relationship_pair);
614  }
615 
616  $options['relationship_pairs'] = $this->removeKeyPrefix('relationship_', $options['relationship_pairs']);
617 
618  foreach ($options['relationship_pairs'] as $key => $pair) {
619  if ($pair instanceof WhereClause) {
620  continue;
621  }
622 
623  if (!$pair['relationship'] && !$pair['guid'] && !$pair['ids']) {
624  unset($options['relationship_pairs'][$key]);
625  continue;
626  }
627 
628  $clause = new RelationshipWhereClause();
629  $clause->ids = (array) $pair['ids'];
630  $clause->names = (array) $pair['relationship'];
631 
632  $clause->join_on = $pair['join_on'];
633  $clause->inverse = $pair['inverse_relationship'];
634  if ($clause->inverse) {
635  $clause->object_guids = (array) $pair['guid'];
636  } else {
637  $clause->subject_guids = (array) $pair['guid'];
638  }
639 
640  $clause->created_after = $pair['created_after'];
641  $clause->created_before = $pair['created_before'];
642 
643 
644  $options['relationship_pairs'][$key] = $clause;
645  }
646 
647  return $options;
648  }
649 
657  protected function normalizeGuidOptions(array $options = []): array {
658  $options = $this->normalizePluralOptions($options, [
659  'guid',
660  'owner_guid',
661  'container_guid',
662  'annotation_owner_guid',
663  ]);
664 
665  $names = [
666  'guids',
667  'owner_guids',
668  'container_guids',
669  'annotation_owner_guids',
670  'relationship_guid',
671  ];
672 
673  foreach ($names as $name) {
674  if (!isset($options[$name])) {
675  continue;
676  }
677 
678  if (!is_array($options[$name])) {
680  }
681 
682  foreach ($options[$name] as $key => $value) {
683  if ($value === false || $value === '') {
684  unset($options[$name][$key]);
685  }
686  }
687  }
688 
689  return $options;
690  }
691 
699  protected function normalizeTimeOptions(array $options = []): array {
700  $props = [
701  'modified',
702  'created',
703  'updated',
704  'metadata_created',
705  'annotation_created',
706  'relationship_created',
707  'last_action',
708  'posted',
709  ];
710 
711  $bounds = ['time_lower', 'time_upper', 'after', 'before'];
712 
713  foreach ($props as $prop) {
714  foreach ($bounds as $bound) {
715  $prop_name = "{$prop}_{$bound}";
716 
717  $new_prop_name = $prop_name;
718  $new_prop_name = str_replace('modified', 'updated', $new_prop_name);
719  $new_prop_name = str_replace('posted', 'created', $new_prop_name);
720  $new_prop_name = str_replace('time_lower', 'after', $new_prop_name);
721  $new_prop_name = str_replace('time_upper', 'before', $new_prop_name);
722 
723  if (!isset($options[$new_prop_name])) {
724  $options[$new_prop_name] = elgg_extract($prop_name, $options);
725  }
726  }
727  }
728 
729  return $options;
730  }
731 
740  protected function removeKeyPrefix(string $prefix, array $array = []): array {
741  foreach ($array as $key => $value) {
742  $new_key = $key;
743  if (str_starts_with($key, $prefix)) {
744  $new_key = substr($key, strlen($prefix));
745  }
746 
747  if (!isset($array[$new_key])) {
748  $array[$new_key] = $value;
749  }
750 
751  if ($new_key !== $key) {
752  unset($array[$key]);
753  }
754 
755  if (is_array($array[$new_key])) {
756  $array[$new_key] = $this->removeKeyPrefix($prefix, $array[$new_key]);
757  }
758  }
759 
760  return $array;
761  }
762 
770  protected function normalizeSelectClauses(array $options = []): array {
771  $options = $this->normalizePluralOptions($options, ['select']);
772 
773  if (empty($options['selects'])) {
774  $options['selects'] = [];
775 
776  return $options;
777  }
778 
779  if (!is_array($options['selects'])) {
780  $options['selects'] = [$options['selects']];
781  }
782 
783  foreach ($options['selects'] as $key => $clause) {
784  if (empty($clause)) {
785  unset($options['selects'][$key]);
786  continue;
787  }
788 
789  if ($clause instanceof SelectClause) {
790  continue;
791  }
792 
793  $options['selects'][$key] = new SelectClause($clause);
794  }
795 
796  return $options;
797  }
798 
806  protected function normalizeWhereClauses(array $options = []): array {
807  $options = $this->normalizePluralOptions($options, ['where']);
808 
809  if (empty($options['wheres'])) {
810  $options['wheres'] = [];
811 
812  return $options;
813  }
814 
815  if (!is_array($options['wheres'])) {
816  $options['wheres'] = [$options['wheres']];
817  }
818 
819  foreach ($options['wheres'] as $key => $clause) {
820  if (empty($clause)) {
821  unset($options['wheres'][$key]);
822  continue;
823  }
824 
825  if ($clause instanceof WhereClause) {
826  continue;
827  }
828 
829  $options['wheres'][$key] = new WhereClause($clause);
830  }
831 
832  return $options;
833  }
834 
842  protected function normalizeJoinClauses(array $options = []): array {
843  $options = $this->normalizePluralOptions($options, ['join']);
844 
845  if (empty($options['joins'])) {
846  $options['joins'] = [];
847 
848  return $options;
849  }
850 
851  if (!is_array($options['joins'])) {
852  $options['joins'] = [$options['joins']];
853  }
854 
855  foreach ($options['joins'] as $key => $join) {
856  if (empty($join)) {
857  unset($options['joins'][$key]);
858  continue;
859  }
860 
861  if ($join instanceof JoinClause) {
862  continue;
863  }
864 
865  if (is_string($join)) {
866  preg_match('/((LEFT|INNER|RIGHT)\s+)?JOIN\s+(.*?)\s+((as\s+)?(.*?)\s+)ON\s+(.*)$/im', $join, $parts);
867 
868  $type = !empty($parts[2]) ? strtolower($parts[2]) : 'inner';
869  $table = $parts[3];
870  $alias = $parts[6];
871  $condition = preg_replace('/\r|\n/', '', $parts[7]);
872 
873  $dbprefix = elgg_get_config('dbprefix');
874  if (!elgg_is_empty($dbprefix) && str_starts_with($table, $dbprefix)) {
875  $table = substr($table, strlen($dbprefix));
876  }
877 
878  $clause = new JoinClause($table, $alias, $condition, $type);
879  $options['joins'][$key] = $clause;
880  }
881  }
882 
883  return $options;
884  }
885 
893  protected function normalizeOrderByClauses(array $options = []): array {
894  $orders = $options['order_by'];
895  $options['order_by'] = [];
896 
897  if (!empty($orders)) {
898  if (is_string($orders)) {
899  $orders = explode(',', $orders);
900  } elseif (!is_array($orders)) {
901  $orders = [$orders];
902  }
903 
904  foreach ($orders as $order) {
905  if ($order instanceof OrderByClause) {
906  $options['order_by'][] = $order;
907  continue;
908  }
909 
910  $order = trim($order);
911  $parts = [];
912  if (preg_match('/(.*)(?=\s+(asc|desc))/i', $order, $parts)) {
913  $column = $parts[1];
914  $direction = $parts[2];
915  } else {
916  $column = $order;
917  $direction = 'ASC';
918  }
919 
920  $direction = strtoupper($direction) === 'DESC' ? 'DESC' : 'ASC';
921 
922  $options['order_by'][] = new OrderByClause($column, $direction);
923  }
924  }
925 
926  $sort_by = $options['sort_by'];
927  if (isset($sort_by['property'])) {
928  // single array variant, convert to an array of sort_by specs
929  $options['sort_by'] = [$sort_by];
930  }
931 
932  foreach ($options['sort_by'] as $sort_spec) {
933  $clause = new EntitySortByClause();
934  $clause->property = elgg_extract('property', $sort_spec);
935  $clause->property_type = elgg_extract('property_type', $sort_spec);
936  $clause->join_type = elgg_extract('join_type', $sort_spec, 'inner');
937  $clause->direction = elgg_extract('direction', $sort_spec);
938  $clause->signed = elgg_extract('signed', $sort_spec);
939  $clause->inverse_relationship = elgg_extract('inverse_relationship', $sort_spec);
940  $clause->relationship_guid = elgg_extract('relationship_guid', $sort_spec);
941 
942  $options['order_by'][] = $clause;
943  }
944 
945  return $options;
946  }
947 
955  protected function normalizeHavingClauses(array $options = []): array {
956  if (empty($options['having'])) {
957  $options['having'] = [];
958 
959  return $options;
960  }
961 
962  if (!is_array($options['having'])) {
963  $options['having'] = [$options['having']];
964  }
965 
966  foreach ($options['having'] as $key => $expr) {
967  if ($expr instanceof HavingClause) {
968  continue;
969  }
970 
971  $options['having'][$key] = new HavingClause($expr);
972  }
973 
974  return $options;
975  }
976 
984  protected function normalizeGroupByClauses(array $options = []): array {
985  if (empty($options['group_by'])) {
986  $options['group_by'] = [];
987 
988  return $options;
989  }
990 
991  if (!is_array($options['group_by'])) {
992  $options['group_by'] = [$options['group_by']];
993  }
994 
995  foreach ($options['group_by'] as $key => $expr) {
996  if ($expr instanceof GroupByClause) {
997  continue;
998  }
999 
1000  $options['group_by'][$key] = new GroupByClause($expr);
1001  }
1002 
1003  return $options;
1004  }
1005 
1014  public static function normalizeMetastringOptions(array $options = []): array {
1015 
1016  // support either metastrings_type or metastring_type
1017  // because I've made this mistake many times and hunting it down is a pain...
1018  $type = elgg_extract('metastring_type', $options, null);
1019  $type = elgg_extract('metastrings_type', $options, $type);
1020 
1021  $options['metastring_type'] = $type;
1022 
1023  // support annotation_ and annotations_ because they're way too easy to confuse
1024  $prefixes = ['metadata_', 'annotation_', 'annotations_'];
1025 
1026  // map the metadata_* options to metastring_* options
1027  $map = [
1028  'names' => 'metastring_names',
1029  'values' => 'metastring_values',
1030  'case_sensitive' => 'metastring_case_sensitive',
1031  'owner_guids' => 'metastring_owner_guids',
1032  'created_time_lower' => 'metastring_created_time_lower',
1033  'created_time_upper' => 'metastring_created_time_upper',
1034  'calculation' => 'metastring_calculation',
1035  'ids' => 'metastring_ids',
1036  ];
1037 
1038  foreach ($prefixes as $prefix) {
1039  $singulars = ["{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id"];
1040  $options = self::normalizePluralOptions($options, $singulars);
1041 
1042  foreach ($map as $specific => $normalized) {
1043  $key = $prefix . $specific;
1044  if (isset($options[$key])) {
1045  $options[$normalized] = $options[$key];
1046  }
1047  }
1048  }
1049 
1050  return $options;
1051  }
1052 
1065  public static function normalizePluralOptions(array $options, array $singulars): array {
1066  foreach ($singulars as $singular) {
1067  $plural = $singular . 's';
1068 
1069  if (array_key_exists($singular, $options)) {
1070  if ($options[$singular] === ELGG_ENTITIES_ANY_VALUE) {
1071  $options[$plural] = $options[$singular];
1072  } else {
1073  // Test for array refs #2641
1074  if (!is_array($options[$singular])) {
1075  $options[$plural] = [$options[$singular]];
1076  } else {
1077  $options[$plural] = $options[$singular];
1078  }
1079  }
1080  }
1081 
1082  unset($options[$singular]);
1083  }
1084 
1085  return $options;
1086  }
1087 }
Exception thrown if an argument is not of the expected type.
elgg_get_config(string $name, $default=null)
Get an Elgg configuration value.
$defaults
Generic entity header upload helper.
Definition: header.php:6
const PRIMARY_ATTR_NAMES
Definition: ElggEntity.php:53
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
Interface that allows resolving statements and/or extending query builder.
Definition: Clause.php:14
const ENTITY_TYPES
Definition: Config.php:263
const ELGG_VALUE_INTEGER
Value types.
Definition: constants.php:111
Builds quereis for matching entities by their attributes.
$column
Definition: add.php:10
Extends QueryBuilder with JOIN clauses.
Definition: JoinClause.php:11
Builds clauses for filtering entities by their properties in entity_relationships table...
Extends QueryBuilder with SELECT clauses.
Extends QueryBuilder with clauses necessary to sort entity lists by entity properties.
$type
Definition: delete.php:21
Builds queries for matching annotations against their properties.
Extends QueryBuilder with GROUP BY statements.
$keys
Definition: access.php:31
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof\ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
$value
Definition: generic.php:51
elgg_is_empty($value)
Check if a value isn&#39;t empty, but allow 0 and &#39;0&#39;.
Definition: input.php:176
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:254
if($who_can_change_language=== 'nobody') elseif($who_can_change_language=== 'admin_only'&&!elgg_is_admin_logged_in()) $options
Definition: language.php:20
Extends QueryBuilder with HAVING clauses.
elgg_log($message, $level=\Psr\Log\LogLevel::NOTICE)
Log a message.
Definition: elgglib.php:86
const ELGG_ENTITIES_ANY_VALUE
Constant to request the value of a parameter be ignored in elgg_get_*() functions.
Definition: constants.php:21
$table
Definition: user.php:37
Extends QueryBuilder with ORDER BY clauses.
if($container instanceof ElggGroup &&$container->guid!=elgg_get_page_owner_guid()) $key
Definition: summary.php:44
Builds a clause from closure or composite expression.
Definition: WhereClause.php:11
const ELGG_VALUE_STRING
Definition: constants.php:112
$subtypes
$index
Definition: gallery.php:40
Builds clauses for filtering entities by properties in metadata table.