Elgg  Version 4.3
LegacyQueryOptionsAdapter.php
Go to the documentation of this file.
1 <?php
2 
4 
5 use Elgg\Config;
20 
27 
35  public function normalizeOptions(array $options = []) {
36 
37  if (!isset($options['__original_options'])) {
38  $options['__original_options'] = $options;
39  }
40 
41  $options = array_merge($this->getDefaults(), $options);
42 
43  $options = $this->normalizeGuidOptions($options);
44  $options = $this->normalizeTimeOptions($options);
45 
46  $options = $this->normalizeAccessOptions($options);
47 
48  $options = $this->normalizeTypeSubtypeOptions($options);
49 
50  $options = $this->normalizePrivateSettingOptions($options);
51  $options = $this->normalizeRelationshipOptions($options);
52  $options = $this->normalizeAnnotationOptions($options);
53  $options = $this->normalizeMetadataOptions($options);
54  $options = $this->normalizeMetadataSearchOptions($options);
55 
56  foreach (['selects', 'joins', 'wheres'] as $prop) {
57  if (empty($options[$prop])) {
58  $options[$prop] = [];
59  }
60 
61  if (!is_array($options[$prop])) {
62  if ($options[$prop]) {
63  $options[$prop] = [$options[$prop]];
64  }
65  }
66  }
67 
68  $options = $this->normalizeSelectClauses($options);
69  $options = $this->normalizeWhereClauses($options);
70  $options = $this->normalizeJoinClauses($options);
71  $options = $this->normalizeOrderByClauses($options);
72  $options = $this->normalizeGroupByClauses($options);
73 
74  return $options;
75  }
76 
81  protected function getDefaults() {
82  return [
83  'types' => null,
84  'subtypes' => null,
85  'type_subtype_pairs' => null,
86  'guids' => null,
87  'owner_guids' => null,
88  'container_guids' => null,
89  'access_ids' => null,
90 
91  'created_after' => null,
92  'created_before' => null,
93  'updated_after' => null,
94  'updated_before' => null,
95  'last_action_after' => null,
96  'last_action_before' => null,
97 
98  'sort_by' => [],
99  'order_by' => null,
100  'count' => false,
101  'limit' => elgg_get_config('default_limit'),
102  'offset' => 0,
103 
104  'selects' => [],
105  'wheres' => [],
106  'joins' => [],
107  'group_by' => null,
108 
109  'metadata_name_value_pairs' => null,
110  'metadata_name_value_pairs_operator' => 'AND',
111  'metadata_case_sensitive' => true,
112  'order_by_metadata' => null,
113  'metadata_ids' => null,
114  'metadata_created_time_lower' => null,
115  'metadata_created_time_upper' => null,
116  'metadata_calculation' => null,
117 
118  'search_name_value_pairs' => null,
119 
120  'annotation_names' => null,
121  'annotation_values' => null,
122  'annotation_name_value_pairs' => null,
123  'annotation_name_value_pairs_operator' => 'AND',
124  'annotation_case_sensitive' => true,
125  'order_by_annotation' => null,
126  'annotation_ids' => null,
127  'annotation_created_time_lower' => null,
128  'annotation_created_time_upper' => null,
129  'annotation_owner_guids' => null,
130  'annotation_calculation' => null,
131 
132  'relationship_pairs' => [],
133 
134  'relationship' => null,
135  'relationship_guid' => null,
136  'inverse_relationship' => false,
137  'relationship_join_on' => 'guid',
138  'relationship_created_time_lower' => null,
139  'relationship_created_time_upper' => null,
140 
141  'private_setting_names' => null,
142  'private_setting_values' => null,
143  'private_setting_name_value_pairs' => null,
144  'private_setting_name_value_pairs_operator' => 'AND',
145  'private_setting_name_prefix' => '',
146  'private_setting_case_sensitive' => false,
147 
148  'preload_owners' => false,
149  'preload_containers' => false,
150  'callback' => null,
151  'distinct' => true,
152 
153  'batch' => false,
154  'batch_inc_offset' => true,
155  'batch_size' => 25,
156 
157  '__ElggBatch' => null,
158  ];
159  }
160 
168  protected function normalizeAccessOptions(array $options = []) {
169 
170  $options = self::normalizePluralOptions($options, ['access_id']);
171 
172  return $options;
173  }
174 
183  protected function normalizeTypeSubtypeOptions(array $options = []) {
184 
185  $singulars = [
186  'type',
187  'subtype',
188  ];
189 
190  $options = self::normalizePluralOptions($options, $singulars);
191 
192  // can't use helper function with type_subtype_pair because
193  // it's already an array...just need to merge it
194  if (isset($options['type_subtype_pair']) && isset($options['type_subtype_pairs'])) {
195  $options['type_subtype_pairs'] = array_merge((array) $options['type_subtype_pairs'], (array) $options['type_subtype_pair']);
196  } else if (isset($options['type_subtype_pair'])) {
197  $options['type_subtype_pairs'] = (array) $options['type_subtype_pair'];
198  } else if (isset($options['type_subtype_pairs'])) {
199  $options['type_subtype_pairs'] = (array) $options['type_subtype_pairs'];
200  } else if (isset($options['types'])) {
201  $options['type_subtype_pairs'] = [];
202  if ($options['types']) {
203  foreach ((array) $options['types'] as $type) {
204  $options['type_subtype_pairs'][$type] = isset($options['subtypes']) ? (array) $options['subtypes'] : null;
205  }
206  }
207  } else if (isset($options['subtypes'])) {
208  throw new InvalidArgumentException('If filtering for entity subtypes it is required to provide one or more entity types.');
209  }
210 
211  if (isset($options['type_subtype_pairs']) && is_array($options['type_subtype_pairs'])) {
212  foreach ($options['type_subtype_pairs'] as $type => $subtypes) {
213  if (!in_array($type, Config::ENTITY_TYPES)) {
214  elgg_log("'$type' is not a valid entity type", 'WARNING');
215  }
216  if (!empty($subtypes) && !is_array($subtypes)) {
217  $options['type_subtype_pairs'][$type] = [$subtypes];
218  }
219  }
220  }
221 
222  unset($options['type_subtype_pair']);
223  unset($options['types']);
224  unset($options['subtypes']);
225 
226  return $options;
227  }
228 
236  protected function normalizeMetadataOptions(array $options = []) {
237  $singulars = [
238  'metadata_id',
239  'metadata_name',
240  'metadata_value',
241  'metadata_name_value_pair',
242  ];
243 
244  $options = self::normalizePluralOptions($options, $singulars);
245 
246  $options = $this->normalizePairedOptions('metadata', $options);
247 
248  if (isset($options['order_by_metadata'])) {
249  elgg_deprecated_notice('Passing "order_by_metadata" to sort your results has been deprecated. Use "sort_by" options instead.', '4.3');
250 
251  $name = elgg_extract('name', $options['order_by_metadata']);
252  $direction = strtoupper(elgg_extract('direction', $options['order_by_metadata'], 'asc'));
253  $as = elgg_extract('as', $options['order_by_metadata']);
254 
255  if ($name) {
256  $options['sort_by'][] = [
257  'property' => $name,
258  'direction' => in_array($direction, ['ASC', 'DESC']) ? $direction : null,
259  'signed' => $as === ELGG_VALUE_INTEGER,
260  'property_type' => 'metadata',
261  ];
262  }
263 
264  $options['order_by'] = null;
265  $options['order_by_metadata'] = null;
266  }
267 
268  $props = [
269  'metadata_ids',
270  'metadata_created_after',
271  'metadata_created_before',
272  ];
273 
274  foreach ($props as $prop) {
275  if (isset($options[$prop]) && empty($options['metadata_name_value_pairs'])) {
276  $options['metadata_name_value_pairs'][] = [
277  $prop => $options[$prop]
278  ];
279  }
280  }
281 
282  foreach ($options['metadata_name_value_pairs'] as $key => $pair) {
283  if ($pair instanceof Clause) {
284  continue;
285  }
286 
287  foreach ($props as $prop) {
288  if (!isset($pair[$prop])) {
289  $options['metadata_name_value_pairs'][$key][$prop] = elgg_extract($prop, $options);
290  }
291  }
292 
293  $options['metadata_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
294  }
295 
296  $options['metadata_name_value_pairs'] = $this->removeKeyPrefix('metadata_', $options['metadata_name_value_pairs']);
297 
298  $defaults = [
299  'name' => null,
300  'value' => null,
301  'comparison' => '=',
302  'type' => ELGG_VALUE_STRING,
303  'case_sensitive' => true,
304  'entity_guids' => null,
305  'ids' => null,
306  'created_after' => null,
307  'created_before' => null,
308  ];
309 
310  foreach ($options['metadata_name_value_pairs'] as $key => $pair) {
311  if ($pair instanceof WhereClause) {
312  continue;
313  }
314 
315  $pair = array_merge($defaults, $pair);
316 
317  if (in_array(strtolower($pair['comparison']), ['in', 'eq', '=']) && is_string($pair['value'])) {
318  // Apparently this madness is supported
319  // \Elgg\Integration\ElggCoreGetEntitiesFromMetadataTest::testElggApiGettersEntityMetadataNVPValidNValidVOperandIn
320  $pair['value'] = array_map(function ($e) {
321  return trim($e, ' \"\'');
322  }, explode(',', $pair['value']));
323  }
324 
325  if (in_array($pair['name'], \ElggEntity::PRIMARY_ATTR_NAMES)) {
326  $clause = new AttributeWhereClause();
327  } else {
328  $clause = new MetadataWhereClause();
329  $clause->ids = (array) $pair['ids'];
330  $clause->entity_guids = (array) $pair['entity_guids'];
331  $clause->created_after = $pair['created_after'];
332  $clause->created_before = $pair['created_before'];
333  }
334 
335  $clause->names = (array) $pair['name'];
336  $clause->values = (array) $pair['value'];
337  $clause->comparison = $pair['comparison'];
338  $clause->value_type = $pair['type'];
339  $clause->case_sensitive = $pair['case_sensitive'];
340 
341  $options['metadata_name_value_pairs'][$key] = $clause;
342  }
343 
344  return $options;
345  }
346 
355  protected function normalizeMetadataSearchOptions(array $options = []) {
356  $singulars = [
357  'search_name_value_pair',
358  ];
359 
360  $options = self::normalizePluralOptions($options, $singulars);
361 
362  $options = $this->normalizePairedOptions('search', $options);
363 
364  foreach ($options['search_name_value_pairs'] as $key => $pair) {
365  if ($pair instanceof Clause) {
366  continue;
367  }
368 
369  $options['search_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
370  }
371 
372  $options['search_name_value_pairs'] = $this->removeKeyPrefix('metadata_', $options['search_name_value_pairs']);
373 
374  $defaults = [
375  'name' => null,
376  'value' => null,
377  'comparison' => '=',
378  'type' => ELGG_VALUE_STRING,
379  'case_sensitive' => true,
380  'entity_guids' => null,
381  'ids' => null,
382  'created_after' => null,
383  'created_before' => null,
384  ];
385 
386  foreach ($options['search_name_value_pairs'] as $key => $pair) {
387  if ($pair instanceof WhereClause) {
388  continue;
389  }
390 
391  $pair = array_merge($defaults, $pair);
392 
393  if (in_array(strtolower($pair['comparison']), ['in', 'eq', '=']) && is_string($pair['value'])) {
394  // Apparently this madness is supported
395  // \Elgg\Integration\ElggCoreGetEntitiesFromMetadataTest::testElggApiGettersEntityMetadataNVPValidNValidVOperandIn
396  $pair['value'] = array_map(function ($e) {
397  return trim($e, ' \"\'');
398  }, explode(',', $pair['value']));
399  }
400 
401  if (in_array($pair['name'], \ElggEntity::PRIMARY_ATTR_NAMES)) {
402  $clause = new AttributeWhereClause();
403  } else {
404  $clause = new MetadataWhereClause();
405  $clause->ids = (array) $pair['ids'];
406  $clause->entity_guids = (array) $pair['entity_guids'];
407  $clause->created_after = $pair['created_after'];
408  $clause->created_before = $pair['created_before'];
409  }
410 
411  $clause->names = (array) $pair['name'];
412  $clause->values = (array) $pair['value'];
413  $clause->comparison = $pair['comparison'];
414  $clause->value_type = $pair['type'];
415  $clause->case_sensitive = $pair['case_sensitive'];
416 
417  $options['search_name_value_pairs'][$key] = $clause;
418  }
419 
420  return $options;
421  }
422 
430  protected function normalizeAnnotationOptions(array $options = []) {
431  $singulars = [
432  'annotation_id',
433  'annotation_name',
434  'annotation_value',
435  'annotation_name_value_pair',
436  ];
437 
438  $options = self::normalizePluralOptions($options, $singulars);
439 
440  $options = $this->normalizePairedOptions('annotation', $options);
441 
442  if (isset($options['order_by_annotation'])) {
443  elgg_deprecated_notice('Passing "order_by_annotation" to sort your results has been deprecated. Use "sort_by" options instead.', '4.3');
444 
445  $name = elgg_extract('name', $options['order_by_annotation']);
446  $direction = strtoupper(elgg_extract('direction', $options['order_by_annotation'], 'asc'));
447  $as = elgg_extract('as', $options['order_by_annotation']);
448 
449  if ($name) {
450  $options['sort_by'][] = [
451  'property' => $name,
452  'property_type' => 'annotation',
453  'direction' => in_array($direction, ['ASC', 'DESC']) ? $direction : null,
454  'signed' => $as === ELGG_VALUE_INTEGER,
455  ];
456  }
457 
458  $options['order_by'] = null;
459  $options['order_by_annotation'] = null;
460  }
461 
462  $props = [
463  'annotation_ids',
464  'annotation_owner_guids',
465  'annotation_created_after',
466  'annotation_created_before',
467  'annotation_sort_by_calculation',
468  ];
469 
470  foreach ($props as $prop) {
471  if (isset($options[$prop]) && empty($options['annotation_name_value_pairs'])) {
472  $options['annotation_name_value_pairs'][] = [
473  $prop => $options[$prop]
474  ];
475  }
476  }
477 
478  foreach ($options['annotation_name_value_pairs'] as $key => $pair) {
479  if ($pair instanceof WhereClause) {
480  continue;
481  }
482 
483  foreach ($props as $prop) {
484  if (!isset($pair[$prop])) {
485  $options['annotation_name_value_pairs'][$key][$prop] = elgg_extract($prop, $options);
486  }
487  }
488 
489  $options['annotation_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
490  }
491 
492  $options['annotation_name_value_pairs'] = $this->removeKeyPrefix('annotation_', $options['annotation_name_value_pairs']);
493 
494  $defaults = [
495  'name' => null,
496  'value' => null,
497  'comparison' => '=',
498  'type' => ELGG_VALUE_STRING,
499  'case_sensitive' => true,
500  'entity_guids' => null,
501  'owner_guids' => null,
502  'ids' => null,
503  'enabled' => null,
504  'access_ids' => null,
505  'created_after' => null,
506  'created_before' => null,
507  'sort_by_calculation' => null,
508  ];
509 
510  foreach ($options['annotation_name_value_pairs'] as $key => $pair) {
511  if ($pair instanceof WhereClause) {
512  continue;
513  }
514 
515  $pair = array_merge($defaults, $pair);
516 
517  $clause = new AnnotationWhereClause();
518  $clause->ids = (array) $pair['ids'];
519  $clause->entity_guids = (array) $pair['entity_guids'];
520  $clause->owner_guids = (array) $pair['owner_guids'];
521  $clause->created_after = $pair['created_after'];
522  $clause->created_before = $pair['created_before'];
523  $clause->names = (array) $pair['name'];
524  $clause->values = (array) $pair['value'];
525  $clause->comparison = $pair['comparison'];
526  $clause->value_type = $pair['type'];
527  $clause->case_sensitive = $pair['case_sensitive'];
528  $clause->enabled = $pair['enabled'];
529  $clause->access_ids = (array) $pair['access_ids'];
530  $clause->sort_by_calculation = $pair['sort_by_calculation'];
531 
532  if ($clause->sort_by_calculation && empty($options['order_by'])) {
533  $clause->sort_by_direction = 'desc';
534  }
535 
536  $options['annotation_name_value_pairs'][$key] = $clause;
537  }
538 
539  return $options;
540  }
541 
549  protected function normalizePrivateSettingOptions(array $options = []) {
550 
551  $singulars = [
552  'private_setting_name',
553  'private_setting_value',
554  'private_setting_name_value_pair',
555  ];
556 
557  $options = self::normalizePluralOptions($options, $singulars);
558 
559  $options = $this->normalizePairedOptions('private_setting', $options);
560 
561  foreach ($options['private_setting_name_value_pairs'] as $key => $pair) {
562  if ($pair instanceof WhereClause) {
563  continue;
564  }
565 
566  $options['private_setting_name_value_pairs'][$key]['entity_guids'] = $options['guids'];
567  }
568 
569  $options['private_setting_name_value_pairs'] = $this->removeKeyPrefix('private_setting_', $options['private_setting_name_value_pairs']);
570 
571  $prefix = null;
572  if (isset($options['private_setting_name_prefix'])) {
573  $prefix = $options['private_setting_name_prefix'];
574  unset($options['private_setting_name_prefix']);
575  }
576 
577  $defaults = [
578  'name' => null,
579  'value' => null,
580  'comparison' => '=',
581  'type' => ELGG_VALUE_STRING,
582  'case_sensitive' => true,
583  'entity_guids' => null,
584  'ids' => null,
585  ];
586 
587  foreach ($options['private_setting_name_value_pairs'] as $key => $pair) {
588  if ($pair instanceof WhereClause) {
589  continue;
590  }
591 
592  $pair = array_merge($defaults, $pair);
593 
594  $names = (array) elgg_extract('name', $pair);
595  $names = array_map(function($name) use ($prefix) {
596  return $prefix ? "$prefix$name" : $name;
597  }, $names);
598 
599  $clause = new PrivateSettingWhereClause();
600  $clause->ids = (array) $pair['ids'];
601  $clause->entity_guids = (array) $pair['entity_guids'];
602  $clause->names = $names;
603  $clause->values = (array) $pair['value'];
604  $clause->comparison = $pair['comparison'];
605  $clause->value_type = $pair['type'];
606  $clause->case_sensitive = $pair['case_sensitive'];
607 
608  $options['private_setting_name_value_pairs'][$key] = $clause;
609  }
610 
611  return $options;
612  }
613 
622  protected function normalizePairedOptions($type = 'metadata', array $options = []) {
623  if (!is_array($options["{$type}_name_value_pairs"])) {
624  $options["{$type}_name_value_pairs"] = [];
625  }
626 
627  $case_sensitive_default = elgg_extract("{$type}_case_sensitive", $options, true);
628 
637  if (isset($options["{$type}_name_value_pairs"]['name'])) {
638  $options["{$type}_name_value_pairs"][] = [
639  'name' => $options["{$type}_name_value_pairs"]['name'],
640  'value' => elgg_extract('value', $options["{$type}_name_value_pairs"]),
641  'comparison' => elgg_extract('operand', $options["{$type}_name_value_pairs"], '='),
642  'case_sensitive' => elgg_extract('case_sensitive', $options["{$type}_name_value_pairs"], $case_sensitive_default)
643  ];
644  unset($options["{$type}_name_value_pairs"]['name']);
645  unset($options["{$type}_name_value_pairs"]['value']);
646  unset($options["{$type}_name_value_pairs"]['operand']);
647  unset($options["{$type}_name_value_pairs"]['case_sensitive']);
648  }
649 
661  foreach ($options["{$type}_name_value_pairs"] as $index => $pair) {
662  if (is_array($pair)) {
663  $keys = array_keys($pair);
664  if (sizeof($keys) === 1 && is_string($keys[0]) && $keys[0] !== 'name' && $keys[0] !== 'value') {
665  $options["{$type}_name_value_pairs"][$index] = [
666  'name' => $keys[0],
667  'value' => $pair[$keys[0]],
668  'comparison' => '=',
669  ];
670  }
671  }
672  }
673 
681  foreach ($options["{$type}_name_value_pairs"] as $index => $values) {
682  if ($values instanceof Clause) {
683  continue;
684  }
685 
686  if (is_array($values)) {
687  if (isset($values['name']) || isset($values['value'])) {
688  continue;
689  }
690  }
691  $options["{$type}_name_value_pairs"][$index] = [
692  'name' => $index,
693  'value' => $values,
694  'comparison' => '=',
695  ];
696  }
697 
698  if (isset($options["{$type}_names"]) || isset($options["{$type}_values"])) {
699  $options["{$type}_name_value_pairs"][] = [
700  'name' => isset($options["{$type}_names"]) ? (array) $options["{$type}_names"] : null,
701  'value' => isset($options["{$type}_values"]) ? (array) $options["{$type}_values"] : null,
702  'comparison' => '=',
703  ];
704  }
705 
706  foreach ($options["{$type}_name_value_pairs"] as $key => $value) {
707  if ($value instanceof Clause) {
708  continue;
709  }
710 
711  if (!isset($value['case_sensitive'])) {
712  $value['case_sensitive'] = $case_sensitive_default;
713  }
714  if (!isset($value['type'])) {
715  if (isset($value['value']) && is_bool($value['value'])) {
716  $value['value'] = (int) $value['value'];
717  }
718  if (isset($value['value']) && is_int($value['value'])) {
719  $value['type'] = ELGG_VALUE_INTEGER;
720  } else {
721  $value['type'] = ELGG_VALUE_STRING;
722  }
723  }
724  if (!isset($value['comparison']) && isset($value['operand'])) {
725  $value['comparison'] = $value['operand'];
726  unset($value['operand']);
727  }
728 
729  $options["{$type}_name_value_pairs"][$key] = $value;
730  }
731 
732  unset($options["{$type}_names"]);
733  unset($options["{$type}_values"]);
734  unset($options["{$type}_case_sensitive"]);
735 
736  return $options;
737  }
738 
746  protected function normalizeRelationshipOptions(array $options = []) {
747 
748  $pair = [];
749 
750  $defaults = [
751  'relationship_ids' => null,
752  'relationship' => null,
753  'relationship_guid' => null,
754  'inverse_relationship' => false,
755  'relationship_join_on' => 'guid',
756  'relationship_created_after' => null,
757  'relationship_created_before' => null,
758  ];
759 
760  foreach (array_keys($defaults) as $prop) {
761  if (isset($options[$prop])) {
762  $pair[$prop] = $options[$prop];
763  }
764  unset($options[$prop]);
765  }
766 
767  $options['relationship_pairs'] = (array) $options['relationship_pairs'];
768  $options['relationship_pairs'][] = $pair;
769 
770  foreach ($options['relationship_pairs'] as $index => $relationship_pair) {
771  if ($relationship_pair instanceof WhereClause) {
772  continue;
773  }
774 
775  $options['relationship_pairs'][$index] = array_merge($defaults, $relationship_pair);
776  }
777 
778  $options['relationship_pairs'] = $this->removeKeyPrefix('relationship_', $options['relationship_pairs']);
779 
780  foreach ($options['relationship_pairs'] as $key => $pair) {
781  if ($pair instanceof WhereClause) {
782  continue;
783  }
784 
785  $pair = array_merge($defaults, $pair);
786 
787  if (!$pair['relationship'] && !$pair['relationship_guid']) {
788  unset($options['relationship_pairs'][$key]);
789  continue;
790  }
791 
792  $clause = new RelationshipWhereClause();
793  $clause->ids = (array) $pair['ids'];
794  $clause->names = (array) $pair['relationship'];
795 
796  $clause->join_on = $pair['join_on'];
797  $clause->inverse = $pair['inverse_relationship'];
798  if ($clause->inverse) {
799  $clause->object_guids = (array) $pair['guid'];
800  } else {
801  $clause->subject_guids = (array) $pair['guid'];
802  }
803  $clause->created_after = $pair['created_after'];
804  $clause->created_before = $pair['created_before'];
805 
806 
807  $options['relationship_pairs'][$key] = $clause;
808  }
809 
810  return $options;
811  }
812 
820  protected function normalizeGuidOptions(array $options = []) {
821 
822  $singulars = [
823  'guid',
824  'owner_guid',
825  'container_guid',
826  'annotation_owner_guid',
827  ];
828 
829  $options = self::normalizePluralOptions($options, $singulars);
830 
831  $names = [
832  'guids',
833  'owner_guids',
834  'container_guids',
835  'annotation_owner_guids',
836  'relationship_guid',
837  ];
838 
839  foreach ($names as $name) {
840  if (!isset($options[$name])) {
841  continue;
842  }
843 
844  if (!is_array($options[$name])) {
846  }
847 
848  foreach ($options[$name] as $key => $value) {
849  if ($value === false || $value === '') {
850  unset($options[$name][$key]);
851  continue;
852  }
853  }
854  }
855 
856  return $options;
857  }
858 
866  protected function normalizeTimeOptions(array $options = []) {
867 
868  $props = [
869  'modified',
870  'created',
871  'updated',
872  'metadata_created',
873  'annotation_created',
874  'relationship_created',
875  'last_action',
876  'posted',
877  ];
878 
879  $bounds = ['time_lower', 'time_upper', 'after', 'before'];
880 
881  foreach ($props as $prop) {
882  foreach ($bounds as $bound) {
883  $prop_name = "{$prop}_{$bound}";
884 
885  $new_prop_name = $prop_name;
886  $new_prop_name = str_replace('modified', 'updated', $new_prop_name);
887  $new_prop_name = str_replace('posted', 'created', $new_prop_name);
888  $new_prop_name = str_replace('time_lower', 'after', $new_prop_name);
889  $new_prop_name = str_replace('time_upper', 'before', $new_prop_name);
890 
891  if (!isset($options[$new_prop_name])) {
892  $options[$new_prop_name] = elgg_extract($prop_name, $options);
893  }
894  }
895  }
896 
897  return $options;
898  }
899 
908  protected function removeKeyPrefix($prefix, array $array = []) {
909  foreach ($array as $key => $value) {
910  $new_key = $key;
911  if (strpos($key, $prefix) === 0) {
912  $new_key = substr($key, strlen($prefix));
913  }
914  if (!isset($array[$new_key])) {
915  $array[$new_key] = $array[$key];
916  }
917  if ($new_key !== $key) {
918  unset($array[$key]);
919  }
920 
921  if (is_array($array[$new_key])) {
922  $array[$new_key] = $this->removeKeyPrefix($prefix, $array[$new_key]);
923  }
924  }
925 
926  return $array;
927  }
928 
936  protected function normalizeSelectClauses(array $options = []) {
937 
938  $options = self::normalizePluralOptions($options, ['select']);
939 
940  foreach ($options['selects'] as $key => $clause) {
941  if (empty($clause)) {
942  unset($options['selects'][$key]);
943  continue;
944  }
945 
946  if ($clause instanceof SelectClause) {
947  continue;
948  }
949 
950  $options['selects'][$key] = new SelectClause($clause);
951  }
952 
953  return $options;
954  }
955 
963  protected function normalizeWhereClauses(array $options = []) {
964 
965  $options = self::normalizePluralOptions($options, ['where']);
966 
967  foreach ($options['wheres'] as $key => $clause) {
968  if (empty($clause)) {
969  unset($options['wheres'][$key]);
970  continue;
971  }
972 
973  if ($clause instanceof WhereClause) {
974  continue;
975  }
976 
977  if (is_string($clause)) {
979  Using literal MySQL statements in 'wheres' options parameter is deprecated.
980  Instead use a closure that receives an instanceof of QueryBuilder
981  and returns a composite DBAL expression
982 
983  {{ $clause }}
984  ", '3.0');
985  }
986 
987  $options['wheres'][$key] = new WhereClause($clause);
988  }
989 
990  return $options;
991  }
992 
1000  protected function normalizeJoinClauses(array $options = []) {
1001 
1002  $options = self::normalizePluralOptions($options, ['join']);
1003 
1004  foreach ($options['joins'] as $key => $join) {
1005  if (empty($join)) {
1006  unset($options['joins'][$key]);
1007  continue;
1008  }
1009 
1010  if ($join instanceof JoinClause) {
1011  continue;
1012  }
1013 
1014  if (is_string($join)) {
1015  preg_match('/((LEFT|INNER|RIGHT)\s+)?JOIN\s+(.*?)\s+((as\s+)?(.*?)\s+)ON\s+(.*)$/im', $join, $parts);
1016 
1017  $type = !empty($parts[2]) ? strtolower($parts[2]) : 'inner';
1018  $table = $parts[3];
1019  $alias = $parts[6];
1020  $condition = preg_replace('/\r|\n/', '', $parts[7]);
1021 
1022  $dbprefix = elgg_get_config('dbprefix');
1023  if (!elgg_is_empty($dbprefix) && strpos($table, $dbprefix) === 0) {
1024  $table = substr($table, strlen($dbprefix));
1025  }
1026 
1028  Using literal MySQL statements in 'joins' options parameter is deprecated.
1029  Instead use a closure that receives an instanceof of QueryBuilder and returns an instanceof of JoinClause,
1030  also consider using one of the built-in methods in QueryBuilder.
1031 
1032  {{ $join }}
1033  ", '3.0');
1034 
1035  $clause = new JoinClause($table, $alias, $condition, $type);
1036  $options['joins'][$key] = $clause;
1037  }
1038  }
1039 
1040  return $options;
1041  }
1042 
1050  protected function normalizeOrderByClauses(array $options = []) {
1051 
1052  $order_by = $options['order_by'];
1053  $options['order_by'] = [];
1054 
1055  if (!empty($order_by)) {
1056  if (is_string($order_by)) {
1057  $orders = explode(',', $order_by);
1058  } else if (is_array($order_by)) {
1059  $orders = $order_by;
1060  } else {
1061  $orders = [$order_by];
1062  }
1063 
1064  foreach ($orders as $order) {
1065  if ($order instanceof OrderByClause) {
1066  $options['order_by'][] = $order;
1067  continue;
1068  }
1069 
1070  $order = trim($order);
1071  $parts = [];
1072  if (preg_match('/(.*)(?=\s+(asc|desc))/i', $order, $parts)) {
1073  $column = $parts[1];
1074  $direction = $parts[2];
1075  } else {
1076  $column = $order;
1077  $direction = 'ASC';
1078  }
1079 
1080  $direction = strtoupper($direction) === 'DESC' ? 'DESC' : 'ASC';
1081 
1082  $options['order_by'][] = new OrderByClause($column, $direction);
1083  }
1084  }
1085 
1086  $sort_by = $options['sort_by'];
1087  if (isset($sort_by['property'])) {
1088  // single array variant, convert to an array of sort_by specs
1089  $options['sort_by'] = [$sort_by];
1090  }
1091 
1092  foreach ($options['sort_by'] as $sort_spec) {
1093  $clause = new EntitySortByClause();
1094  $clause->property = elgg_extract('property', $sort_spec);
1095  $clause->property_type = elgg_extract('property_type', $sort_spec);
1096  $clause->join_type = elgg_extract('join_type', $sort_spec, 'inner');
1097  $clause->direction = elgg_extract('direction', $sort_spec);
1098  $clause->signed = elgg_extract('signed', $sort_spec);
1099  $clause->inverse_relationship = elgg_extract('inverse_relationship', $sort_spec);
1100  $clause->relationship_guid = elgg_extract('relationship_guid', $sort_spec);
1101 
1102  $options['order_by'][] = $clause;
1103  }
1104 
1105  return $options;
1106  }
1107 
1115  protected function normalizeGroupByClauses(array $options = []) {
1116 
1117  if (!isset($options['having'])) {
1118  $options['having'] = [];
1119  } else {
1120  if (!is_array($options['having'])) {
1121  $options['having'] = [$options['having']];
1122  }
1123 
1124  foreach ($options['having'] as $key => $expr) {
1125  if ($expr instanceof HavingClause) {
1126  continue;
1127  }
1128 
1129  $options['having'][$key] = new HavingClause($expr);
1130  }
1131  }
1132 
1133  if (empty($options['group_by'])) {
1134  $options['group_by'] = [];
1135  }
1136 
1137  if (is_string($options['group_by'])) {
1138  $clause = $options['group_by'];
1139 
1140  $options['group_by'] = explode(',', $options['group_by']);
1141 
1142  if (count($options['group_by']) > 1) {
1144  Using literal MySQL statements in 'group_by' options parameter is deprecated.
1145  Instead use a closure that receives an instanceof of QueryBuilder
1146  and returns a prepared clause.
1147 
1148  {{ $clause }}
1149  ", '3.0');
1150  }
1151  }
1152 
1153  foreach ($options['group_by'] as $key => $expr) {
1154  if ($expr instanceof GroupByClause) {
1155  continue;
1156  }
1157 
1158  if (is_string($expr)) {
1159  $expr = trim($expr);
1160  }
1161 
1162  $options['group_by'][$key] = new GroupByClause($expr);
1163  }
1164 
1165  return $options;
1166  }
1167 
1175  public static function normalizeMetastringOptions(array $options = []) {
1176 
1177  // support either metastrings_type or metastring_type
1178  // because I've made this mistake many times and hunting it down is a pain...
1179  $type = elgg_extract('metastring_type', $options, null);
1180  $type = elgg_extract('metastrings_type', $options, $type);
1181 
1182  $options['metastring_type'] = $type;
1183 
1184  // support annotation_ and annotations_ because they're way too easy to confuse
1185  $prefixes = ['metadata_', 'annotation_', 'annotations_'];
1186 
1187  // map the metadata_* options to metastring_* options
1188  $map = [
1189  'names' => 'metastring_names',
1190  'values' => 'metastring_values',
1191  'case_sensitive' => 'metastring_case_sensitive',
1192  'owner_guids' => 'metastring_owner_guids',
1193  'created_time_lower' => 'metastring_created_time_lower',
1194  'created_time_upper' => 'metastring_created_time_upper',
1195  'calculation' => 'metastring_calculation',
1196  'ids' => 'metastring_ids',
1197  ];
1198 
1199  foreach ($prefixes as $prefix) {
1200  $singulars = ["{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id"];
1201  $options = self::normalizePluralOptions($options, $singulars);
1202 
1203  foreach ($map as $specific => $normalized) {
1204  $key = $prefix . $specific;
1205  if (isset($options[$key])) {
1206  $options[$normalized] = $options[$key];
1207  }
1208  }
1209  }
1210 
1211  return $options;
1212  }
1213 
1226  public static function normalizePluralOptions($options, $singulars) {
1227  foreach ($singulars as $singular) {
1228  $plural = $singular . 's';
1229 
1230  if (array_key_exists($singular, $options)) {
1231  if ($options[$singular] === ELGG_ENTITIES_ANY_VALUE) {
1232  $options[$plural] = $options[$singular];
1233  } else {
1234  // Test for array refs #2641
1235  if (!is_array($options[$singular])) {
1236  $options[$plural] = [$options[$singular]];
1237  } else {
1238  $options[$plural] = $options[$singular];
1239  }
1240  }
1241  }
1242 
1243  unset($options[$singular]);
1244  }
1245 
1246  return $options;
1247  }
1248 }
Exception thrown if an argument is not of the expected type.
elgg_deprecated_notice(string $msg, string $dep_version)
Log a notice about deprecated use of a function, view, etc.
Definition: deprecation.php:52
const PRIMARY_ATTR_NAMES
Definition: ElggEntity.php:50
if(!$user||!$user->canDelete()) $name
Definition: delete.php:22
Interface that allows resolving statements and/or extending query builder.
Definition: Clause.php:14
$defaults
const ENTITY_TYPES
Definition: Config.php:264
const ELGG_VALUE_INTEGER
Value types.
Definition: constants.php:126
Builds quereis for matching entities by their attributes.
$column
Definition: add.php:10
Extends QueryBuilder with JOIN clauses.
Definition: JoinClause.php:12
Builds clauses for filtering entities by their properties in entity_relationships table...
Extends QueryBuilder with SELECT clauses.
Extends QueryBuilder with clauses necesary 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
$options
Elgg admin footer.
Definition: footer.php:6
$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:179
Extends QueryBuilder with HAVING clauses.
elgg_log($message, $level=\Psr\Log\LogLevel::NOTICE)
Log a message.
Definition: elgglib.php:399
const ELGG_ENTITIES_ANY_VALUE
Definition: constants.php:24
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:547
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:12
const ELGG_VALUE_STRING
Definition: constants.php:127
$subtypes
Builds queries for filtering entties by their properties in private_settings table.
$index
Definition: gallery.php:40
Builds clauses for filtering entities by properties in metadata table.
$table
Definition: cron.php:56
elgg_get_config($name, $default=null)
Get an Elgg configuration value.