Elgg  Version 1.10
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 
147  function get($guid) {
148  // This should not be a static local var. Notice that cache writing occurs in a completely
149  // different instance outside this function.
150  // @todo We need a single Memcache instance with a shared pool of namespace wrappers. This function would pull an instance from the pool.
151  static $shared_cache;
152 
153  // We could also use: if (!(int) $guid) { return false },
154  // but that evaluates to a false positive for $guid = true.
155  // This is a bit slower, but more thorough.
156  if (!is_numeric($guid) || $guid === 0 || $guid === '0') {
157  return false;
158  }
159 
160  // Check local cache first
161  $new_entity = _elgg_retrieve_cached_entity($guid);
162  if ($new_entity) {
163  return $new_entity;
164  }
165 
166  // Check shared memory cache, if available
167  if (null === $shared_cache) {
168  if (is_memcache_available()) {
169  $shared_cache = new \ElggMemcache('new_entity_cache');
170  } else {
171  $shared_cache = false;
172  }
173  }
174 
175  // until ACLs in memcache, DB query is required to determine access
176  $entity_row = get_entity_as_row($guid);
177  if (!$entity_row) {
178  return false;
179  }
180 
181  if ($shared_cache) {
182  $cached_entity = $shared_cache->load($guid);
183  // @todo store ACLs in memcache https://github.com/elgg/elgg/issues/3018#issuecomment-13662617
184  if ($cached_entity) {
185  // @todo use ACL and cached entity access_id to determine if user can see it
186  return $cached_entity;
187  }
188  }
189 
190  // don't let incomplete entities cause fatal exceptions
191  try {
192  $new_entity = entity_row_to_elggstar($entity_row);
193  } catch (IncompleteEntityException $e) {
194  return false;
195  }
196 
197  if ($new_entity) {
198  _elgg_cache_entity($new_entity);
199  }
200  return $new_entity;
201  }
202 
215  function exists($guid) {
216 
217 
219 
220  $query = "SELECT count(*) as total FROM {$this->CONFIG->dbprefix}entities WHERE guid = $guid";
221  $result = _elgg_services()->db->getDataRow($query);
222  if ($result->total == 0) {
223  return false;
224  } else {
225  return true;
226  }
227  }
228 
237  function enable($guid, $recursive = true) {
238 
239  // Override access only visible entities
240  $old_access_status = access_get_show_hidden_status();
242 
243  $result = false;
245  if ($entity) {
246  $result = $entity->enable($recursive);
247  }
248 
249  access_show_hidden_entities($old_access_status);
250  return $result;
251  }
252 
326  function getEntities(array $options = array()) {
327 
328 
329  $defaults = array(
330  'types' => ELGG_ENTITIES_ANY_VALUE,
331  'subtypes' => ELGG_ENTITIES_ANY_VALUE,
332  'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
333 
334  'guids' => ELGG_ENTITIES_ANY_VALUE,
335  'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
336  'container_guids' => ELGG_ENTITIES_ANY_VALUE,
337  'site_guids' => $this->CONFIG->site_guid,
338 
339  'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
340  'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
341  'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
342  'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
343 
344  'reverse_order_by' => false,
345  'order_by' => 'e.time_created desc',
346  'group_by' => ELGG_ENTITIES_ANY_VALUE,
347  'limit' => _elgg_services()->config->get('default_limit'),
348  'offset' => 0,
349  'count' => false,
350  'selects' => array(),
351  'wheres' => array(),
352  'joins' => array(),
353 
354  'preload_owners' => false,
355  'callback' => 'entity_row_to_elggstar',
356  'distinct' => true,
357 
358  // private API
359  '__ElggBatch' => null,
360  );
361 
362  $options = array_merge($defaults, $options);
363 
364  // can't use helper function with type_subtype_pair because
365  // it's already an array...just need to merge it
366  if (isset($options['type_subtype_pair'])) {
367  if (isset($options['type_subtype_pairs'])) {
368  $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
369  $options['type_subtype_pair']);
370  } else {
371  $options['type_subtype_pairs'] = $options['type_subtype_pair'];
372  }
373  }
374 
375  $singulars = array('type', 'subtype', 'guid', 'owner_guid', 'container_guid', 'site_guid');
376  $options = _elgg_normalize_plural_options_array($options, $singulars);
377 
378  // evaluate where clauses
379  if (!is_array($options['wheres'])) {
380  $options['wheres'] = array($options['wheres']);
381  }
382 
383  $wheres = $options['wheres'];
384 
385  $wheres[] = _elgg_get_entity_type_subtype_where_sql('e', $options['types'],
386  $options['subtypes'], $options['type_subtype_pairs']);
387 
388  $wheres[] = _elgg_get_guid_based_where_sql('e.guid', $options['guids']);
389  $wheres[] = _elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
390  $wheres[] = _elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
391  $wheres[] = _elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
392 
393  $wheres[] = _elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
394  $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
395 
396  // see if any functions failed
397  // remove empty strings on successful functions
398  foreach ($wheres as $i => $where) {
399  if ($where === false) {
400  return false;
401  } elseif (empty($where)) {
402  unset($wheres[$i]);
403  }
404  }
405 
406  // remove identical where clauses
407  $wheres = array_unique($wheres);
408 
409  // evaluate join clauses
410  if (!is_array($options['joins'])) {
411  $options['joins'] = array($options['joins']);
412  }
413 
414  // remove identical join clauses
415  $joins = array_unique($options['joins']);
416 
417  foreach ($joins as $i => $join) {
418  if ($join === false) {
419  return false;
420  } elseif (empty($join)) {
421  unset($joins[$i]);
422  }
423  }
424 
425  // evalutate selects
426  if ($options['selects']) {
427  $selects = '';
428  foreach ($options['selects'] as $select) {
429  $selects .= ", $select";
430  }
431  } else {
432  $selects = '';
433  }
434 
435  if (!$options['count']) {
436  $distinct = $options['distinct'] ? "DISTINCT" : "";
437  $query = "SELECT $distinct e.*{$selects} FROM {$this->CONFIG->dbprefix}entities e ";
438  } else {
439  // note: when DISTINCT unneeded, it's slightly faster to compute COUNT(*) than GUIDs
440  $count_expr = $options['distinct'] ? "DISTINCT e.guid" : "*";
441  $query = "SELECT COUNT($count_expr) as total FROM {$this->CONFIG->dbprefix}entities e ";
442  }
443 
444  // add joins
445  foreach ($joins as $j) {
446  $query .= " $j ";
447  }
448 
449  // add wheres
450  $query .= ' WHERE ';
451 
452  foreach ($wheres as $w) {
453  $query .= " $w AND ";
454  }
455 
456  // Add access controls
457  $query .= _elgg_get_access_where_sql();
458 
459  // reverse order by
460  if ($options['reverse_order_by']) {
461  $options['order_by'] = _elgg_sql_reverse_order_by_clause($options['order_by']);
462  }
463 
464  if (!$options['count']) {
465  if ($options['group_by']) {
466  $query .= " GROUP BY {$options['group_by']}";
467  }
468 
469  if ($options['order_by']) {
470  $query .= " ORDER BY {$options['order_by']}";
471  }
472 
473  if ($options['limit']) {
474  $limit = sanitise_int($options['limit'], false);
475  $offset = sanitise_int($options['offset'], false);
476  $query .= " LIMIT $offset, $limit";
477  }
478 
479  if ($options['callback'] === 'entity_row_to_elggstar') {
480  $dt = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
481  } else {
482  $dt = _elgg_services()->db->getData($query, $options['callback']);
483  }
484 
485  if ($dt) {
486  // populate entity and metadata caches, and prepare $entities for preloader
487  $guids = array();
488  foreach ($dt as $item) {
489  // A custom callback could result in items that aren't \ElggEntity's, so check for them
490  if ($item instanceof \ElggEntity) {
491  _elgg_cache_entity($item);
492  // plugins usually have only settings
493  if (!$item instanceof \ElggPlugin) {
494  $guids[] = $item->guid;
495  }
496  }
497  }
498  // @todo Without this, recursive delete fails. See #4568
499  reset($dt);
500 
501  if ($guids) {
502  _elgg_services()->metadataCache->populateFromEntities($guids);
503  }
504 
505  if ($options['preload_owners'] && count($dt) > 1) {
506  _elgg_services()->ownerPreloader->preload($dt);
507  }
508  }
509  return $dt;
510  } else {
511  $total = _elgg_services()->db->getDataRow($query);
512  return (int)$total->total;
513  }
514  }
515 
526  function fetchFromSql($sql, \ElggBatch $batch = null) {
527  static $plugin_subtype;
528  if (null === $plugin_subtype) {
529  $plugin_subtype = get_subtype_id('object', 'plugin');
530  }
531 
532  // Keys are types, values are columns that, if present, suggest that the secondary
533  // table is already JOINed
534  $types_to_optimize = array(
535  'object' => 'title',
536  'user' => 'password',
537  'group' => 'name',
538  );
539 
540  $rows = _elgg_services()->db->getData($sql);
541 
542  // guids to look up in each type
543  $lookup_types = array();
544  // maps GUIDs to the $rows key
545  $guid_to_key = array();
546 
547  if (isset($rows[0]->type, $rows[0]->subtype)
548  && $rows[0]->type === 'object'
549  && $rows[0]->subtype == $plugin_subtype) {
550  // Likely the entire resultset is plugins, which have already been optimized
551  // to JOIN the secondary table. In this case we allow retrieving from cache,
552  // but abandon the extra queries.
553  $types_to_optimize = array();
554  }
555 
556  // First pass: use cache where possible, gather GUIDs that we're optimizing
557  foreach ($rows as $i => $row) {
558  if (empty($row->guid) || empty($row->type)) {
559  throw new \LogicException('Entity row missing guid or type');
560  }
562  if ($entity) {
563  $entity->refresh($row);
564  $rows[$i] = $entity;
565  continue;
566  }
567  if (isset($types_to_optimize[$row->type])) {
568  // check if row already looks JOINed.
569  if (isset($row->{$types_to_optimize[$row->type]})) {
570  // Row probably already contains JOINed secondary table. Don't make another query just
571  // to pull data that's already there
572  continue;
573  }
574  $lookup_types[$row->type][] = $row->guid;
575  $guid_to_key[$row->guid] = $i;
576  }
577  }
578  // Do secondary queries and merge rows
579  if ($lookup_types) {
580  $dbprefix = _elgg_services()->config->get('dbprefix');
581 
582  foreach ($lookup_types as $type => $guids) {
583  $set = "(" . implode(',', $guids) . ")";
584  $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set";
585  $secondary_rows = _elgg_services()->db->getData($sql);
586  if ($secondary_rows) {
587  foreach ($secondary_rows as $secondary_row) {
588  $key = $guid_to_key[$secondary_row->guid];
589  // cast to arrays to merge then cast back
590  $rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row);
591  }
592  }
593  }
594  }
595  // Second pass to finish conversion
596  foreach ($rows as $i => $row) {
597  if ($row instanceof \ElggEntity) {
598  continue;
599  } else {
600  try {
602  } catch (IncompleteEntityException $e) {
603  // don't let incomplete entities throw fatal errors
604  unset($rows[$i]);
605 
606  // report incompletes to the batch process that spawned this query
607  if ($batch) {
608  $batch->reportIncompleteEntity($row);
609  }
610  }
611  }
612  }
613  return $rows;
614  }
615 
627  function getEntityTypeSubtypeWhereSql($table, $types, $subtypes, $pairs) {
628  // subtype depends upon type.
629  if ($subtypes && !$types) {
630  _elgg_services()->logger->warn("Cannot set subtypes without type.");
631  return false;
632  }
633 
634  // short circuit if nothing is requested
635  if (!$types && !$subtypes && !$pairs) {
636  return '';
637  }
638 
639  // these are the only valid types for entities in elgg
640  $valid_types = _elgg_services()->config->get('entity_types');
641 
642  // pairs override
643  $wheres = array();
644  if (!is_array($pairs)) {
645  if (!is_array($types)) {
646  $types = array($types);
647  }
648 
649  if ($subtypes && !is_array($subtypes)) {
650  $subtypes = array($subtypes);
651  }
652 
653  // decrementer for valid types. Return false if no valid types
654  $valid_types_count = count($types);
655  $valid_subtypes_count = 0;
656  // remove invalid types to get an accurate count of
657  // valid types for the invalid subtype detection to use
658  // below.
659  // also grab the count of ALL subtypes on valid types to decrement later on
660  // and check against.
661  //
662  // yes this is duplicating a foreach on $types.
663  foreach ($types as $type) {
664  if (!in_array($type, $valid_types)) {
665  $valid_types_count--;
666  unset($types[array_search($type, $types)]);
667  } else {
668  // do the checking (and decrementing) in the subtype section.
669  $valid_subtypes_count += count($subtypes);
670  }
671  }
672 
673  // return false if nothing is valid.
674  if (!$valid_types_count) {
675  return false;
676  }
677 
678  // subtypes are based upon types, so we need to look at each
679  // type individually to get the right subtype id.
680  foreach ($types as $type) {
681  $subtype_ids = array();
682  if ($subtypes) {
683  foreach ($subtypes as $subtype) {
684  // check that the subtype is valid
685  if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) {
686  // subtype value is 0
687  $subtype_ids[] = ELGG_ENTITIES_NO_VALUE;
688  } elseif (!$subtype) {
689  // subtype is ignored.
690  // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0
691  continue;
692  } else {
693  $subtype_id = get_subtype_id($type, $subtype);
694 
695  if ($subtype_id) {
696  $subtype_ids[] = $subtype_id;
697  } else {
698  $valid_subtypes_count--;
699  _elgg_services()->logger->notice("Type-subtype '$type:$subtype' does not exist!");
700  continue;
701  }
702  }
703  }
704 
705  // return false if we're all invalid subtypes in the only valid type
706  if ($valid_subtypes_count <= 0) {
707  return false;
708  }
709  }
710 
711  if (is_array($subtype_ids) && count($subtype_ids)) {
712  $subtype_ids_str = implode(',', $subtype_ids);
713  $wheres[] = "({$table}.type = '$type' AND {$table}.subtype IN ($subtype_ids_str))";
714  } else {
715  $wheres[] = "({$table}.type = '$type')";
716  }
717  }
718  } else {
719  // using type/subtype pairs
720  $valid_pairs_count = count($pairs);
721  $valid_pairs_subtypes_count = 0;
722 
723  // same deal as above--we need to know how many valid types
724  // and subtypes we have before hitting the subtype section.
725  // also normalize the subtypes into arrays here.
726  foreach ($pairs as $paired_type => $paired_subtypes) {
727  if (!in_array($paired_type, $valid_types)) {
728  $valid_pairs_count--;
729  unset($pairs[array_search($paired_type, $pairs)]);
730  } else {
731  if ($paired_subtypes && !is_array($paired_subtypes)) {
732  $pairs[$paired_type] = array($paired_subtypes);
733  }
734  $valid_pairs_subtypes_count += count($paired_subtypes);
735  }
736  }
737 
738  if ($valid_pairs_count <= 0) {
739  return false;
740  }
741  foreach ($pairs as $paired_type => $paired_subtypes) {
742  // this will always be an array because of line 2027, right?
743  // no...some overly clever person can say pair => array('object' => null)
744  if (is_array($paired_subtypes)) {
745  $paired_subtype_ids = array();
746  foreach ($paired_subtypes as $paired_subtype) {
747  if (ELGG_ENTITIES_NO_VALUE === $paired_subtype
748  || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) {
749 
750  $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ?
751  ELGG_ENTITIES_NO_VALUE : $paired_subtype_id;
752  } else {
753  $valid_pairs_subtypes_count--;
754  _elgg_services()->logger->notice("Type-subtype '$paired_type:$paired_subtype' does not exist!");
755  // return false if we're all invalid subtypes in the only valid type
756  continue;
757  }
758  }
759 
760  // return false if there are no valid subtypes.
761  if ($valid_pairs_subtypes_count <= 0) {
762  return false;
763  }
764 
765 
766  if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) {
767  $wheres[] = "({$table}.type = '$paired_type'"
768  . " AND {$table}.subtype IN ($paired_subtype_ids_str))";
769  }
770  } else {
771  $wheres[] = "({$table}.type = '$paired_type')";
772  }
773  }
774  }
775 
776  // pairs override the above. return false if they don't exist.
777  if (is_array($wheres) && count($wheres)) {
778  $where = implode(' OR ', $wheres);
779  return "($where)";
780  }
781 
782  return '';
783  }
784 
796  // short circuit if nothing requested
797  // 0 is a valid guid
798  if (!$guids && $guids !== 0) {
799  return '';
800  }
801 
802  // normalize and sanitise owners
803  if (!is_array($guids)) {
804  $guids = array($guids);
805  }
806 
807  $guids_sanitized = array();
808  foreach ($guids as $guid) {
809  if ($guid !== ELGG_ENTITIES_NO_VALUE) {
810  $guid = sanitise_int($guid);
811 
812  if (!$guid) {
813  return false;
814  }
815  }
816  $guids_sanitized[] = $guid;
817  }
818 
819  $where = '';
820  $guid_str = implode(',', $guids_sanitized);
821 
822  // implode(',', 0) returns 0.
823  if ($guid_str !== false && $guid_str !== '') {
824  $where = "($column IN ($guid_str))";
825  }
826 
827  return $where;
828  }
829 
843  function getEntityTimeWhereSql($table, $time_created_upper = null,
844  $time_created_lower = null, $time_updated_upper = null, $time_updated_lower = null) {
845 
846  $wheres = array();
847 
848  // exploit PHP's loose typing (quack) to check that they are INTs and not str cast to 0
849  if ($time_created_upper && $time_created_upper == sanitise_int($time_created_upper)) {
850  $wheres[] = "{$table}.time_created <= $time_created_upper";
851  }
852 
853  if ($time_created_lower && $time_created_lower == sanitise_int($time_created_lower)) {
854  $wheres[] = "{$table}.time_created >= $time_created_lower";
855  }
856 
857  if ($time_updated_upper && $time_updated_upper == sanitise_int($time_updated_upper)) {
858  $wheres[] = "{$table}.time_updated <= $time_updated_upper";
859  }
860 
861  if ($time_updated_lower && $time_updated_lower == sanitise_int($time_updated_lower)) {
862  $wheres[] = "{$table}.time_updated >= $time_updated_lower";
863  }
864 
865  if (is_array($wheres) && count($wheres) > 0) {
866  $where_str = implode(' AND ', $wheres);
867  return "($where_str)";
868  }
869 
870  return '';
871  }
872 
904  function getEntitiesFromAttributes(array $options = array()) {
905  $defaults = array(
906  'attribute_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
907  'attribute_name_value_pairs_operator' => 'AND',
908  );
909 
910  $options = array_merge($defaults, $options);
911 
912  $singulars = array('type', 'attribute_name_value_pair');
914 
916 
917  if ($clauses) {
918  // merge wheres to pass to elgg_get_entities()
919  if (isset($options['wheres']) && !is_array($options['wheres'])) {
920  $options['wheres'] = array($options['wheres']);
921  } elseif (!isset($options['wheres'])) {
922  $options['wheres'] = array();
923  }
924 
925  $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
926 
927  // merge joins to pass to elgg_get_entities()
928  if (isset($options['joins']) && !is_array($options['joins'])) {
929  $options['joins'] = array($options['joins']);
930  } elseif (!isset($options['joins'])) {
931  $options['joins'] = array();
932  }
933 
934  $options['joins'] = array_merge($options['joins'], $clauses['joins']);
935  }
936 
938  }
939 
947  function getEntityAttributeWhereSql(array $options = array()) {
948 
949  if (!isset($options['types'])) {
950  throw new \InvalidArgumentException("The entity type must be defined for elgg_get_entities_from_attributes()");
951  }
952 
953  if (is_array($options['types']) && count($options['types']) !== 1) {
954  throw new \InvalidArgumentException("Only one type can be passed to elgg_get_entities_from_attributes()");
955  }
956 
957  // type can be passed as string or array
958  $type = $options['types'];
959  if (is_array($type)) {
960  $type = $type[0];
961  }
962 
963  // @todo the types should be defined somewhere (as constant on \ElggEntity?)
964  if (!in_array($type, array('group', 'object', 'site', 'user'))) {
965  throw new \InvalidArgumentException("Invalid type '$type' passed to elgg_get_entities_from_attributes()");
966  }
967 
968 
969  $type_table = "{$this->CONFIG->dbprefix}{$type}s_entity";
970 
971  $return = array(
972  'joins' => array(),
973  'wheres' => array(),
974  );
975 
976  // short circuit if nothing requested
977  if ($options['attribute_name_value_pairs'] == ELGG_ENTITIES_ANY_VALUE) {
978  return $return;
979  }
980 
981  if (!is_array($options['attribute_name_value_pairs'])) {
982  throw new \InvalidArgumentException("attribute_name_value_pairs must be an array for elgg_get_entities_from_attributes()");
983  }
984 
985  $wheres = array();
986 
987  // check if this is an array of pairs or just a single pair.
988  $pairs = $options['attribute_name_value_pairs'];
989  if (isset($pairs['name']) || isset($pairs['value'])) {
990  $pairs = array($pairs);
991  }
992 
993  $pair_wheres = array();
994  foreach ($pairs as $index => $pair) {
995  // must have at least a name and value
996  if (!isset($pair['name']) || !isset($pair['value'])) {
997  continue;
998  }
999 
1000  if (isset($pair['operand'])) {
1001  $operand = sanitize_string($pair['operand']);
1002  } else {
1003  $operand = '=';
1004  }
1005 
1006  if (is_numeric($pair['value'])) {
1007  $value = sanitize_string($pair['value']);
1008  } else if (is_array($pair['value'])) {
1009  $values_array = array();
1010  foreach ($pair['value'] as $pair_value) {
1011  if (is_numeric($pair_value)) {
1012  $values_array[] = sanitize_string($pair_value);
1013  } else {
1014  $values_array[] = "'" . sanitize_string($pair_value) . "'";
1015  }
1016  }
1017 
1018  $operand = 'IN';
1019  if ($values_array) {
1020  $value = '(' . implode(', ', $values_array) . ')';
1021  }
1022 
1023  } else {
1024  $value = "'" . sanitize_string($pair['value']) . "'";
1025  }
1026 
1027  $name = sanitize_string($pair['name']);
1028 
1029  // case sensitivity can be specified per pair
1030  $pair_binary = '';
1031  if (isset($pair['case_sensitive'])) {
1032  $pair_binary = ($pair['case_sensitive']) ? 'BINARY ' : '';
1033  }
1034 
1035  $pair_wheres[] = "({$pair_binary}type_table.$name $operand $value)";
1036  }
1037 
1038  if ($where = implode(" {$options['attribute_name_value_pairs_operator']} ", $pair_wheres)) {
1039  $return['wheres'][] = "($where)";
1040 
1041  $return['joins'][] = "JOIN $type_table type_table ON e.guid = type_table.guid";
1042  }
1043 
1044  return $return;
1045  }
1046 
1064  function getDates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0,
1065  $order_by = 'time_created') {
1066 
1067 
1068 
1069  $site_guid = (int) $site_guid;
1070  if ($site_guid == 0) {
1071  $site_guid = $this->CONFIG->site_guid;
1072  }
1073  $where = array();
1074 
1075  if ($type != "") {
1077  $where[] = "type='$type'";
1078  }
1079 
1080  if (is_array($subtype)) {
1081  $tempwhere = "";
1082  if (sizeof($subtype)) {
1083  foreach ($subtype as $typekey => $subtypearray) {
1084  foreach ($subtypearray as $subtypeval) {
1085  $typekey = sanitise_string($typekey);
1086  if (!empty($subtypeval)) {
1087  if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) {
1088  return false;
1089  }
1090  } else {
1091  $subtypeval = 0;
1092  }
1093  if (!empty($tempwhere)) {
1094  $tempwhere .= " or ";
1095  }
1096  $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})";
1097  }
1098  }
1099  }
1100  if (!empty($tempwhere)) {
1101  $where[] = "({$tempwhere})";
1102  }
1103  } else {
1104  if ($subtype) {
1105  if (!$subtype_id = get_subtype_id($type, $subtype)) {
1106  return false;
1107  } else {
1108  $where[] = "subtype=$subtype_id";
1109  }
1110  }
1111  }
1112 
1113  if ($container_guid !== 0) {
1114  if (is_array($container_guid)) {
1115  foreach ($container_guid as $key => $val) {
1116  $container_guid[$key] = (int) $val;
1117  }
1118  $where[] = "container_guid in (" . implode(",", $container_guid) . ")";
1119  } else {
1120  $container_guid = (int) $container_guid;
1121  $where[] = "container_guid = {$container_guid}";
1122  }
1123  }
1124 
1125  if ($site_guid > 0) {
1126  $where[] = "site_guid = {$site_guid}";
1127  }
1128 
1129  $where[] = _elgg_get_access_where_sql(array('table_alias' => ''));
1130 
1131  $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth
1132  FROM {$this->CONFIG->dbprefix}entities where ";
1133 
1134  foreach ($where as $w) {
1135  $sql .= " $w and ";
1136  }
1137 
1138  $sql .= "1=1 ORDER BY $order_by";
1139  if ($result = _elgg_services()->db->getData($sql)) {
1140  $endresult = array();
1141  foreach ($result as $res) {
1142  $endresult[] = $res->yearmonth;
1143  }
1144  return $endresult;
1145  }
1146  return false;
1147  }
1148 
1161  function updateLastAction($guid, $posted = null) {
1162 
1163  $guid = (int)$guid;
1164  $posted = (int)$posted;
1165 
1166  if (!$posted) {
1167  $posted = time();
1168  }
1169 
1170  if ($guid) {
1171  //now add to the river updated table
1172  $query = "UPDATE {$this->CONFIG->dbprefix}entities SET last_action = {$posted} WHERE guid = {$guid}";
1173  $result = _elgg_services()->db->updateData($query);
1174  if ($result) {
1175  return true;
1176  } else {
1177  return false;
1178  }
1179  } else {
1180  return false;
1181  }
1182  }
1183 }
$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
const ELGG_ENTITIES_NO_VALUE
Definition: elgglib.php:2068
_elgg_get_guid_based_where_sql($column, $guids)
Returns SQL where clause for owner and containers.
Definition: entities.php:535
if(elgg_in_context('widget')) $offset
Definition: pagination.php:20
_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:29
$column
Definition: add.php:13
if(!$autoload_available) _elgg_services()
Definition: autoloader.php:20
$return
Definition: opendd.php:15
$guid
Removes an admin notice.
_elgg_sql_reverse_order_by_clause($order_by)
Reverses the ordering in an ORDER BY clause.
Definition: elgglib.php:1716
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
$limit
Definition: userpicker.php:33
$key
Definition: summary.php:34
getGuidBasedWhereSql($column, $guids)
Returns SQL where clause for owner and containers.
$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:2059
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:170
exists($guid)
Does an entity exist?
get_entity_as_row($guid)
Returns a database row from the entities table.
Definition: entities.php:352
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:157
$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:669
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.
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:1479
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.
$defaults
Definition: access.php:19
$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:214
$subtype
Definition: river.php:12
list style type
Definition: admin.php:747
_elgg_fetch_entities_from_sql($sql,\ElggBatch $batch=null)
Return entities from an SQL query generated by elgg_get_entities.
Definition: entities.php:504
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