Elgg  Version 4.3
Entities.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
14 
25 class Entities extends Repository {
26 
30  public function count() {
31  $qb = Select::fromTable('entities', 'e');
32 
33  $count_expr = $this->options->distinct ? "DISTINCT e.guid" : "*";
34  $qb->select("COUNT({$count_expr}) AS total");
35 
36  $qb = $this->buildQuery($qb);
37 
38  $result = _elgg_services()->db->getDataRow($qb);
39 
40  if (empty($result)) {
41  return 0;
42  }
43 
44  return (int) $result->total;
45  }
46 
57  public function calculate($function, $property, $property_type = null) {
58 
59  if (!in_array(strtolower($function), QueryBuilder::$calculations)) {
60  throw new InvalidArgumentException("'$function' is not a valid numeric function");
61  }
62 
63  if (!isset($property_type)) {
64  if (in_array($property, \ElggEntity::PRIMARY_ATTR_NAMES)) {
65  $property_type = 'attribute';
66  } else {
67  $property_type = 'metadata';
68  }
69  }
70 
71  $qb = Select::fromTable('entities', 'e');
72 
73  switch ($property_type) {
74  case 'attribute':
75  if (!in_array($property, \ElggEntity::PRIMARY_ATTR_NAMES)) {
76  throw new InvalidParameterException("'$property' is not a valid attribute");
77  }
78 
79  $qb->addSelect("{$function}(e.{$property}) AS calculation");
80  break;
81 
82  case 'metadata' :
83  $alias = $qb->joinMetadataTable('e', 'guid', $property, 'inner', 'n_table');
84  $qb->addSelect("{$function}({$alias}.value) AS calculation");
85  break;
86 
87  case 'annotation' :
88  $alias = $qb->joinAnnotationTable('e', 'guid', $property, 'inner', 'n_table');
89  $qb->addSelect("{$function}({$alias}.value) AS calculation");
90  break;
91 
92  case 'private_setting' :
93  $alias = $qb->joinPrivateSettingsTable('e', 'guid', $property, 'inner', 'ps');
94  $qb->addSelect("{$function}({$alias}.value) AS calculation");
95  break;
96  }
97 
98  $qb = $this->buildQuery($qb);
99 
100  $result = _elgg_services()->db->getDataRow($qb);
101 
102  // do not cast data as calculations could be used as int, float or string
103  return $result->calculation;
104  }
105 
115  public function get($limit = null, $offset = null, $callback = null) {
116 
117  $qb = Select::fromTable('entities', 'e');
118 
119  $distinct = $this->options->distinct ? "DISTINCT" : "";
120  $qb->select("$distinct e.*");
121 
122  $this->expandInto($qb, 'e');
123 
124  $qb = $this->buildQuery($qb);
125 
126  // Keeping things backwards compatible
127  $original_order = elgg_extract('order_by', $this->options->__original_options);
128  if (empty($original_order) && $original_order !== false) {
129  $qb->addOrderBy('e.time_created', 'desc');
130  // also add order by guid, to rely less on internals of MySQL fallback ordering
131  $qb->addOrderBy('e.guid', 'desc');
132  }
133 
134  if ($limit > 0) {
135  $qb->setMaxResults((int) $limit);
136  $qb->setFirstResult((int) $offset);
137  }
138 
139  $options = $this->options->getArrayCopy();
140 
141  $options['limit'] = (int) $limit;
142  $options['offset'] = (int) $offset;
143  $options['callback'] = $callback ? : $this->options->callback;
144  if (!isset($options['callback'])) {
145  $options['callback'] = [_elgg_services()->entityTable, 'rowToElggStar'];
146  }
147 
148  unset($options['count']);
149 
150  return _elgg_services()->entityTable->fetch($qb, $options);
151  }
152 
162  public function getDates() {
163 
164  $qb = Select::fromTable('entities', 'e');
165 
166  $qb->select("DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(e.time_created)) AS yearmonth");
167 
168  $this->expandInto($qb, 'e');
169 
170  $qb = $this->buildQuery($qb);
171 
172  $options = $this->options->getArrayCopy();
173  unset($options['count']);
174 
175  $options['callback'] = false;
176 
177  $results = _elgg_services()->entityTable->fetch($qb, $options);
178 
179  if (empty($results)) {
180  return false;
181  }
182 
183  return array_map(function ($e) {
184  return $e->yearmonth;
185  }, $results);
186  }
187 
194  public function execute() {
195 
196  if ($this->options->annotation_calculation) {
197  $clauses = $this->options->annotation_name_value_pairs;
198  if (count($clauses) > 1 && $this->options->annotation_name_value_pairs_operator !== 'OR') {
199  throw new LogicException("Annotation calculation can not be performed on multiple annotation name value pairs merged with AND");
200  }
201 
202  $clause = array_shift($clauses);
203 
204  return $this->calculate($this->options->annotation_calculation, $clause->names, 'annotation');
205  } else if ($this->options->metadata_calculation) {
206  $clauses = $this->options->metadata_name_value_pairs;
207  if (count($clauses) > 1 && $this->options->metadata_name_value_pairs_operator !== 'OR') {
208  throw new LogicException("Metadata calculation can not be performed on multiple metadata name value pairs merged with AND");
209  }
210 
211  $clause = array_shift($clauses);
212 
213  return $this->calculate($this->options->metadata_calculation, $clause->names, 'metadata');
214  } else if ($this->options->count) {
215  return $this->count();
216  } else if ($this->options->batch) {
217  return $this->batch($this->options->limit, $this->options->offset, $this->options->callback);
218  } else {
219  return $this->get($this->options->limit, $this->options->offset, $this->options->callback);
220  }
221  }
222 
230  protected function buildQuery(QueryBuilder $qb) {
231 
232  $ands = [];
233 
234  foreach ($this->options->joins as $join) {
235  $join->prepare($qb, 'e');
236  }
237 
238  foreach ($this->options->wheres as $where) {
239  $ands[] = $where->prepare($qb, 'e');
240  }
241 
242  $ands[] = $this->buildEntityClause($qb);
243  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator);
244  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->search_name_value_pairs, 'OR');
245  $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator);
246  $ands[] = $this->buildPairedPrivateSettingsClause($qb, $this->options->private_setting_name_value_pairs, $this->options->private_setting_name_value_pairs_operator);
247  $ands[] = $this->buildPairedRelationshipClause($qb, $this->options->relationship_pairs);
248 
249  $ands = $qb->merge($ands);
250 
251  if (!empty($ands)) {
252  $qb->andWhere($ands);
253  }
254 
255  return $qb;
256  }
257 
266  protected function buildEntityClause(QueryBuilder $qb) {
267  return EntityWhereClause::factory($this->options)->prepare($qb, 'e');
268  }
269 
280  protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
281  $parts = [];
282 
283 
284  foreach ($clauses as $clause) {
285  if ($clause instanceof MetadataWhereClause) {
286  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
287  $joined_alias = $qb->joinMetadataTable('e', 'guid', null, 'inner', 'n_table');
288  } else {
289  $joined_alias = $qb->joinMetadataTable('e', 'guid', $clause->names);
290  }
291  $parts[] = $clause->prepare($qb, $joined_alias);
292  }
293  }
294 
295  return $qb->merge($parts, $boolean);
296  }
297 
308  protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
309  $parts = [];
310 
311  foreach ($clauses as $clause) {
312  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
313  $joined_alias = $qb->joinAnnotationTable('e', 'guid', null, 'inner', 'n_table');
314  } else {
315  $joined_alias = $qb->joinAnnotationTable('e', 'guid', $clause->names);
316  }
317  $parts[] = $clause->prepare($qb, $joined_alias);
318  }
319 
320  return $qb->merge($parts, $boolean);
321  }
322 
333  protected function buildPairedPrivateSettingsClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
334  $parts = [];
335 
336  foreach ($clauses as $clause) {
337  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
338  $joined_alias = $qb->joinPrivateSettingsTable('e', 'guid', null, 'inner', 'ps');
339  } else {
340  $joined_alias = $qb->joinPrivateSettingsTable('e', 'guid', $clause->names);
341  }
342  $parts[] = $clause->prepare($qb, $joined_alias);
343  }
344 
345  return $qb->merge($parts, $boolean);
346  }
347 
357  protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
358  $parts = [];
359 
360  foreach ($clauses as $clause) {
361  if (strtoupper($boolean) == 'OR' || count($clauses) === 1) {
362  $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, null, $clause->inverse, 'inner', 'r');
363  } else {
364  $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, $clause->names, $clause->inverse);
365  }
366  $parts[] = $clause->prepare($qb, $joined_alias);
367  }
368 
369  return $qb->merge($parts, $boolean);
370  }
371 }
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:308
execute()
Execute the query resolving calculation, count and/or batch options.
Definition: Entities.php:194
Exception thrown if an argument is not of the expected type.
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:97
const PRIMARY_ATTR_NAMES
Definition: ElggEntity.php:50
buildQuery(QueryBuilder $qb)
Build a database query.
Definition: Entities.php:230
calculate($function, $property, $property_type=null)
Performs a mathematical calculation on a set of entity properties.
Definition: Entities.php:57
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:25
buildEntityClause(QueryBuilder $qb)
Process entity attribute wheres Applies entity attribute constrains on the selected entities table...
Definition: Entities.php:266
if($pagination &&($position== 'after'||$position== 'both')) $limit
Definition: list.php:108
count()
{Count rows.int}
Definition: Entities.php:30
Abstract methods for interfacing with the database.
Definition: Repository.php:16
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:280
expandInto(QueryBuilder $qb, $table_alias=null)
Extend query builder with select, group_by, having and order_by clauses from $options.
Definition: Repository.php:181
Exception that represents error in the program logic.
buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process relationship pairs.
Definition: Entities.php:357
$results
Definition: content.php:22
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:547
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:638
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:162
$qb
Definition: queue.php:11
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:333
Builds clauses for filtering entities by properties in metadata table.