Elgg  Version 1.11
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 
306  function getEntities(array $options = array()) {
307 
308 
309  $defaults = array(
310  'types' => ELGG_ENTITIES_ANY_VALUE,
311  'subtypes' => ELGG_ENTITIES_ANY_VALUE,
312  'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
313 
314  'guids' => ELGG_ENTITIES_ANY_VALUE,
315  'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
316  'container_guids' => ELGG_ENTITIES_ANY_VALUE,
317  'site_guids' => $this->CONFIG->site_guid,
318 
319  'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
320  'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
321  'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
322  'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
323 
324  'reverse_order_by' => false,
325  'order_by' => 'e.time_created desc',
326  'group_by' => ELGG_ENTITIES_ANY_VALUE,
327  'limit' => _elgg_services()->config->get('default_limit'),
328  'offset' => 0,
329  'count' => false,
330  'selects' => array(),
331  'wheres' => array(),
332  'joins' => array(),
333 
334  'preload_owners' => false,
335  'preload_containers' => false,
336  'callback' => 'entity_row_to_elggstar',
337  'distinct' => true,
338 
339  // private API
340  '__ElggBatch' => null,
341  );
342 
343  $options = array_merge($defaults, $options);
344 
345  // can't use helper function with type_subtype_pair because
346  // it's already an array...just need to merge it
347  if (isset($options['type_subtype_pair'])) {
348  if (isset($options['type_subtype_pairs'])) {
349  $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
350  $options['type_subtype_pair']);
351  } else {
352  $options['type_subtype_pairs'] = $options['type_subtype_pair'];
353  }
354  }
355 
356  $singulars = array('type', 'subtype', 'guid', 'owner_guid', 'container_guid', 'site_guid');
357  $options = _elgg_normalize_plural_options_array($options, $singulars);
358 
359  $options = $this->autoJoinTables($options);
360 
361  // evaluate where clauses
362  if (!is_array($options['wheres'])) {
363  $options['wheres'] = array($options['wheres']);
364  }
365 
366  $wheres = $options['wheres'];
367 
368  $wheres[] = _elgg_get_entity_type_subtype_where_sql('e', $options['types'],
369  $options['subtypes'], $options['type_subtype_pairs']);
370 
371  $wheres[] = _elgg_get_guid_based_where_sql('e.guid', $options['guids']);
372  $wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
373  $wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
374  $wheres[] = _elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
375 
376  $wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
377  $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
378 
379  // see if any functions failed
380  // remove empty strings on successful functions
381  foreach ($wheres as $i => $where) {
382  if ($where === false) {
383  return false;
384  } elseif (empty($where)) {
385  unset($wheres[$i]);
386  }
387  }
388 
389  // remove identical where clauses
390  $wheres = array_unique($wheres);
391 
392  // evaluate join clauses
393  if (!is_array($options['joins'])) {
394  $options['joins'] = array($options['joins']);
395  }
396 
397  // remove identical join clauses
398  $joins = array_unique($options['joins']);
399 
400  foreach ($joins as $i => $join) {
401  if ($join === false) {
402  return false;
403  } elseif (empty($join)) {
404  unset($joins[$i]);
405  }
406  }
407 
408  // evalutate selects
409  if ($options['selects']) {
410  $selects = '';
411  foreach ($options['selects'] as $select) {
412  $selects .= ", $select";
413  }
414  } else {
415  $selects = '';
416  }
417 
418  if (!$options['count']) {
419  $distinct = $options['distinct'] ? "DISTINCT" : "";
420  $query = "SELECT $distinct e.*{$selects} FROM {$this->CONFIG->dbprefix}entities e ";
421  } else {
422  // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than GUIDs
423  $count_expr = $options['distinct'] ? "DISTINCT e.guid" : "*";
424  $query = "SELECT COUNT($count_expr) as total FROM {$this->CONFIG->dbprefix}entities e ";
425  }
426 
427  // add joins
428  foreach ($joins as $j) {
429  $query .= " $j ";
430  }
431 
432  // add wheres
433  $query .= ' WHERE ';
434 
435  foreach ($wheres as $w) {
436  $query .= " $w AND ";
437  }
438 
439  // Add access controls
440  $query .= _elgg_get_access_where_sql();
441 
442  // reverse order by
443  if ($options['reverse_order_by']) {
444  $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']);
445  }
446 
447  if ($options['count']) {
448  $total = _elgg_services()->db->getDataRow($query);
449  return (int)$total->total;
450  }
451 
452  if ($options['group_by']) {
453  $query .= " GROUP BY {$options['group_by']}";
454  }
455 
456  if ($options['order_by']) {
457  $query .= " ORDER BY {$options['order_by']}";
458  }
459 
460  if ($options['limit']) {
461  $limit = sanitise_int($options['limit'], false);
462  $offset = sanitise_int($options['offset'], false);
463  $query .= " LIMIT $offset, $limit";
464  }
465 
466  if ($options['callback'] === 'entity_row_to_elggstar') {
467  $results = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
468  } else {
469  $results = _elgg_services()->db->getData($query, $options['callback']);
470  }
471 
472  if (!$results) {
473  // no results, no preloading
474  return $results;
475  }
476 
477  // populate entity and metadata caches, and prepare $entities for preloader
478  $guids = array();
479  foreach ($results as $item) {
480  // A custom callback could result in items that aren't \ElggEntity's, so check for them
481  if ($item instanceof \ElggEntity) {
482  _elgg_cache_entity($item);
483  // plugins usually have only settings
484  if (!$item instanceof \ElggPlugin) {
485  $guids[] = $item->guid;
486  }
487  }
488  }
489  // @todo Without this, recursive delete fails. See #4568
490  reset($results);
491 
492  if ($guids) {
493  // there were entities in the result set, preload metadata for them
494  _elgg_services()->metadataCache->populateFromEntities($guids);
495  }
496 
497  if (count($results) > 1) {
498  $props_to_preload = [];
499  if ($options['preload_owners']) {
500  $props_to_preload[] = 'owner_guid';
501  }
502  if ($options['preload_containers']) {
503  $props_to_preload[] = 'container_guid';
504  }
505  if ($props_to_preload) {
506  // note, ElggEntityPreloaderIntegrationTest assumes it can swap out
507  // the preloader after boot. If you inject this component at construction
508  // time that unit test will break. :/
509  _elgg_services()->entityPreloader->preload($results, $props_to_preload);
510  }
511  }
512 
513  return $results;
514  }
515 
523  protected function autoJoinTables(array $options) {
524  // we must be careful that the query doesn't specify any options that may join
525  // tables or change the selected columns
526  if (!is_array($options['types'])
527  || count($options['types']) !== 1
528  || !empty($options['selects'])
529  || !empty($options['wheres'])
530  || !empty($options['joins'])
531  || $options['callback'] !== 'entity_row_to_elggstar'
532  || $options['count']) {
533  // Too dangerous to auto-join
534  return $options;
535  }
536 
537  $join_types = [
538  // Each class must have a static getExternalAttributes() : array
539  'object' => 'ElggObject',
540  'user' => 'ElggUser',
541  'group' => 'ElggGroup',
542  'site' => 'ElggSite',
543  ];
544 
545  // We use reset() because $options['types'] may not have a numeric key
546  $type = reset($options['types']);
547  if (empty($join_types[$type])) {
548  return $options;
549  }
550 
551  // Get the columns we'll need to select. We can't use st.* because the order_by
552  // clause may reference "guid", which MySQL will complain about being ambiguous
553  if (!is_callable([$join_types[$type], 'getExternalAttributes'])) {
554  // for some reason can't get external attributes.
555  return $options;
556  }
557 
558  $attributes = $join_types[$type]::getExternalAttributes();
559  foreach (array_keys($attributes) as $col) {
560  $options['selects'][] = "st.$col";
561  }
562 
563  // join the secondary table
564  $options['joins'][] = "JOIN {$this->CONFIG->dbprefix}{$type}s_entity st ON (e.guid = st.guid)";
565 
566  return $options;
567  }
568 
579  function fetchFromSql($sql, \ElggBatch $batch = null) {
580  static $plugin_subtype;
581  if (null === $plugin_subtype) {
582  $plugin_subtype = get_subtype_id('object', 'plugin');
583  }
584 
585  // Keys are types, values are columns that, if present, suggest that the secondary
586  // table is already JOINed. Note it's OK if guess incorrectly because entity load()
587  // will fetch any missing attributes.
588  $types_to_optimize = array(
589  'object' => 'title',
590  'user' => 'password',
591  'group' => 'name',
592  'site' => 'url',
593  );
594 
595  $rows = _elgg_services()->db->getData($sql);
596 
597  // guids to look up in each type
598  $lookup_types = array();
599  // maps GUIDs to the $rows key
600  $guid_to_key = array();
601 
602  if (isset($rows[0]->type, $rows[0]->subtype)
603  && $rows[0]->type === 'object'
604  && $rows[0]->subtype == $plugin_subtype) {
605  // Likely the entire resultset is plugins, which have already been optimized
606  // to JOIN the secondary table. In this case we allow retrieving from cache,
607  // but abandon the extra queries.
608  $types_to_optimize = array();
609  }
610 
611  // First pass: use cache where possible, gather GUIDs that we're optimizing
612  foreach ($rows as $i => $row) {
613  if (empty($row->guid) || empty($row->type)) {
614  throw new \LogicException('Entity row missing guid or type');
615  }
617  if ($entity) {
618  $entity->refresh($row);
619  $rows[$i] = $entity;
620  continue;
621  }
622  if (isset($types_to_optimize[$row->type])) {
623  // check if row already looks JOINed.
624  if (isset($row->{$types_to_optimize[$row->type]})) {
625  // Row probably already contains JOINed secondary table. Don't make another query just
626  // to pull data that's already there
627  continue;
628  }
629  $lookup_types[$row->type][] = $row->guid;
630  $guid_to_key[$row->guid] = $i;
631  }
632  }
633  // Do secondary queries and merge rows
634  if ($lookup_types) {
635  $dbprefix = _elgg_services()->config->get('dbprefix');
636 
637  foreach ($lookup_types as $type => $guids) {
638  $set = "(" . implode(',', $guids) . ")";
639  $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set";
640  $secondary_rows = _elgg_services()->db->getData($sql);
641  if ($secondary_rows) {
642  foreach ($secondary_rows as $secondary_row) {
643  $key = $guid_to_key[$secondary_row->guid];
644  // cast to arrays to merge then cast back
645  $rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row);
646  }
647  }
648  }
649  }
650  // Second pass to finish conversion
651  foreach ($rows as $i => $row) {
652  if ($row instanceof \ElggEntity) {
653  continue;
654  } else {
655  try {
657  } catch (IncompleteEntityException $e) {
658  // don't let incomplete entities throw fatal errors
659  unset($rows[$i]);
660 
661  // report incompletes to the batch process that spawned this query
662  if ($batch) {
663  $batch->reportIncompleteEntity($row);
664  }
665  }
666  }
667  }
668  return $rows;
669  }
670 
682  function getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs) {
683  // subtype depends upon type.
684  if ($subtypes && !$types) {
685  _elgg_services()->logger->warn("Cannot set subtypes without type.");
686  return false;
687  }
688 
689  // short circuit if nothing is requested
690  if (!$types && !$subtypes && !$pairs) {
691  return '';
692  }
693 
694  // these are the only valid types for entities in elgg
695  $valid_types = _elgg_services()->config->get('entity_types');
696 
697  // pairs override
698  $wheres = array();
699  if (!is_array($pairs)) {
700  if (!is_array($types)) {
701  $types = array($types);
702  }
703 
704  if ($subtypes && !is_array($subtypes)) {
705  $subtypes = array($subtypes);
706  }
707 
708  // decrementer for valid types. Return false if no valid types
709  $valid_types_count = count($types);
710  $valid_subtypes_count = 0;
711  // remove invalid types to get an accurate count of
712  // valid types for the invalid subtype detection to use
713  // below.
714  // also grab the count of ALL subtypes on valid types to decrement later on
715  // and check against.
716  //
717  // yes this is duplicating a foreach on $types.
718  foreach ($types as $type) {
719  if (!in_array($type, $valid_types)) {
720  $valid_types_count--;
721  unset($types[array_search($type, $types)]);
722  } else {
723  // do the checking (and decrementing) in the subtype section.
724  $valid_subtypes_count += count($subtypes);
725  }
726  }
727 
728  // return false if nothing is valid.
729  if (!$valid_types_count) {
730  return false;
731  }
732 
733  // subtypes are based upon types, so we need to look at each
734  // type individually to get the right subtype id.
735  foreach ($types as $type) {
736  $subtype_ids = array();
737  if ($subtypes) {
738  foreach ($subtypes as $subtype) {
739  // check that the subtype is valid
740  if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) {
741  // subtype value is 0
742  $subtype_ids[] = ELGG_ENTITIES_NO_VALUE;
743  } elseif (!$subtype) {
744  // subtype is ignored.
745  // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0
746  continue;
747  } else {
748  $subtype_id = get_subtype_id($type, $subtype);
749 
750  if ($subtype_id) {
751  $subtype_ids[] = $subtype_id;
752  } else {
753  $valid_subtypes_count--;
754  _elgg_services()->logger->notice("Type-subtype '$type:$subtype' does not exist!");
755  continue;
756  }
757  }
758  }
759 
760  // return false if we're all invalid subtypes in the only valid type
761  if ($valid_subtypes_count <= 0) {
762  return false;
763  }
764  }
765 
766  if (is_array($subtype_ids) && count($subtype_ids)) {
767  $subtype_ids_str = implode(',', $subtype_ids);
768  $wheres[] = "({$table}.type = '$type' AND {$table}.subtype IN ($subtype_ids_str))";
769  } else {
770  $wheres[] = "({$table}.type = '$type')";
771  }
772  }
773  } else {
774  // using type/subtype pairs
775  $valid_pairs_count = count($pairs);
776  $valid_pairs_subtypes_count = 0;
777 
778  // same deal as above--we need to know how many valid types
779  // and subtypes we have before hitting the subtype section.
780  // also normalize the subtypes into arrays here.
781  foreach ($pairs as $paired_type => $paired_subtypes) {
782  if (!in_array($paired_type, $valid_types)) {
783  $valid_pairs_count--;
784  unset($pairs[array_search($paired_type, $pairs)]);
785  } else {
786  if ($paired_subtypes && !is_array($paired_subtypes)) {
787  $pairs[$paired_type] = array($paired_subtypes);
788  }
789  $valid_pairs_subtypes_count += count($paired_subtypes);
790  }
791  }
792 
793  if ($valid_pairs_count <= 0) {
794  return false;
795  }
796  foreach ($pairs as $paired_type => $paired_subtypes) {
797  // this will always be an array because of line 2027, right?
798  // no...some overly clever person can say pair => array('object' => null)
799  if (is_array($paired_subtypes)) {
800  $paired_subtype_ids = array();
801  foreach ($paired_subtypes as $paired_subtype) {
802  if (ELGG_ENTITIES_NO_VALUE === $paired_subtype
803  || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) {
804 
805  $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ?
806  ELGG_ENTITIES_NO_VALUE : $paired_subtype_id;
807  } else {
808  $valid_pairs_subtypes_count--;
809  _elgg_services()->logger->notice("Type-subtype '$paired_type:$paired_subtype' does not exist!");
810  // return false if we're all invalid subtypes in the only valid type
811  continue;
812  }
813  }
814 
815  // return false if there are no valid subtypes.
816  if ($valid_pairs_subtypes_count <= 0) {
817  return false;
818  }
819 
820 
821  if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) {
822  $wheres[] = "({$table}.type = '$paired_type'"
823  . " AND {$table}.subtype IN ($paired_subtype_ids_str))";
824  }
825  } else {
826  $wheres[] = "({$table}.type = '$paired_type')";
827  }
828  }
829  }
830 
831  // pairs override the above. return false if they don't exist.
832  if (is_array($wheres) && count($wheres)) {
833  $where = implode(' OR ', $wheres);
834  return "($where)";
835  }
836 
837  return '';
838  }
839 
851  // short circuit if nothing requested
852  // 0 is a valid guid
853  if (!$guids && $guids !== 0) {
854  return '';
855  }
856 
857  // normalize and sanitise owners
858  if (!is_array($guids)) {
859  $guids = array($guids);
860  }
861 
862  $guids_sanitized = array();
863  foreach ($guids as $guid) {
864  if ($guid !== ELGG_ENTITIES_NO_VALUE) {
865  $guid = sanitise_int($guid);
866 
867  if (!$guid) {
868  return false;
869  }
870  }
871  $guids_sanitized[] = $guid;
872  }
873 
874  $where = '';
875  $guid_str = implode(',', $guids_sanitized);
876 
877  // implode(',', 0) returns 0.
878  if ($guid_str !== false && $guid_str !== '') {
879  $where = "($column IN ($guid_str))";
880  }
881 
882  return $where;
883  }
884 
898  function getEntityTimeWhereSql($table, $time_created_upper = null,
899  $time_created_lower = null, $time_updated_upper = null, $time_updated_lower = null) {
900 
901  $wheres = array();
902 
903  // exploit PHP's loose typing (quack) to check that they are INTs and not str cast to 0
904  if ($time_created_upper && $time_created_upper == sanitise_int($time_created_upper)) {
905  $wheres[] = "{$table}.time_created <= $time_created_upper";
906  }
907 
908  if ($time_created_lower && $time_created_lower == sanitise_int($time_created_lower)) {
909  $wheres[] = "{$table}.time_created >= $time_created_lower";
910  }
911 
912  if ($time_updated_upper && $time_updated_upper == sanitise_int($time_updated_upper)) {
913  $wheres[] = "{$table}.time_updated <= $time_updated_upper";
914  }
915 
916  if ($time_updated_lower && $time_updated_lower == sanitise_int($time_updated_lower)) {
917  $wheres[] = "{$table}.time_updated >= $time_updated_lower";
918  }
919 
920  if (is_array($wheres) && count($wheres) > 0) {
921  $where_str = implode(' AND ', $wheres);
922  return "($where_str)";
923  }
924 
925  return '';
926  }
927 
959  function getEntitiesFromAttributes(array $options = array()) {
960  $defaults = array(
961  'attribute_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
962  'attribute_name_value_pairs_operator' => 'AND',
963  );
964 
965  $options = array_merge($defaults, $options);
966 
967  $singulars = array('type', 'attribute_name_value_pair');
969 
971 
972  if ($clauses) {
973  // merge wheres to pass to elgg_get_entities()
974  if (isset($options['wheres']) && !is_array($options['wheres'])) {
975  $options['wheres'] = array($options['wheres']);
976  } elseif (!isset($options['wheres'])) {
977  $options['wheres'] = array();
978  }
979 
980  $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
981 
982  // merge joins to pass to elgg_get_entities()
983  if (isset($options['joins']) && !is_array($options['joins'])) {
984  $options['joins'] = array($options['joins']);
985  } elseif (!isset($options['joins'])) {
986  $options['joins'] = array();
987  }
988 
989  $options['joins'] = array_merge($options['joins'], $clauses['joins']);
990  }
991 
993  }
994 
1002  function getEntityAttributeWhereSql(array $options = array()) {
1003 
1004  if (!isset($options['types'])) {
1005  throw new \InvalidArgumentException("The entity type must be defined for elgg_get_entities_from_attributes()");
1006  }
1007 
1008  if (is_array($options['types']) && count($options['types']) !== 1) {
1009  throw new \InvalidArgumentException("Only one type can be passed to elgg_get_entities_from_attributes()");
1010  }
1011 
1012  // type can be passed as string or array
1013  $type = $options['types'];
1014  if (is_array($type)) {
1015  $type = $type[0];
1016  }
1017 
1018  // @todo the types should be defined somewhere (as constant on \ElggEntity?)
1019  if (!in_array($type, array('group', 'object', 'site', 'user'))) {
1020  throw new \InvalidArgumentException("Invalid type '$type' passed to elgg_get_entities_from_attributes()");
1021  }
1022 
1023 
1024  $type_table = "{$this->CONFIG->dbprefix}{$type}s_entity";
1025 
1026  $return = array(
1027  'joins' => array(),
1028  'wheres' => array(),
1029  );
1030 
1031  // short circuit if nothing requested
1032  if ($options['attribute_name_value_pairs'] == ELGG_ENTITIES_ANY_VALUE) {
1033  return $return;
1034  }
1035 
1036  if (!is_array($options['attribute_name_value_pairs'])) {
1037  throw new \InvalidArgumentException("attribute_name_value_pairs must be an array for elgg_get_entities_from_attributes()");
1038  }
1039 
1040  $wheres = array();
1041 
1042  // check if this is an array of pairs or just a single pair.
1043  $pairs = $options['attribute_name_value_pairs'];
1044  if (isset($pairs['name']) || isset($pairs['value'])) {
1045  $pairs = array($pairs);
1046  }
1047 
1048  $pair_wheres = array();
1049  foreach ($pairs as $index => $pair) {
1050  // must have at least a name and value
1051  if (!isset($pair['name']) || !isset($pair['value'])) {
1052  continue;
1053  }
1054 
1055  if (isset($pair['operand'])) {
1056  $operand = sanitize_string($pair['operand']);
1057  } else {
1058  $operand = '=';
1059  }
1060 
1061  if (is_numeric($pair['value'])) {
1062  $value = sanitize_string($pair['value']);
1063  } else if (is_array($pair['value'])) {
1064  $values_array = array();
1065  foreach ($pair['value'] as $pair_value) {
1066  if (is_numeric($pair_value)) {
1067  $values_array[] = sanitize_string($pair_value);
1068  } else {
1069  $values_array[] = "'" . sanitize_string($pair_value) . "'";
1070  }
1071  }
1072 
1073  $operand = 'IN';
1074  if ($values_array) {
1075  $value = '(' . implode(', ', $values_array) . ')';
1076  }
1077 
1078  } else {
1079  $value = "'" . sanitize_string($pair['value']) . "'";
1080  }
1081 
1082  $name = sanitize_string($pair['name']);
1083 
1084  // case sensitivity can be specified per pair
1085  $pair_binary = '';
1086  if (isset($pair['case_sensitive'])) {
1087  $pair_binary = ($pair['case_sensitive']) ? 'BINARY ' : '';
1088  }
1089 
1090  $pair_wheres[] = "({$pair_binary}type_table.$name $operand $value)";
1091  }
1092 
1093  if ($where = implode(" {$options['attribute_name_value_pairs_operator']} ", $pair_wheres)) {
1094  $return['wheres'][] = "($where)";
1095 
1096  $return['joins'][] = "JOIN $type_table type_table ON e.guid = type_table.guid";
1097  }
1098 
1099  return $return;
1100  }
1101 
1119  function getDates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0,
1120  $order_by = 'time_created') {
1121 
1122 
1123 
1124  $site_guid = (int) $site_guid;
1125  if ($site_guid == 0) {
1126  $site_guid = $this->CONFIG->site_guid;
1127  }
1128  $where = array();
1129 
1130  if ($type != "") {
1131  $type = sanitise_string($type);
1132  $where[] = "type='$type'";
1133  }
1134 
1135  if (is_array($subtype)) {
1136  $tempwhere = "";
1137  if (sizeof($subtype)) {
1138  foreach ($subtype as $typekey => $subtypearray) {
1139  foreach ($subtypearray as $subtypeval) {
1140  $typekey = sanitise_string($typekey);
1141  if (!empty($subtypeval)) {
1142  if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) {
1143  return false;
1144  }
1145  } else {
1146  $subtypeval = 0;
1147  }
1148  if (!empty($tempwhere)) {
1149  $tempwhere .= " or ";
1150  }
1151  $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})";
1152  }
1153  }
1154  }
1155  if (!empty($tempwhere)) {
1156  $where[] = "({$tempwhere})";
1157  }
1158  } else {
1159  if ($subtype) {
1160  if (!$subtype_id = get_subtype_id($type, $subtype)) {
1161  return false;
1162  } else {
1163  $where[] = "subtype=$subtype_id";
1164  }
1165  }
1166  }
1167 
1168  if ($container_guid !== 0) {
1169  if (is_array($container_guid)) {
1170  foreach ($container_guid as $key => $val) {
1171  $container_guid[$key] = (int) $val;
1172  }
1173  $where[] = "container_guid in (" . implode(",", $container_guid) . ")";
1174  } else {
1176  $where[] = "container_guid = {$container_guid}";
1177  }
1178  }
1179 
1180  if ($site_guid > 0) {
1181  $where[] = "site_guid = {$site_guid}";
1182  }
1183 
1184  $where[] = _elgg_get_access_where_sql(array('table_alias' => ''));
1185 
1186  $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth
1187  FROM {$this->CONFIG->dbprefix}entities where ";
1188 
1189  foreach ($where as $w) {
1190  $sql .= " $w and ";
1191  }
1192 
1193  $sql .= "1=1 ORDER BY $order_by";
1194  if ($result = _elgg_services()->db->getData($sql)) {
1195  $endresult = array();
1196  foreach ($result as $res) {
1197  $endresult[] = $res->yearmonth;
1198  }
1199  return $endresult;
1200  }
1201  return false;
1202  }
1203 
1216  function updateLastAction($guid, $posted = null) {
1217 
1218  $guid = (int)$guid;
1219  $posted = (int)$posted;
1220 
1221  if (!$posted) {
1222  $posted = time();
1223  }
1224 
1225  if ($guid) {
1226  //now add to the river updated table
1227  $query = "UPDATE {$this->CONFIG->dbprefix}entities SET last_action = {$posted} WHERE guid = {$guid}";
1228  $result = _elgg_services()->db->updateData($query);
1229  if ($result) {
1230  return true;
1231  } else {
1232  return false;
1233  }
1234  } else {
1235  return false;
1236  }
1237  }
1238 }
$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:1976
_elgg_get_guid_based_where_sql($column, $guids)
Returns SQL where clause for owner and containers.
Definition: entities.php:535
_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:553
_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:25
$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:1619
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:922
$limit
Definition: userpicker.php:31
$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:1967
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:520
$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:670
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:1376
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:748
_elgg_fetch_entities_from_sql($sql,\ElggBatch $batch=null)
Return entities from an SQL query generated by elgg_get_entities.
Definition: entities.php:504
$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