Elgg  Version master
Annotations.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
13 
20 class Annotations extends Repository {
21 
25  public function count() {
27 
28  $count_expr = $this->options->distinct ? "DISTINCT {$qb->getTableAlias()}.id" : '*';
29  $qb->select("COUNT({$count_expr}) AS total");
30 
31  $qb = $this->buildQuery($qb);
32 
33  $result = _elgg_services()->db->getDataRow($qb);
34 
35  if (empty($result)) {
36  return 0;
37  }
38 
39  return (int) $result->total;
40  }
41 
52  public function calculate($function, $property, $property_type = null) {
53  if (!in_array(strtolower($function), QueryBuilder::CALCULATIONS)) {
54  throw new DomainException("'{$function}' is not a valid numeric function");
55  }
56 
57  if (!isset($property_type)) {
58  $property_type = 'annotation';
59  }
60 
62 
63  switch ($property_type) {
64  case 'attribute':
65  if (!in_array($property, \ElggEntity::PRIMARY_ATTR_NAMES)) {
66  throw new DomainException("'{$property}' is not a valid attribute");
67  }
68 
69  $alias = $qb->joinEntitiesTable($qb->getTableAlias(), 'entity_guid', 'inner', EntityTable::DEFAULT_JOIN_ALIAS);
70  $qb->select("{$function}({$alias}.{$property}) AS calculation");
71  break;
72 
73  case 'annotation':
75  if (!empty($this->options->annotation_name_value_pairs) && $this->options->annotation_name_value_pairs[0]->names != $property) {
76  $alias = $qb->joinAnnotationTable($qb->getTableAlias(), 'entity_guid', $property);
77  }
78 
79  $qb->select("{$function}({$alias}.value) AS calculation");
80  break;
81 
82  case 'metadata':
83  $alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', $property);
84  $qb->select("{$function}({$alias}.value) AS calculation");
85  break;
86  }
87 
88  $qb = $this->buildQuery($qb);
89 
90  $result = _elgg_services()->db->getDataRow($qb);
91 
92  return $result ? (int) $result->calculation : 0;
93  }
94 
104  public function get($limit = null, $offset = null, $callback = null) {
106 
107  $distinct = $this->options->distinct ? 'DISTINCT ' : '';
108  $qb->select("{$distinct}{$qb->getTableAlias()}.*");
109 
110  $this->expandInto($qb, $qb->getTableAlias());
111 
112  $qb = $this->buildQuery($qb);
113 
114  // add default ordering
115  $original_order = elgg_extract('order_by', $this->options->__original_options);
116  if (empty($this->options->order_by) && $original_order !== false) {
117  $qb->addOrderBy("{$qb->getTableAlias()}.time_created", 'asc');
118  $qb->addOrderBy("{$qb->getTableAlias()}.id", 'asc');
119  }
120 
121  if ($limit > 0) {
122  $qb->setMaxResults((int) $limit);
123  $qb->setFirstResult((int) $offset);
124  }
125 
126  $callback = $callback ?: $this->options->callback;
127  if (!isset($callback)) {
128  $callback = function ($row) {
129  return new \ElggAnnotation($row);
130  };
131  }
132 
133  $results = _elgg_services()->db->getData($qb, $callback);
134  if (!empty($results) && $this->options->preload_owners) {
135  _elgg_services()->entityPreloader->preload($results, ['owner_guid']);
136  }
137 
138  return $results;
139  }
140 
147  public function execute() {
148  if ($this->options->annotation_calculation) {
149  $clauses = $this->options->annotation_name_value_pairs;
150  if (count($clauses) > 1 && $this->options->annotation_name_value_pairs_operator !== 'OR') {
151  throw new LogicException('Annotation calculation can not be performed on multiple annotation name value pairs merged with AND');
152  }
153 
154  $clause = array_shift($clauses);
155 
156  return $this->calculate($this->options->annotation_calculation, $clause->names, 'annotation');
157  } elseif ($this->options->metadata_calculation) {
158  $clauses = $this->options->metadata_name_value_pairs;
159  if (count($clauses) > 1 && $this->options->metadata_name_value_pairs_operator !== 'OR') {
160  throw new LogicException('Metadata calculation can not be performed on multiple metadata name value pairs merged with AND');
161  }
162 
163  $clause = array_shift($clauses);
164 
165  return $this->calculate($this->options->metadata_calculation, $clause->names, 'metadata');
166  } elseif ($this->options->count) {
167  return $this->count();
168  } elseif ($this->options->batch) {
169  return $this->batch($this->options->limit, $this->options->offset, $this->options->callback);
170  } else {
171  return $this->get($this->options->limit, $this->options->offset, $this->options->callback);
172  }
173  }
174 
182  protected function buildQuery(QueryBuilder $qb) {
183  $ands = [];
184 
185  foreach ($this->options->joins as $join) {
186  $join->prepare($qb, $qb->getTableAlias());
187  }
188 
189  foreach ($this->options->wheres as $where) {
190  $ands[] = $where->prepare($qb, $qb->getTableAlias());
191  }
192 
193  $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator);
194  $ands[] = $this->buildEntityWhereClause($qb);
195  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator);
196  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->search_name_value_pairs, 'OR');
197  $ands[] = $this->buildPairedRelationshipClause($qb, $this->options->relationship_pairs);
198 
199  $ands = $qb->merge($ands);
200 
201  if (!empty($ands)) {
202  $qb->andWhere($ands);
203  }
204 
205  return $qb;
206  }
207 
217  $joined_alias = $qb->joinEntitiesTable($qb->getTableAlias(), 'entity_guid', 'inner', EntityTable::DEFAULT_JOIN_ALIAS);
218  return EntityWhereClause::factory($this->options)->prepare($qb, $joined_alias);
219  }
220 
231  protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
232  $parts = [];
233 
234  if (empty($clauses)) {
235  // We need to make sure that enabled and access clauses are appended to the query
236  $clauses[] = new AnnotationWhereClause();
237  }
238 
239  foreach ($clauses as $clause) {
240  $parts[] = $clause->prepare($qb, $qb->getTableAlias());
241  }
242 
243  return $qb->merge($parts, $boolean);
244  }
245 
256  protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
257  $parts = [];
258 
259  foreach ($clauses as $clause) {
260  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
261  $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', null, 'inner', MetadataTable::DEFAULT_JOIN_ALIAS);
262  } else {
263  $joined_alias = $qb->joinMetadataTable($qb->getTableAlias(), 'entity_guid', $clause->names);
264  }
265 
266  $parts[] = $clause->prepare($qb, $joined_alias);
267  }
268 
269  return $qb->merge($parts, $boolean);
270  }
271 
282  protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
283  $parts = [];
284 
285  foreach ($clauses as $clause) {
286  $join_on = $clause->join_on == 'guid' ? 'entity_guid' : $clause->join_on;
287  if (strtoupper($boolean) === 'OR' || count($clauses) === 1) {
288  $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $join_on, null, $clause->inverse, 'inner', RelationshipsTable::DEFAULT_JOIN_ALIAS);
289  } else {
290  $joined_alias = $qb->joinRelationshipTable($qb->getTableAlias(), $join_on, $clause->names, $clause->inverse);
291  }
292 
293  $parts[] = $clause->prepare($qb, $joined_alias);
294  }
295 
296  return $qb->merge($parts, $boolean);
297  }
298 }
buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process annotation name value pairs Applies where clauses to the selected annotation table...
batch($limit=null, $offset=null, $callback=null)
Fetch rows as an ElggBatch.
Definition: Repository.php:123
const PRIMARY_ATTR_NAMES
Definition: ElggEntity.php:61
buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process relationship name value pairs Joins relationship table on entity_guid in the annotations tabl...
if(empty($count)) $offset
Definition: pagination.php:26
calculate($function, $property, $property_type=null)
Performs a mathematical calculation on metadata or metadata entity&#39;s properties.
Definition: Annotations.php:52
Exception thrown if a value does not adhere to a defined valid data domain.
Database abstraction query builder.
Builds queries for matching annotations against their properties.
if($item instanceof\ElggEntity) elseif($item instanceof\ElggRiverItem) elseif($item instanceof\ElggRelationship) elseif(is_callable([$item, 'getType']))
Definition: item.php:48
buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process metadata name value pairs Joins metadata table on entity_guid in the annotations table and ap...
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
expandInto(QueryBuilder $qb, $table_alias=null)
Extend query builder with select, group_by, having and order_by clauses from $options.
Definition: Repository.php:250
Exception that represents error in the program logic.
joinEntitiesTable(string $from_alias= '', string $from_column= 'guid',?string $join_type= 'inner', string $joined_alias=null)
Join entity table from alias and return joined table alias.
joinRelationshipTable(string $from_alias= '', string $from_column= 'guid', $name=null, bool $inverse=false,?string $join_type= 'inner', string $joined_alias=null)
Join relationship table from alias and return joined table alias.
$results
Definition: content.php:22
joinMetadataTable(string $from_alias= '', string $from_column= 'guid', $name=null,?string $join_type= 'inner', string $joined_alias=null)
Join metadata table from alias and return joined table alias.
execute()
Execute the query resolving calculation, count and/or batch options.
getTableAlias()
Returns the alias of the primary table.
merge($parts=null, $boolean= 'AND')
Merges multiple composite expressions with a boolean.
buildQuery(QueryBuilder $qb)
Build a database query.
static fromTable(string $table, string $alias=null)
Returns a QueryBuilder for selecting data from a given table.
Definition: Select.php:18
_elgg_services()
Get the global service provider.
Definition: elgglib.php:351
buildEntityWhereClause(QueryBuilder $qb)
Process entity attribute wheres Joins entities table on entity guid in annotations table and applies ...
$qb
Definition: queue.php:12