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