Elgg  Version 3.0
Annotations.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
5 use Closure;
12 use ElggAnnotation;
13 use ElggEntity;
16 
25 class Annotations extends Repository {
26 
30  public function count() {
31  $qb = Select::fromTable('annotations', 'n_table');
32 
33  $count_expr = $this->options->distinct ? "DISTINCT n_table.id" : "*";
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  $property_type = 'annotation';
65  }
66 
67  $qb = Select::fromTable('annotations', 'n_table');
68 
69  switch ($property_type) {
70  case 'attribute':
71  if (!in_array($property, ElggEntity::$primary_attr_names)) {
72  throw new InvalidParameterException("'$property' is not a valid attribute");
73  }
74 
75  $alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e');
76  $qb->select("{$function}({$alias}.{$property}) AS calculation");
77  break;
78 
79  case 'annotation' :
80  $alias = 'n_table';
81  if (!empty($this->options->annotation_name_value_pairs) && $this->options->annotation_name_value_pairs[0]->names != $property) {
82  $alias = $qb->joinAnnotationTable('n_table', 'entity_guid', $property);
83  }
84  $qb->select("{$function}($alias.value) AS calculation");
85  break;
86 
87  case 'metadata' :
88  $alias = $qb->joinMetadataTable('n_table', 'entity_guid', $property);
89  $qb->select("{$function}({$alias}.value) AS calculation");
90  break;
91 
92  case 'private_setting' :
93  $alias = $qb->joinPrivateSettingsTable('n_table', 'entity_guid', $property);
94  $qb->select("{$function}({$alias}.value) AS calculation");
95  break;
96  }
97 
98  $qb = $this->buildQuery($qb);
99 
100  $result = _elgg_services()->db->getDataRow($qb);
101 
102  if (empty($result)) {
103  return 0;
104  }
105 
106  return (int) $result->calculation;
107  }
108 
118  public function get($limit = null, $offset = null, $callback = null) {
119 
120  $qb = Select::fromTable('annotations', 'n_table');
121 
122  $distinct = $this->options->distinct ? "DISTINCT" : "";
123  $qb->select("$distinct n_table.*");
124 
125  $this->expandInto($qb, 'n_table');
126 
127  $qb = $this->buildQuery($qb);
128 
129  // Keeping things backwards compatible
130  $original_order = elgg_extract('order_by', $this->options->__original_options);
131  if (empty($original_order) && $original_order !== false) {
132  $qb->addOrderBy('n_table.time_created', 'asc');
133  $qb->addOrderBy('n_table.id', 'asc');
134  }
135 
136  if ($limit > 0) {
137  $qb->setMaxResults((int) $limit);
138  $qb->setFirstResult((int) $offset);
139  }
140 
141  $callback = $callback ? : $this->options->callback;
142  if (!isset($callback)) {
143  $callback = function ($row) {
144  return new ElggAnnotation($row);
145  };
146  }
147 
148  $results = _elgg_services()->db->getData($qb, $callback);
149  if (!empty($results) && $this->options->preload_owners) {
150  _elgg_services()->entityPreloader->preload($results, ['owner_guid']);
151  }
152 
153  return $results;
154  }
155 
162  public function execute() {
163 
164  if ($this->options->annotation_calculation) {
165  $clauses = $this->options->annotation_name_value_pairs;
166  if (count($clauses) > 1 && $this->options->annotation_name_value_pairs_operator !== 'OR') {
167  throw new \LogicException("Annotation calculation can not be performed on multiple annotation name value pairs merged with AND");
168  }
169 
170  $clause = array_shift($clauses);
171 
172  return $this->calculate($this->options->annotation_calculation, $clause->names, 'annotation');
173  } else if ($this->options->metadata_calculation) {
174  $clauses = $this->options->metadata_name_value_pairs;
175  if (count($clauses) > 1 && $this->options->metadata_name_value_pairs_operator !== 'OR') {
176  throw new \LogicException("Metadata calculation can not be performed on multiple metadata name value pairs merged with AND");
177  }
178 
179  $clause = array_shift($clauses);
180 
181  return $this->calculate($this->options->metadata_calculation, $clause->names, 'metadata');
182  } else if ($this->options->count) {
183  return $this->count();
184  } else if ($this->options->batch) {
185  return $this->batch($this->options->limit, $this->options->offset, $this->options->callback);
186  } else {
187  return $this->get($this->options->limit, $this->options->offset, $this->options->callback);
188  }
189  }
190 
198  protected function buildQuery(QueryBuilder $qb) {
199 
200  $ands = [];
201 
202  foreach ($this->options->joins as $join) {
203  $join->prepare($qb, 'n_table');
204  }
205 
206  foreach ($this->options->wheres as $where) {
207  $ands[] = $where->prepare($qb, 'n_table');
208  }
209 
210  $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator);
211  $ands[] = $this->buildEntityWhereClause($qb);
212  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator);
213  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->search_name_value_pairs, 'OR');
214  $ands[] = $this->buildPairedPrivateSettingsClause($qb, $this->options->private_setting_name_value_pairs, $this->options->private_setting_name_value_pairs_operator);
215  $ands[] = $this->buildPairedRelationshipClause($qb, $this->options->relationship_pairs);
216 
217  $ands = $qb->merge($ands);
218 
219  if (!empty($ands)) {
220  $qb->andWhere($ands);
221  }
222 
223  return $qb;
224  }
225 
234  protected function buildEntityWhereClause(QueryBuilder $qb) {
235  $joined_alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e');
236  return EntityWhereClause::factory($this->options)->prepare($qb, $joined_alias);
237  }
238 
249  protected function buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
250  $parts = [];
251 
252  if (empty($clauses)) {
253  // We need to make sure that enabled and access clauses are appended to the query
254  $clauses[] = new AnnotationWhereClause();
255  }
256 
257  foreach ($clauses as $clause) {
258  $parts[] = $clause->prepare($qb, 'n_table');
259  }
260 
261  return $qb->merge($parts, $boolean);
262  }
263 
274  protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
275  $parts = [];
276 
277  foreach ($clauses as $clause) {
278  if (strtoupper($boolean) === 'OR' || count($clauses) > 1) {
279  $joined_alias = $qb->joinMetadataTable('n_table', 'entity_guid');
280  } else {
281  $joined_alias = $qb->joinMetadataTable('n_table', 'entity_guid', $clause->names);
282  }
283  $parts[] = $clause->prepare($qb, $joined_alias);
284  }
285 
286  return $qb->merge($parts, $boolean);
287  }
288 
299  protected function buildPairedPrivateSettingsClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
300  $parts = [];
301 
302  foreach ($clauses as $clause) {
303  if (strtoupper($boolean) === 'OR' || count($clauses) > 1) {
304  $joined_alias = $qb->joinPrivateSettingsTable('n_table', 'entity_guid');
305  } else {
306  $joined_alias = $qb->joinPrivateSettingsTable('n_table', 'entity_guid', $clause->names);
307  }
308  $parts[] = $clause->prepare($qb, $joined_alias);
309  }
310 
311  return $qb->merge($parts, $boolean);
312  }
313 
324  protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
325  $parts = [];
326 
327  foreach ($clauses as $clause) {
328  $join_on = $clause->join_on == 'guid' ? 'entity_guid' : $clause->join_on;
329  if (strtoupper($boolean) == 'OR' || count($clauses) > 1) {
330  $joined_alias = $qb->joinRelationshipTable('n_table', $join_on, null, $clause->inverse);
331  } else {
332  $joined_alias = $qb->joinRelationshipTable('n_table', $join_on, $clause->names, $clause->inverse);
333  }
334  $parts[] = $clause->prepare($qb, $joined_alias);
335  }
336 
337  return $qb->merge($parts, $boolean);
338  }
339 }
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.Number of rows to fetch Index of the first row Callback function to run d...
Definition: Repository.php:96
buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process relationship name value pairs Joins relationship table on entity_guid in the annotations tabl...
calculate($function, $property, $property_type=null)
Performs a mathematical calculation on metadata or metadata entity&#39;s properties.
Definition: Annotations.php:57
if(!$count) $offset
Definition: pagination.php:26
Database abstraction query builder.
Builds queries for matching annotations against their properties.
joinEntitiesTable($from_alias= '', $from_column= 'guid', $join_type= 'inner', $joined_alias=null)
Join entity table from alias and return joined table alias.
buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process metadata name value pairs Joins metadata table on entity_guid in the annotations table and ap...
Abstract methods for interfacing with the database.
Definition: Repository.php:15
$limit
Definition: userpicker.php:52
static $primary_attr_names
Definition: ElggEntity.php:49
expandInto(QueryBuilder $qb, $table_alias=null)
Extend query builder with select, group_by, having and order_by clauses from $options.
Definition: Repository.php:180
count()
{Count rows.int}
Definition: Annotations.php:30
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.
execute()
Execute the query resolving calculation, count and/or batch options.
merge($parts=null, $boolean= 'AND')
Merges multiple composite expressions with a boolean.
buildQuery(QueryBuilder $qb)
Build a database query.
_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.
Annotation repository contains methods for fetching annotations from database or performing calculati...
Definition: Annotations.php:25
buildEntityWhereClause(QueryBuilder $qb)
Process entity attribute wheres Joins entities table on entity guid in annotations table and applies ...
elgg ElggEntity
Definition: ElggEntity.js:15
buildPairedPrivateSettingsClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process private settings name value pairs Joins private settings table on entity_guid in the annotati...