Elgg  Version 5.1
Entities.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
13 
24 class Entities extends Repository {
25 
29  public function count() {
30  $qb = Select::fromTable('entities', 'e');
31 
32  $count_expr = $this->options->distinct ? 'DISTINCT e.guid' : '*';
33  $qb->select("COUNT({$count_expr}) AS total");
34 
35  $qb = $this->buildQuery($qb);
36 
37  $result = _elgg_services()->db->getDataRow($qb);
38 
39  if (empty($result)) {
40  return 0;
41  }
42 
43  return (int) $result->total;
44  }
45 
56  public function calculate($function, $property, $property_type = null) {
57  if (!in_array(strtolower($function), QueryBuilder::CALCULATIONS)) {
58  throw new DomainException("'{$function}' is not a valid numeric function");
59  }
60 
61  if (!isset($property_type)) {
62  if (in_array($property, \ElggEntity::PRIMARY_ATTR_NAMES)) {
63  $property_type = 'attribute';
64  } else {
65  $property_type = 'metadata';
66  }
67  }
68 
69  $qb = Select::fromTable('entities', 'e');
70 
71  switch ($property_type) {
72  case 'attribute':
73  if (!in_array($property, \ElggEntity::PRIMARY_ATTR_NAMES)) {
74  throw new DomainException("'{$property}' is not a valid attribute");
75  }
76 
77  $qb->addSelect("{$function}(e.{$property}) AS calculation");
78  break;
79 
80  case 'metadata':
81  $alias = $qb->joinMetadataTable('e', 'guid', $property, 'inner', 'n_table');
82  $qb->addSelect("{$function}({$alias}.value) AS calculation");
83  break;
84 
85  case 'annotation':
86  $alias = $qb->joinAnnotationTable('e', 'guid', $property, 'inner', 'n_table');
87  $qb->addSelect("{$function}({$alias}.value) AS calculation");
88  break;
89  }
90 
91  $qb = $this->buildQuery($qb);
92 
93  $result = _elgg_services()->db->getDataRow($qb);
94 
95  // do not cast data as calculations could be used as int, float or string
96  return $result->calculation;
97  }
98 
108  public function get($limit = null, $offset = null, $callback = null) {
109  $qb = Select::fromTable('entities', 'e');
110 
111  $distinct = $this->options->distinct ? 'DISTINCT' : '';
112  $qb->select("{$distinct} e.*");
113 
114  $this->expandInto($qb, 'e');
115 
116  $qb = $this->buildQuery($qb);
117 
118  // Keeping things backwards compatible
119  $original_order = elgg_extract('order_by', $this->options->__original_options);
120  if (empty($original_order) && $original_order !== false) {
121  $qb->addOrderBy('e.time_created', 'desc');
122  // also add order by guid, to rely less on internals of MySQL fallback ordering
123  $qb->addOrderBy('e.guid', 'desc');
124  }
125 
126  if ($limit > 0) {
127  $qb->setMaxResults((int) $limit);
128  $qb->setFirstResult((int) $offset);
129  }
130 
131  $options = $this->options->getArrayCopy();
132 
133  $options['limit'] = (int) $limit;
134  $options['offset'] = (int) $offset;
135  $options['callback'] = $callback ?: $this->options->callback;
136  if (!isset($options['callback'])) {
137  $options['callback'] = [_elgg_services()->entityTable, 'rowToElggStar'];
138  }
139 
140  unset($options['count']);
141 
142  return _elgg_services()->entityTable->fetch($qb, $options);
143  }
144 
154  public function getDates(): array {
155  $qb = Select::fromTable('entities', 'e');
156 
157  $qb->select('DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(e.time_created)) AS yearmonth');
158 
159  $this->expandInto($qb, 'e');
160 
161  $qb = $this->buildQuery($qb);
162 
163  $options = $this->options->getArrayCopy();
164  unset($options['count']);
165 
166  $options['callback'] = false;
167 
168  $results = _elgg_services()->entityTable->fetch($qb, $options);
169 
170  if (empty($results)) {
171  return [];
172  }
173 
174  return array_map(function ($e) {
175  return $e->yearmonth;
176  }, $results);
177  }
178 
185  public function execute() {
186  if ($this->options->annotation_calculation) {
187  $clauses = $this->options->annotation_name_value_pairs;
188  if (count($clauses) > 1 && $this->options->annotation_name_value_pairs_operator !== 'OR') {
189  throw new LogicException('Annotation calculation can not be performed on multiple annotation name value pairs merged with AND');
190  }
191 
192  $clause = array_shift($clauses);
193 
194  return $this->calculate($this->options->annotation_calculation, $clause->names, 'annotation');
195  } else if ($this->options->metadata_calculation) {
196  $clauses = $this->options->metadata_name_value_pairs;
197  if (count($clauses) > 1 && $this->options->metadata_name_value_pairs_operator !== 'OR') {
198  throw new LogicException('Metadata calculation can not be performed on multiple metadata name value pairs merged with AND');
199  }
200 
201  $clause = array_shift($clauses);
202 
203  return $this->calculate($this->options->metadata_calculation, $clause->names, 'metadata');
204  } else if ($this->options->count) {
205  return $this->count();
206  } else if ($this->options->batch) {
207  return $this->batch($this->options->limit, $this->options->offset, $this->options->callback);
208  } else {
209  return $this->get($this->options->limit, $this->options->offset, $this->options->callback);
210  }
211  }
212 
220  protected function buildQuery(QueryBuilder $qb) {
221  $ands = [];
222 
223  foreach ($this->options->joins as $join) {
224  $join->prepare($qb, 'e');
225  }
226 
227  foreach ($this->options->wheres as $where) {
228  $ands[] = $where->prepare($qb, 'e');
229  }
230 
231  $ands[] = $this->buildEntityClause($qb);
232  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator);
233  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->search_name_value_pairs, 'OR');
234  $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator);
235  $ands[] = $this->buildPairedRelationshipClause($qb, $this->options->relationship_pairs);
236 
237  $ands = $qb->merge($ands);
238 
239  if (!empty($ands)) {
240  $qb->andWhere($ands);
241  }
242 
243  return $qb;
244  }
245 
254  protected function buildEntityClause(QueryBuilder $qb) {
255  return EntityWhereClause::factory($this->options)->prepare($qb, 'e');
256  }
257 
268  protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
269  $parts = [];
270 
271  foreach ($clauses as $clause) {
272  if ($clause instanceof MetadataWhereClause) {
273  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
274  $joined_alias = $qb->joinMetadataTable('e', 'guid', null, 'inner', 'n_table');
275  } else {
276  $joined_alias = $qb->joinMetadataTable('e', 'guid', $clause->names);
277  }
278 
279  $parts[] = $clause->prepare($qb, $joined_alias);
280  }
281  }
282 
283  return $qb->merge($parts, $boolean);
284  }
285 
296  protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
297  $parts = [];
298 
299  foreach ($clauses as $clause) {
300  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
301  $joined_alias = $qb->joinAnnotationTable('e', 'guid', null, 'inner', 'n_table');
302  } else {
303  $joined_alias = $qb->joinAnnotationTable('e', 'guid', $clause->names);
304  }
305 
306  $parts[] = $clause->prepare($qb, $joined_alias);
307  }
308 
309  return $qb->merge($parts, $boolean);
310  }
311 
321  protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
322  $parts = [];
323 
324  foreach ($clauses as $clause) {
325  if (strtoupper($boolean) == 'OR' || count($clauses) === 1) {
326  $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, null, $clause->inverse, 'inner', 'r');
327  } else {
328  $joined_alias = $qb->joinRelationshipTable('e', $clause->join_on, $clause->names, $clause->inverse);
329  }
330 
331  $parts[] = $clause->prepare($qb, $joined_alias);
332  }
333 
334  return $qb->merge($parts, $boolean);
335  }
336 }
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:296
execute()
Execute the query resolving calculation, count and/or batch options.
Definition: Entities.php:185
batch($limit=null, $offset=null, $callback=null)
Fetch rows as an ElggBatch.
Definition: Repository.php:127
const PRIMARY_ATTR_NAMES
Definition: ElggEntity.php:50
buildQuery(QueryBuilder $qb)
Build a database query.
Definition: Entities.php:220
calculate($function, $property, $property_type=null)
Performs a mathematical calculation on a set of entity properties.
Definition: Entities.php:56
if(empty($count)) $offset
Definition: pagination.php:26
Exception thrown if a value does not adhere to a defined valid data domain.
Database abstraction query builder.
Entities repository contains methods for fetching entities from database or performing calculations o...
Definition: Entities.php:24
buildEntityClause(QueryBuilder $qb)
Process entity attribute wheres Applies entity attribute constrains on the selected entities table...
Definition: Entities.php:254
elgg_extract($key, $array, $default=null, bool $strict=true)
Checks for $array[$key] and returns its value if it exists, else returns $default.
Definition: elgglib.php:254
Abstract methods for interfacing with the database.
Definition: Repository.php:16
$limit
Definition: pagination.php:28
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:268
expandInto(QueryBuilder $qb, $table_alias=null)
Extend query builder with select, group_by, having and order_by clauses from $options.
Definition: Repository.php:254
Exception that represents error in the program logic.
buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process relationship pairs.
Definition: Entities.php:321
$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.
static fromTable($table, $alias=null)
{}
Definition: Select.php:13
merge($parts=null, $boolean= 'AND')
Merges multiple composite expressions with a boolean.
_elgg_services()
Get the global service provider.
Definition: elgglib.php:346
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:154
$qb
Definition: queue.php:11
Builds clauses for filtering entities by properties in metadata table.