Elgg  Version 3.0
Entities.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
5 use Closure;
12 use ElggEntity;
15 
32 class Entities extends Repository {
33 
37  public function count() {
38  $qb = Select::fromTable('entities', 'e');
39 
40  $count_expr = $this->options->distinct ? "DISTINCT e.guid" : "*";
41  $qb->select("COUNT({$count_expr}) AS total");
42 
43  $qb = $this->buildQuery($qb);
44 
45  $result = _elgg_services()->db->getDataRow($qb);
46 
47  if (empty($result)) {
48  return 0;
49  }
50 
51  return (int) $result->total;
52  }
53 
64  public function calculate($function, $property, $property_type = null) {
65 
66  if (!in_array(strtolower($function), QueryBuilder::$calculations)) {
67  throw new InvalidArgumentException("'$function' is not a valid numeric function");
68  }
69 
70  if (!isset($property_type)) {
71  if (in_array($property, ElggEntity::$primary_attr_names)) {
72  $property_type = 'attribute';
73  } else {
74  $property_type = 'metadata';
75  }
76  }
77 
78  $qb = Select::fromTable('entities', 'e');
79 
80  switch ($property_type) {
81  case 'attribute':
82  if (!in_array($property, ElggEntity::$primary_attr_names)) {
83  throw new InvalidParameterException("'$property' is not a valid attribute");
84  }
85 
86  $qb->addSelect("{$function}(e.{$property}) AS calculation");
87  break;
88 
89  case 'metadata' :
90  $alias = $qb->joinMetadataTable('e', 'guid', $property, 'inner', 'n_table');
91  $qb->addSelect("{$function}({$alias}.value) AS calculation");
92  break;
93 
94  case 'annotation' :
95  $alias = $qb->joinAnnotationTable('e', 'guid', $property, 'inner', 'n_table');
96  $qb->addSelect("{$function}({$alias}.value) AS calculation");
97  break;
98 
99  case 'private_setting' :
100  $alias = $qb->joinPrivateSettingsTable('e', 'guid', $property, 'inner', 'ps');
101  $qb->addSelect("{$function}({$alias}.value) AS calculation");
102  break;
103  }
104 
105  $qb = $this->buildQuery($qb);
106 
107  $result = _elgg_services()->db->getDataRow($qb);
108 
109  // do not cast data as calculations could be used as int, float or string
110  return $result->calculation;
111  }
112 
122  public function get($limit = null, $offset = null, $callback = null) {
123 
124  $qb = Select::fromTable('entities', 'e');
125 
126  $distinct = $this->options->distinct ? "DISTINCT" : "";
127  $qb->select("$distinct e.*");
128 
129  $this->expandInto($qb, 'e');
130 
131  $qb = $this->buildQuery($qb);
132 
133  // Keeping things backwards compatible
134  $original_order = elgg_extract('order_by', $this->options->__original_options);
135  if (empty($original_order) && $original_order !== false) {
136  $qb->addOrderBy('e.time_created', 'desc');
137  // also add order by guid, to rely less on internals of MySQL fallback ordering
138  $qb->addOrderBy('e.guid', 'desc');
139  }
140 
141  if ($limit > 0) {
142  $qb->setMaxResults((int) $limit);
143  $qb->setFirstResult((int) $offset);
144  }
145 
146  $options = $this->options->getArrayCopy();
147 
148  $options['limit'] = (int) $limit;
149  $options['offset'] = (int) $offset;
150  $options['callback'] = $callback ? : $this->options->callback;
151  if (!isset($options['callback'])) {
152  $options['callback'] = 'entity_row_to_elggstar';
153  }
154 
155  unset($options['count']);
156 
157  return _elgg_services()->entityTable->fetch($qb, $options);
158  }
159 
169  public function getDates() {
170 
171  $qb = Select::fromTable('entities', 'e');
172 
173  $qb->select("DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(e.time_created)) AS yearmonth");
174 
175  $this->expandInto($qb, 'e');
176 
177  $qb = $this->buildQuery($qb);
178 
179  $options = $this->options->getArrayCopy();
180  unset($options['count']);
181 
182  $options['callback'] = false;
183 
184  $results = _elgg_services()->entityTable->fetch($qb, $options);
185 
186  if (empty($results)) {
187  return false;
188  }
189 
190  return array_map(function ($e) {
191  return $e->yearmonth;
192  }, $results);
193  }
194 
201  public function execute() {
202 
203  if ($this->options->annotation_calculation) {
204  $clauses = $this->options->annotation_name_value_pairs;
205  if (count($clauses) > 1 && $this->options->annotation_name_value_pairs_operator !== 'OR') {
206  throw new \LogicException("Annotation calculation can not be performed on multiple annotation name value pairs merged with AND");
207  }
208 
209  $clause = array_shift($clauses);
210 
211  return $this->calculate($this->options->annotation_calculation, $clause->names, 'annotation');
212  } else if ($this->options->metadata_calculation) {
213  $clauses = $this->options->metadata_name_value_pairs;
214  if (count($clauses) > 1 && $this->options->metadata_name_value_pairs_operator !== 'OR') {
215  throw new \LogicException("Metadata calculation can not be performed on multiple metadata name value pairs merged with AND");
216  }
217 
218  $clause = array_shift($clauses);
219 
220  return $this->calculate($this->options->metadata_calculation, $clause->names, 'metadata');
221  } else if ($this->options->count) {
222  return $this->count();
223  } else if ($this->options->batch) {
224  return $this->batch($this->options->limit, $this->options->offset, $this->options->callback);
225  } else {
226  return $this->get($this->options->limit, $this->options->offset, $this->options->callback);
227  }
228  }
229 
237  protected function buildQuery(QueryBuilder $qb) {
238 
239  $ands = [];
240 
241  foreach ($this->options->joins as $join) {
242  $join->prepare($qb, 'e');
243  }
244 
245  foreach ($this->options->wheres as $where) {
246  $ands[] = $where->prepare($qb, 'e');
247  }
248 
249  $ands[] = $this->buildEntityClause($qb);
250  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator);
251  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->search_name_value_pairs, 'OR');
252  $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator);
253  $ands[] = $this->buildPairedPrivateSettingsClause($qb, $this->options->private_setting_name_value_pairs, $this->options->private_setting_name_value_pairs_operator);
254  $ands[] = $this->buildPairedRelationshipClause($qb, $this->options->relationship_pairs);
255 
256  $ands = $qb->merge($ands);
257 
258  if (!empty($ands)) {
259  $qb->andWhere($ands);
260  }
261 
262  return $qb;
263  }
264 
273  protected function buildEntityClause(QueryBuilder $qb) {
274  return EntityWhereClause::factory($this->options)->prepare($qb, 'e');
275  }
276 
287  protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
288  $parts = [];
289 
290 
291  foreach ($clauses as $clause) {
292  if ($clause instanceof MetadataWhereClause) {
293  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
294  $joined_alias = $qb->joinMetadataTable('e', 'guid', null, 'inner', 'n_table');
295  } else {
296  $joined_alias = $qb->joinMetadataTable('e', 'guid', $clause->names);
297  }
298  $parts[] = $clause->prepare($qb, $joined_alias);
299  }
300  }
301 
302  return $qb->merge($parts, $boolean);
303  }
304 
315  protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
316  $parts = [];
317 
318  foreach ($clauses as $clause) {
319  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
320  $joined_alias = $qb->joinAnnotationTable('e', 'guid', null, 'inner', 'n_table');
321  } else {
322  $joined_alias = $qb->joinAnnotationTable('e', 'guid', $clause->names);
323  }
324  $parts[] = $clause->prepare($qb, $joined_alias);
325  }
326 
327  return $qb->merge($parts, $boolean);
328  }
329 
340  protected function buildPairedPrivateSettingsClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
341  $parts = [];
342 
343  foreach ($clauses as $clause) {
344  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
345  $joined_alias = $qb->joinPrivateSettingsTable('e', 'guid', null, 'inner', 'ps');
346  } else {
347  $joined_alias = $qb->joinPrivateSettingsTable('e', 'guid', $clause->names);
348  }
349  $parts[] = $clause->prepare($qb, $joined_alias);
350  }
351 
352  return $qb->merge($parts, $boolean);
353  }
354 
364  protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
365  $parts = [];
366 
367  foreach ($clauses as $clause) {
368  if (strtoupper($boolean) == 'OR' || count($clauses) === 1) {
369  $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, null, $clause->inverse, 'inner', 'r');
370  } else {
371  $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, $clause->names, $clause->inverse);
372  }
373  $parts[] = $clause->prepare($qb, $joined_alias);
374  }
375 
376  return $qb->merge($parts, $boolean);
377  }
378 }
buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process annotation name value pairs Joins the annotation table on entity guid in the entities table a...
Definition: Entities.php:315
execute()
Execute the query resolving calculation, count and/or batch options.
Definition: Entities.php:201
batch($limit=null, $offset=null, $callback=null)
{Fetch rows as an ElggBatch.Number of rows to fetch Index of the first row Callback function to run d...
Definition: Repository.php:96
buildQuery(QueryBuilder $qb)
Build a database query.
Definition: Entities.php:237
calculate($function, $property, $property_type=null)
Performs a mathematical calculation on a set of entity properties.
Definition: Entities.php:64
if(!$count) $offset
Definition: pagination.php:26
Database abstraction query builder.
Entities repository contains methods for fetching entities from database or performing calculations o...
Definition: Entities.php:32
buildEntityClause(QueryBuilder $qb)
Process entity attribute wheres Applies entity attribute constrains on the selected entities table...
Definition: Entities.php:273
count()
{Count rows.int}
Definition: Entities.php:37
Abstract methods for interfacing with the database.
Definition: Repository.php:15
$limit
Definition: userpicker.php:52
static $primary_attr_names
Definition: ElggEntity.php:49
buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process metadata name value pairs Joins the metadata table on entity guid in the entities table and a...
Definition: Entities.php:287
expandInto(QueryBuilder $qb, $table_alias=null)
Extend query builder with select, group_by, having and order_by clauses from $options.
Definition: Repository.php:180
buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process relationship pairs.
Definition: Entities.php:364
joinAnnotationTable($from_alias= '', $from_column= 'guid', $name=null, $join_type= 'inner', $joined_alias=null)
Join annotations table from alias and return joined table alias.
elgg_extract($key, $array, $default=null, $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:1131
static fromTable($table, $alias=null)
{}
Definition: Select.php:13
joinPrivateSettingsTable($from_alias= '', $from_column= 'guid', $name=null, $join_type= 'inner', $joined_alias=null)
Join private settings table from alias and return joined table alias.
merge($parts=null, $boolean= 'AND')
Merges multiple composite expressions with a boolean.
_elgg_services()
Get the global service provider.
Definition: elgglib.php:1292
joinMetadataTable($from_alias= '', $from_column= 'guid', $name=null, $join_type= 'inner', $joined_alias=null)
Join metadata table from alias and return joined table alias.
joinRelationshipTable($from_alias= '', $from_column= 'guid', $name=null, $inverse=false, $join_type= 'inner', $joined_alias=null)
Join relationship table from alias and return joined table alias.
getDates()
Returns a list of months in which entities were updated or created.
Definition: Entities.php:169
elgg ElggEntity
Definition: ElggEntity.js:15
buildPairedPrivateSettingsClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process private setting name value pairs Joins the private settings table on entity guid in the entit...
Definition: Entities.php:340
Builds clauses for filtering entities by properties in metadata table.