Elgg  Version 1.12
EntityTable.php
Go to the documentation of this file.
1 <?php
2 namespace Elgg\Database;
3 
5 
15 class EntityTable {
21  private $CONFIG;
22 
26  public function __construct() {
27  global $CONFIG;
28  $this->CONFIG = $CONFIG;
29  }
30 
45  function getRow($guid) {
46 
47 
48  if (!$guid) {
49  return false;
50  }
51 
52  $guid = (int) $guid;
53  $access = _elgg_get_access_where_sql(array('table_alias' => ''));
54 
55  return _elgg_services()->db->getDataRow("SELECT * from {$this->CONFIG->dbprefix}entities where guid=$guid and $access");
56  }
57 
73  function rowToElggStar($row) {
74  if (!($row instanceof \stdClass)) {
75  return $row;
76  }
77 
78  if ((!isset($row->guid)) || (!isset($row->subtype))) {
79  return $row;
80  }
81 
82  $new_entity = false;
83 
84  // Create a memcache cache if we can
85  static $newentity_cache;
86  if ((!$newentity_cache) && (is_memcache_available())) {
87  $newentity_cache = new \ElggMemcache('new_entity_cache');
88  }
89  if ($newentity_cache) {
90  $new_entity = $newentity_cache->load($row->guid);
91  }
92  if ($new_entity) {
93  return $new_entity;
94  }
95 
96  // load class for entity if one is registered
97  $classname = get_subtype_class_from_id($row->subtype);
98  if ($classname != "") {
99  if (class_exists($classname)) {
100  $new_entity = new $classname($row);
101 
102  if (!($new_entity instanceof \ElggEntity)) {
103  $msg = $classname . " is not a " . '\ElggEntity' . ".";
104  throw new \ClassException($msg);
105  }
106  } else {
107  error_log("Class '" . $classname . "' was not found, missing plugin?");
108  }
109  }
110 
111  if (!$new_entity) {
112  //@todo Make this into a function
113  switch ($row->type) {
114  case 'object' :
115  $new_entity = new \ElggObject($row);
116  break;
117  case 'user' :
118  $new_entity = new \ElggUser($row);
119  break;
120  case 'group' :
121  $new_entity = new \ElggGroup($row);
122  break;
123  case 'site' :
124  $new_entity = new \ElggSite($row);
125  break;
126  default:
127  $msg = "Entity type " . $row->type . " is not supported.";
128  throw new \InstallationException($msg);
129  }
130  }
131 
132  // Cache entity if we have a cache available
133  if (($newentity_cache) && ($new_entity)) {
134  $newentity_cache->save($new_entity->guid, $new_entity);
135  }
136 
137  return $new_entity;
138  }
139 
149  function get($guid, $type = '') {
150  // We could also use: if (!(int) $guid) { return false },
151  // but that evaluates to a false positive for $guid = true.
152  // This is a bit slower, but more thorough.
153  if (!is_numeric($guid) || $guid === 0 || $guid === '0') {
154  return false;
155  }
156 
157  // Check local cache first
158  $new_entity = _elgg_retrieve_cached_entity($guid);
159  if ($new_entity) {
160  if ($type) {
161  return elgg_instanceof($new_entity, $type) ? $new_entity : false;
162  }
163  return $new_entity;
164  }
165 
166  $options = [
167  'guid' => $guid,
168  'limit' => 1,
169  'site_guids' => ELGG_ENTITIES_ANY_VALUE, // for BC with get_entity, allow matching any site
170  ];
171  if ($type) {
172  $options['type'] = $type;
173  }
174  $entities = $this->getEntities($options);
175  return $entities ? $entities[0] : false;
176  }
177 
190  function exists($guid) {
191 
192 
194 
195  $query = "SELECT count(*) as total FROM {$this->CONFIG->dbprefix}entities WHERE guid = $guid";
196  $result = _elgg_services()->db->getDataRow($query);
197  if ($result->total == 0) {
198  return false;
199  } else {
200  return true;
201  }
202  }
203 
212  function enable($guid, $recursive = true) {
213 
214  // Override access only visible entities
215  $old_access_status = access_get_show_hidden_status();
217 
218  $result = false;
220  if ($entity) {
221  $result = $entity->enable($recursive);
222  }
223 
224  access_show_hidden_entities($old_access_status);
225  return $result;
226  }
227 
310  function getEntities(array $options = array()) {
311 
312 
313  $defaults = array(
314  'types' => ELGG_ENTITIES_ANY_VALUE,
315  'subtypes' => ELGG_ENTITIES_ANY_VALUE,
316  'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
317 
318  'guids' => ELGG_ENTITIES_ANY_VALUE,
319  'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
320  'container_guids' => ELGG_ENTITIES_ANY_VALUE,
321  'site_guids' => $this->CONFIG->site_guid,
322 
323  'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
324  'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
325  'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
326  'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
327 
328  'reverse_order_by' => false,
329  'order_by' => 'e.time_created desc',
330  'group_by' => ELGG_ENTITIES_ANY_VALUE,
331  'limit' => _elgg_services()->config->get('default_limit'),
332  'offset' => 0,
333  'count' => false,
334  'selects' => array(),
335  'wheres' => array(),
336  'joins' => array(),
337 
338  'preload_owners' => false,
339  'preload_containers' => false,
340  'callback' => 'entity_row_to_elggstar',
341  'distinct' => true,
342 
343  // private API
344  '__ElggBatch' => null,
345  );
346 
347  $options = array_merge($defaults, $options);
348 
349  // can't use helper function with type_subtype_pair because
350  // it's already an array...just need to merge it
351  if (isset($options['type_subtype_pair'])) {
352  if (isset($options['type_subtype_pairs'])) {
353  $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
354  $options['type_subtype_pair']);
355  } else {
356  $options['type_subtype_pairs'] = $options['type_subtype_pair'];
357  }
358  }
359 
360  $singulars = array('type', 'subtype', 'guid', 'owner_guid', 'container_guid', 'site_guid');
361  $options = _elgg_normalize_plural_options_array($options, $singulars);
362 
363  $options = $this->autoJoinTables($options);
364 
365  // evaluate where clauses
366  if (!is_array($options['wheres'])) {
367  $options['wheres'] = array($options['wheres']);
368  }
369 
370  $wheres = $options['wheres'];
371 
372  $wheres[] = _elgg_get_entity_type_subtype_where_sql('e', $options['types'],
373  $options['subtypes'], $options['type_subtype_pairs']);
374 
375  $wheres[] = _elgg_get_guid_based_where_sql('e.guid', $options['guids']);
376  $wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
377  $wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
378  $wheres[] = _elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
379 
380  $wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
381  $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
382 
383  // see if any functions failed
384  // remove empty strings on successful functions
385  foreach ($wheres as $i => $where) {
386  if ($where === false) {
387  return false;
388  } elseif (empty($where)) {
389  unset($wheres[$i]);
390  }
391  }
392 
393  // remove identical where clauses
394  $wheres = array_unique($wheres);
395 
396  // evaluate join clauses
397  if (!is_array($options['joins'])) {
398  $options['joins'] = array($options['joins']);
399  }
400 
401  // remove identical join clauses
402  $joins = array_unique($options['joins']);
403 
404  foreach ($joins as $i => $join) {
405  if ($join === false) {
406  return false;
407  } elseif (empty($join)) {
408  unset($joins[$i]);
409  }
410  }
411 
412  // evalutate selects
413  if ($options['selects']) {
414  $selects = '';
415  foreach ($options['selects'] as $select) {
416  $selects .= ", $select";
417  }
418  } else {
419  $selects = '';
420  }
421 
422  if (!$options['count']) {
423  $distinct = $options['distinct'] ? "DISTINCT" : "";
424  $query = "SELECT $distinct e.*{$selects} FROM {$this->CONFIG->dbprefix}entities e ";
425  } else {
426  // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than GUIDs
427  $count_expr = $options['distinct'] ? "DISTINCT e.guid" : "*";
428  $query = "SELECT COUNT($count_expr) as total FROM {$this->CONFIG->dbprefix}entities e ";
429  }
430 
431  // add joins
432  foreach ($joins as $j) {
433  $query .= " $j ";
434  }
435 
436  // add wheres
437  $query .= ' WHERE ';
438 
439  foreach ($wheres as $w) {
440  $query .= " $w AND ";
441  }
442 
443  // Add access controls
444  $query .= _elgg_get_access_where_sql();
445 
446  // reverse order by
447  if ($options['reverse_order_by']) {
448  $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']);
449  }
450 
451  if ($options['count']) {
452  $total = _elgg_services()->db->getDataRow($query);
453  return (int)$total->total;
454  }
455 
456  if ($options['group_by']) {
457  $query .= " GROUP BY {$options['group_by']}";
458  }
459 
460  if ($options['order_by']) {
461  $query .= " ORDER BY {$options['order_by']}";
462  }
463 
464  if ($options['limit']) {
465  $limit = sanitise_int($options['limit'], false);
466  $offset = sanitise_int($options['offset'], false);
467  $query .= " LIMIT $offset, $limit";
468  }
469 
470  if ($options['callback'] === 'entity_row_to_elggstar') {
471  $results = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
472  } else {
473  $results = _elgg_services()->db->getData($query, $options['callback']);
474  }
475 
476  if (!$results) {
477  // no results, no preloading
478  return $results;
479  }
480 
481  // populate entity and metadata caches, and prepare $entities for preloader
482  $guids = array();
483  foreach ($results as $item) {
484  // A custom callback could result in items that aren't \ElggEntity's, so check for them
485  if ($item instanceof \ElggEntity) {
486  _elgg_cache_entity($item);
487  // plugins usually have only settings
488  if (!$item instanceof \ElggPlugin) {
489  $guids[] = $item->guid;
490  }
491  }
492  }
493  // @todo Without this, recursive delete fails. See #4568
494  reset($results);
495 
496  if ($guids) {
497  // there were entities in the result set, preload metadata for them
498  _elgg_services()->metadataCache->populateFromEntities($guids);
499  }
500 
501  if (count($results) > 1) {
502  $props_to_preload = [];
503  if ($options['preload_owners']) {
504  $props_to_preload[] = 'owner_guid';
505  }
506  if ($options['preload_containers']) {
507  $props_to_preload[] = 'container_guid';
508  }
509  if ($props_to_preload) {
510  // note, ElggEntityPreloaderIntegrationTest assumes it can swap out
511  // the preloader after boot. If you inject this component at construction
512  // time that unit test will break. :/
513  _elgg_services()->entityPreloader->preload($results, $props_to_preload);
514  }
515  }
516 
517  return $results;
518  }
519 
527  protected function autoJoinTables(array $options) {
528  // we must be careful that the query doesn't specify any options that may join
529  // tables or change the selected columns
530  if (!is_array($options['types'])
531  || count($options['types']) !== 1
532  || !empty($options['selects'])
533  || !empty($options['wheres'])
534  || !empty($options['joins'])
535  || $options['callback'] !== 'entity_row_to_elggstar'
536  || $options['count']) {
537  // Too dangerous to auto-join
538  return $options;
539  }
540 
541  $join_types = [
542  // Each class must have a static getExternalAttributes() : array
543  'object' => 'ElggObject',
544  'user' => 'ElggUser',
545  'group' => 'ElggGroup',
546  'site' => 'ElggSite',
547  ];
548 
549  // We use reset() because $options['types'] may not have a numeric key
550  $type = reset($options['types']);
551  if (empty($join_types[$type])) {
552  return $options;
553  }
554 
555  // Get the columns we'll need to select. We can't use st.* because the order_by
556  // clause may reference "guid", which MySQL will complain about being ambiguous
557  if (!is_callable([$join_types[$type], 'getExternalAttributes'])) {
558  // for some reason can't get external attributes.
559  return $options;
560  }
561 
562  $attributes = $join_types[$type]::getExternalAttributes();
563  foreach (array_keys($attributes) as $col) {
564  $options['selects'][] = "st.$col";
565  }
566 
567  // join the secondary table
568  $options['joins'][] = "JOIN {$this->CONFIG->dbprefix}{$type}s_entity st ON (e.guid = st.guid)";
569 
570  return $options;
571  }
572 
583  function fetchFromSql($sql, \ElggBatch $batch = null) {
584  static $plugin_subtype;
585  if (null === $plugin_subtype) {
586  $plugin_subtype = get_subtype_id('object', 'plugin');
587  }
588 
589  // Keys are types, values are columns that, if present, suggest that the secondary
590  // table is already JOINed. Note it's OK if guess incorrectly because entity load()
591  // will fetch any missing attributes.
592  $types_to_optimize = array(
593  'object' => 'title',
594  'user' => 'password',
595  'group' => 'name',
596  'site' => 'url',
597  );
598 
599  $rows = _elgg_services()->db->getData($sql);
600 
601  // guids to look up in each type
602  $lookup_types = array();
603  // maps GUIDs to the $rows key
604  $guid_to_key = array();
605 
606  if (isset($rows[0]->type, $rows[0]->subtype)
607  && $rows[0]->type === 'object'
608  && $rows[0]->subtype == $plugin_subtype) {
609  // Likely the entire resultset is plugins, which have already been optimized
610  // to JOIN the secondary table. In this case we allow retrieving from cache,
611  // but abandon the extra queries.
612  $types_to_optimize = array();
613  }
614 
615  // First pass: use cache where possible, gather GUIDs that we're optimizing
616  foreach ($rows as $i => $row) {
617  if (empty($row->guid) || empty($row->type)) {
618  throw new \LogicException('Entity row missing guid or type');
619  }
621  if ($entity) {
622  $entity->refresh($row);
623  $rows[$i] = $entity;
624  continue;
625  }
626  if (isset($types_to_optimize[$row->type])) {
627  // check if row already looks JOINed.
628  if (isset($row->{$types_to_optimize[$row->type]})) {
629  // Row probably already contains JOINed secondary table. Don't make another query just
630  // to pull data that's already there
631  continue;
632  }
633  $lookup_types[$row->type][] = $row->guid;
634  $guid_to_key[$row->guid] = $i;
635  }
636  }
637  // Do secondary queries and merge rows
638  if ($lookup_types) {
639  $dbprefix = _elgg_services()->config->get('dbprefix');
640 
641  foreach ($lookup_types as $type => $guids) {
642  $set = "(" . implode(',', $guids) . ")";
643  $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set";
644  $secondary_rows = _elgg_services()->db->getData($sql);
645  if ($secondary_rows) {
646  foreach ($secondary_rows as $secondary_row) {
647  $key = $guid_to_key[$secondary_row->guid];
648  // cast to arrays to merge then cast back
649  $rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row);
650  }
651  }
652  }
653  }
654  // Second pass to finish conversion
655  foreach ($rows as $i => $row) {
656  if ($row instanceof \ElggEntity) {
657  continue;
658  } else {
659  try {
661  } catch (IncompleteEntityException $e) {
662  // don't let incomplete entities throw fatal errors
663  unset($rows[$i]);
664 
665  // report incompletes to the batch process that spawned this query
666  if ($batch) {
667  $batch->reportIncompleteEntity($row);
668  }
669  }
670  }
671  }
672  return $rows;
673  }
674 
686  function getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs) {
687  // subtype depends upon type.
688  if ($subtypes && !$types) {
689  _elgg_services()->logger->warn("Cannot set subtypes without type.");
690  return false;
691  }
692 
693  // short circuit if nothing is requested
694  if (!$types && !$subtypes && !$pairs) {
695  return '';
696  }
697 
698  // these are the only valid types for entities in elgg
699  $valid_types = _elgg_services()->config->get('entity_types');
700 
701  // pairs override
702  $wheres = array();
703  if (!is_array($pairs)) {
704  if (!is_array($types)) {
705  $types = array($types);
706  }
707 
708  if ($subtypes && !is_array($subtypes)) {
709  $subtypes = array($subtypes);
710  }
711 
712  // decrementer for valid types. Return false if no valid types
713  $valid_types_count = count($types);
714  $valid_subtypes_count = 0;
715  // remove invalid types to get an accurate count of
716  // valid types for the invalid subtype detection to use
717  // below.
718  // also grab the count of ALL subtypes on valid types to decrement later on
719  // and check against.
720  //
721  // yes this is duplicating a foreach on $types.
722  foreach ($types as $type) {
723  if (!in_array($type, $valid_types)) {
724  $valid_types_count--;
725  unset($types[array_search($type, $types)]);
726  } else {
727  // do the checking (and decrementing) in the subtype section.
728  $valid_subtypes_count += count($subtypes);
729  }
730  }
731 
732  // return false if nothing is valid.
733  if (!$valid_types_count) {
734  return false;
735  }
736 
737  // subtypes are based upon types, so we need to look at each
738  // type individually to get the right subtype id.
739  foreach ($types as $type) {
740  $subtype_ids = array();
741  if ($subtypes) {
742  foreach ($subtypes as $subtype) {
743  // check that the subtype is valid
744  if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) {
745  // subtype value is 0
746  $subtype_ids[] = ELGG_ENTITIES_NO_VALUE;
747  } elseif (!$subtype) {
748  // subtype is ignored.
749  // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0
750  continue;
751  } else {
752  $subtype_id = get_subtype_id($type, $subtype);
753 
754  if ($subtype_id) {
755  $subtype_ids[] = $subtype_id;
756  } else {
757  $valid_subtypes_count--;
758  _elgg_services()->logger->notice("Type-subtype '$type:$subtype' does not exist!");
759  continue;
760  }
761  }
762  }
763 
764  // return false if we're all invalid subtypes in the only valid type
765  if ($valid_subtypes_count <= 0) {
766  return false;
767  }
768  }
769 
770  if (is_array($subtype_ids) && count($subtype_ids)) {
771  $subtype_ids_str = implode(',', $subtype_ids);
772  $wheres[] = "({$table}.type = '$type' AND {$table}.subtype IN ($subtype_ids_str))";
773  } else {
774  $wheres[] = "({$table}.type = '$type')";
775  }
776  }
777  } else {
778  // using type/subtype pairs
779  $valid_pairs_count = count($pairs);
780  $valid_pairs_subtypes_count = 0;
781 
782  // same deal as above--we need to know how many valid types
783  // and subtypes we have before hitting the subtype section.
784  // also normalize the subtypes into arrays here.
785  foreach ($pairs as $paired_type => $paired_subtypes) {
786  if (!in_array($paired_type, $valid_types)) {
787  $valid_pairs_count--;
788  unset($pairs[array_search($paired_type, $pairs)]);
789  } else {
790  if ($paired_subtypes && !is_array($paired_subtypes)) {
791  $pairs[$paired_type] = array($paired_subtypes);
792  }
793  $valid_pairs_subtypes_count += count($paired_subtypes);
794  }
795  }
796 
797  if ($valid_pairs_count <= 0) {
798  return false;
799  }
800  foreach ($pairs as $paired_type => $paired_subtypes) {
801  // this will always be an array because of line 2027, right?
802  // no...some overly clever person can say pair => array('object' => null)
803  if (is_array($paired_subtypes)) {
804  $paired_subtype_ids = array();
805  foreach ($paired_subtypes as $paired_subtype) {
806  if (ELGG_ENTITIES_NO_VALUE === $paired_subtype
807  || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) {
808 
809  $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ?
810  ELGG_ENTITIES_NO_VALUE : $paired_subtype_id;
811  } else {
812  $valid_pairs_subtypes_count--;
813  _elgg_services()->logger->notice("Type-subtype '$paired_type:$paired_subtype' does not exist!");
814  // return false if we're all invalid subtypes in the only valid type
815  continue;
816  }
817  }
818 
819  // return false if there are no valid subtypes.
820  if ($valid_pairs_subtypes_count <= 0) {
821  return false;
822  }
823 
824 
825  if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) {
826  $wheres[] = "({$table}.type = '$paired_type'"
827  . " AND {$table}.subtype IN ($paired_subtype_ids_str))";
828  }
829  } else {
830  $wheres[] = "({$table}.type = '$paired_type')";
831  }
832  }
833  }
834 
835  // pairs override the above. return false if they don't exist.
836  if (is_array($wheres) && count($wheres)) {
837  $where = implode(' OR ', $wheres);
838  return "($where)";
839  }
840 
841  return '';
842  }
843 
855  // short circuit if nothing requested
856  // 0 is a valid guid
857  if (!$guids && $guids !== 0) {
858  return '';
859  }
860 
861  // normalize and sanitise owners
862  if (!is_array($guids)) {
863  $guids = array($guids);
864  }
865 
866  $guids_sanitized = array();
867  foreach ($guids as $guid) {
868  if ($guid !== ELGG_ENTITIES_NO_VALUE) {
869  $guid = sanitise_int($guid);
870 
871  if (!$guid) {
872  return false;
873  }
874  }
875  $guids_sanitized[] = $guid;
876  }
877 
878  $where = '';
879  $guid_str = implode(',', $guids_sanitized);
880 
881  // implode(',', 0) returns 0.
882  if ($guid_str !== false && $guid_str !== '') {
883  $where = "($column IN ($guid_str))";
884  }
885 
886  return $where;
887  }
888 
902  function getEntityTimeWhereSql($table, $time_created_upper = null,
903  $time_created_lower = null, $time_updated_upper = null, $time_updated_lower = null) {
904 
905  $wheres = array();
906 
907  // exploit PHP's loose typing (quack) to check that they are INTs and not str cast to 0
908  if ($time_created_upper && $time_created_upper == sanitise_int($time_created_upper)) {
909  $wheres[] = "{$table}.time_created <= $time_created_upper";
910  }
911 
912  if ($time_created_lower && $time_created_lower == sanitise_int($time_created_lower)) {
913  $wheres[] = "{$table}.time_created >= $time_created_lower";
914  }
915 
916  if ($time_updated_upper && $time_updated_upper == sanitise_int($time_updated_upper)) {
917  $wheres[] = "{$table}.time_updated <= $time_updated_upper";
918  }
919 
920  if ($time_updated_lower && $time_updated_lower == sanitise_int($time_updated_lower)) {
921  $wheres[] = "{$table}.time_updated >= $time_updated_lower";
922  }
923 
924  if (is_array($wheres) && count($wheres) > 0) {
925  $where_str = implode(' AND ', $wheres);
926  return "($where_str)";
927  }
928 
929  return '';
930  }
931 
963  function getEntitiesFromAttributes(array $options = array()) {
964  $defaults = array(
965  'attribute_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
966  'attribute_name_value_pairs_operator' => 'AND',
967  );
968 
969  $options = array_merge($defaults, $options);
970 
971  $singulars = array('type', 'attribute_name_value_pair');
973 
975 
976  if ($clauses) {
977  // merge wheres to pass to elgg_get_entities()
978  if (isset($options['wheres']) && !is_array($options['wheres'])) {
979  $options['wheres'] = array($options['wheres']);
980  } elseif (!isset($options['wheres'])) {
981  $options['wheres'] = array();
982  }
983 
984  $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
985 
986  // merge joins to pass to elgg_get_entities()
987  if (isset($options['joins']) && !is_array($options['joins'])) {
988  $options['joins'] = array($options['joins']);
989  } elseif (!isset($options['joins'])) {
990  $options['joins'] = array();
991  }
992 
993  $options['joins'] = array_merge($options['joins'], $clauses['joins']);
994  }
995 
997  }
998 
1006  function getEntityAttributeWhereSql(array $options = array()) {
1007 
1008  if (!isset($options['types'])) {
1009  throw new \InvalidArgumentException("The entity type must be defined for elgg_get_entities_from_attributes()");
1010  }
1011 
1012  if (is_array($options['types']) && count($options['types']) !== 1) {
1013  throw new \InvalidArgumentException("Only one type can be passed to elgg_get_entities_from_attributes()");
1014  }
1015 
1016  // type can be passed as string or array
1017  $type = $options['types'];
1018  if (is_array($type)) {
1019  $type = $type[0];
1020  }
1021 
1022  // @todo the types should be defined somewhere (as constant on \ElggEntity?)
1023  if (!in_array($type, array('group', 'object', 'site', 'user'))) {
1024  throw new \InvalidArgumentException("Invalid type '$type' passed to elgg_get_entities_from_attributes()");
1025  }
1026 
1027 
1028  $type_table = "{$this->CONFIG->dbprefix}{$type}s_entity";
1029 
1030  $return = array(
1031  'joins' => array(),
1032  'wheres' => array(),
1033  );
1034 
1035  // short circuit if nothing requested
1036  if ($options['attribute_name_value_pairs'] == ELGG_ENTITIES_ANY_VALUE) {
1037  return $return;
1038  }
1039 
1040  if (!is_array($options['attribute_name_value_pairs'])) {
1041  throw new \InvalidArgumentException("attribute_name_value_pairs must be an array for elgg_get_entities_from_attributes()");
1042  }
1043 
1044  $wheres = array();
1045 
1046  // check if this is an array of pairs or just a single pair.
1047  $pairs = $options['attribute_name_value_pairs'];
1048  if (isset($pairs['name']) || isset($pairs['value'])) {
1049  $pairs = array($pairs);
1050  }
1051 
1052  $pair_wheres = array();
1053  foreach ($pairs as $index => $pair) {
1054  // must have at least a name and value
1055  if (!isset($pair['name']) || !isset($pair['value'])) {
1056  continue;
1057  }
1058 
1059  if (isset($pair['operand'])) {
1060  $operand = sanitize_string($pair['operand']);
1061  } else {
1062  $operand = '=';
1063  }
1064 
1065  if (is_numeric($pair['value'])) {
1066  $value = sanitize_string($pair['value']);
1067  } else if (is_array($pair['value'])) {
1068  $values_array = array();
1069  foreach ($pair['value'] as $pair_value) {
1070  if (is_numeric($pair_value)) {
1071  $values_array[] = sanitize_string($pair_value);
1072  } else {
1073  $values_array[] = "'" . sanitize_string($pair_value) . "'";
1074  }
1075  }
1076 
1077  $operand = 'IN';
1078  if ($values_array) {
1079  $value = '(' . implode(', ', $values_array) . ')';
1080  }
1081 
1082  } else {
1083  $value = "'" . sanitize_string($pair['value']) . "'";
1084  }
1085 
1086  $name = sanitize_string($pair['name']);
1087 
1088  // case sensitivity can be specified per pair
1089  $pair_binary = '';
1090  if (isset($pair['case_sensitive'])) {
1091  $pair_binary = ($pair['case_sensitive']) ? 'BINARY ' : '';
1092  }
1093 
1094  $pair_wheres[] = "({$pair_binary}type_table.$name $operand $value)";
1095  }
1096 
1097  if ($where = implode(" {$options['attribute_name_value_pairs_operator']} ", $pair_wheres)) {
1098  $return['wheres'][] = "($where)";
1099 
1100  $return['joins'][] = "JOIN $type_table type_table ON e.guid = type_table.guid";
1101  }
1102 
1103  return $return;
1104  }
1105 
1123  function getDates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0,
1124  $order_by = 'time_created') {
1125 
1126 
1127 
1128  $site_guid = (int) $site_guid;
1129  if ($site_guid == 0) {
1130  $site_guid = $this->CONFIG->site_guid;
1131  }
1132  $where = array();
1133 
1134  if ($type != "") {
1135  $type = sanitise_string($type);
1136  $where[] = "type='$type'";
1137  }
1138 
1139  if (is_array($subtype)) {
1140  $tempwhere = "";
1141  if (sizeof($subtype)) {
1142  foreach ($subtype as $typekey => $subtypearray) {
1143  foreach ($subtypearray as $subtypeval) {
1144  $typekey = sanitise_string($typekey);
1145  if (!empty($subtypeval)) {
1146  if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) {
1147  return false;
1148  }
1149  } else {
1150  $subtypeval = 0;
1151  }
1152  if (!empty($tempwhere)) {
1153  $tempwhere .= " or ";
1154  }
1155  $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})";
1156  }
1157  }
1158  }
1159  if (!empty($tempwhere)) {
1160  $where[] = "({$tempwhere})";
1161  }
1162  } else {
1163  if ($subtype) {
1164  if (!$subtype_id = get_subtype_id($type, $subtype)) {
1165  return false;
1166  } else {
1167  $where[] = "subtype=$subtype_id";
1168  }
1169  }
1170  }
1171 
1172  if ($container_guid !== 0) {
1173  if (is_array($container_guid)) {
1174  foreach ($container_guid as $key => $val) {
1175  $container_guid[$key] = (int) $val;
1176  }
1177  $where[] = "container_guid in (" . implode(",", $container_guid) . ")";
1178  } else {
1180  $where[] = "container_guid = {$container_guid}";
1181  }
1182  }
1183 
1184  if ($site_guid > 0) {
1185  $where[] = "site_guid = {$site_guid}";
1186  }
1187 
1188  $where[] = _elgg_get_access_where_sql(array('table_alias' => ''));
1189 
1190  $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth
1191  FROM {$this->CONFIG->dbprefix}entities where ";
1192 
1193  foreach ($where as $w) {
1194  $sql .= " $w and ";
1195  }
1196 
1197  $sql .= "1=1 ORDER BY $order_by";
1198  if ($result = _elgg_services()->db->getData($sql)) {
1199  $endresult = array();
1200  foreach ($result as $res) {
1201  $endresult[] = $res->yearmonth;
1202  }
1203  return $endresult;
1204  }
1205  return false;
1206  }
1207 
1220  function updateLastAction($guid, $posted = null) {
1221 
1222  $guid = (int)$guid;
1223  $posted = (int)$posted;
1224 
1225  if (!$posted) {
1226  $posted = time();
1227  }
1228 
1229  if ($guid) {
1230  //now add to the river updated table
1231  $query = "UPDATE {$this->CONFIG->dbprefix}entities SET last_action = {$posted} WHERE guid = {$guid}";
1232  $result = _elgg_services()->db->updateData($query);
1233  if ($result) {
1234  return true;
1235  } else {
1236  return false;
1237  }
1238  } else {
1239  return false;
1240  }
1241  }
1242 }
$dbprefix
Definition: index.php:13
enable($guid, $recursive=true)
Enable an entity.
$table
Definition: cron.php:28
if($guid==elgg_get_logged_in_user_guid()) $name
Definition: delete.php:21
_elgg_retrieve_cached_entity($guid)
Retrieve a entity from the cache.
Definition: entities.php:125
$e
Definition: metadata.php:12
get_subtype_id($type, $subtype)
Return the id for a given subtype.
Definition: entities.php:157
$defaults
const ELGG_ENTITIES_NO_VALUE
Definition: elgglib.php:2015
_elgg_get_guid_based_where_sql($column, $guids)
Returns SQL where clause for owner and containers.
Definition: entities.php:539
_elgg_get_entity_time_where_sql($table, $time_created_upper=null, $time_created_lower=null, $time_updated_upper=null, $time_updated_lower=null)
Returns SQL where clause for entity time limits.
Definition: entities.php:557
_elgg_cache_entity(\ElggEntity $entity)
Cache an entity.
Definition: entities.php:92
$value
Definition: longtext.php:26
$column
Definition: add.php:13
$return
Definition: opendd.php:15
if(!$count) $offset
Definition: pagination.php:26
$guid
Removes an admin notice.
autoJoinTables(array $options)
Decorate getEntities() options in order to auto-join secondary tables where it&#39;s safe to do so...
_elgg_sql_reverse_order_by_clause($order_by)
Reverses the ordering in an ORDER BY clause.
Definition: elgglib.php:1658
sanitize_string($string)
Sanitize a string for database use.
Definition: database.php:140
getRow($guid)
Returns a database row from the entities table.
Definition: EntityTable.php:45
getDates($type= '', $subtype= '', $container_guid=0, $site_guid=0, $order_by= 'time_created')
Returns a list of months in which entities were updated or created.
get_subtype_class_from_id($subtype_id)
Returns the class name for a subtype id.
Definition: entities.php:224
entity_row_to_elggstar($row)
Create an Elgg* object from a given entity row.
Definition: entities.php:371
$options
Definition: index.php:14
getEntityTimeWhereSql($table, $time_created_upper=null, $time_created_lower=null, $time_updated_upper=null, $time_updated_lower=null)
Returns SQL where clause for entity time limits.
updateLastAction($guid, $posted=null)
Update the last_action column in the entities table for $guid.
rowToElggStar($row)
Create an Elgg* object from a given entity row.
Definition: EntityTable.php:73
elgg_instanceof($entity, $type=null, $subtype=null, $class=null)
Checks if $entity is an and optionally for type and subtype.
Definition: entities.php:926
$limit
Definition: userpicker.php:38
$key
Definition: summary.php:34
getGuidBasedWhereSql($column, $guids)
Returns SQL where clause for owner and containers.
_elgg_services()
Definition: autoloader.php:14
$item
Definition: item.php:12
sanitise_string($string)
Wrapper function for alternate English spelling (.
Definition: database.php:150
const ELGG_ENTITIES_ANY_VALUE
Definition: elgglib.php:2006
elgg ElggUser
Definition: ElggUser.js:12
elgg global
Pointer to the global context.
Definition: elgglib.js:12
$type
Definition: add.php:8
getEntityAttributeWhereSql(array $options=array())
Get the join and where clauses for working with entity attributes.
access_get_show_hidden_status()
Return current status of showing disabled entities.
Definition: access.php:172
exists($guid)
Does an entity exist?
getEntities(array $options=array())
Returns an array of entities with optional filtering.
fetchFromSql($sql,\ElggBatch $batch=null)
Return entities from an SQL query generated by elgg_get_entities.
$posted
Definition: comment.php:69
$guids
access_show_hidden_entities($show_hidden)
Show or hide disabled entities.
Definition: access.php:159
$subtypes
_elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pairs)
Returns SQL where clause for type and subtype on main entity table.
Definition: entities.php:524
$row
sanitise_int($int, $signed=true)
Sanitizes an integer for database use.
Definition: database.php:173
_elgg_get_entity_attribute_where_sql(array $options=array())
Get the join and where clauses for working with entity attributes.
Definition: entities.php:674
is_memcache_available()
Return true if memcache is available and configured.
Definition: memcache.php:16
$rows
getEntitiesFromAttributes(array $options=array())
Gets entities based upon attributes in secondary tables.
$container_guid
elgg_get_entities_from_relationship($options)
Return entities matching a given query joining against a relationship.
_elgg_normalize_plural_options_array($options, $singulars)
Normalise the singular keys in an options array to plural keys.
Definition: elgglib.php:1401
sanitize_int($int, $signed=true)
Sanitizes an integer for database use.
Definition: database.php:161
getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs)
Returns SQL where clause for type and subtype on main entity table.
$entity
Definition: delete.php:10
_elgg_get_access_where_sql(array $options=array())
Returns the SQL where clause for enforcing read access to data.
Definition: access.php:216
$subtype
Definition: river.php:12
list style type
Definition: admin.php:753
_elgg_fetch_entities_from_sql($sql,\ElggBatch $batch=null)
Return entities from an SQL query generated by elgg_get_entities.
Definition: entities.php:508
$attributes
Definition: ajax_loader.php:13
get_entity($guid)
Loads and returns an entity object from a guid.
Definition: entities.php:382
$access
Definition: save.php:15
__construct()
Constructor.
Definition: EntityTable.php:26