Elgg  Version 3.0
Metadata.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
5 use Closure;
12 use ElggData;
13 use ElggEntity;
14 use ElggMetadata;
17 use LogicException;
18 
27 class Metadata extends Repository {
28 
32  public function count() {
33  $qb = Select::fromTable('metadata', 'n_table');
34 
35  $count_expr = $this->options->distinct ? "DISTINCT n_table.id" : "*";
36  $qb->select("COUNT({$count_expr}) AS total");
37 
38  $qb = $this->buildQuery($qb);
39 
40  $result = _elgg_services()->db->getDataRow($qb);
41 
42  if (empty($result)) {
43  return 0;
44  }
45 
46  return (int) $result->total;
47  }
48 
59  public function calculate($function, $property, $property_type = null) {
60 
61  if (!in_array(strtolower($function), QueryBuilder::$calculations)) {
62  throw new InvalidArgumentException("'$function' is not a valid numeric function");
63  }
64 
65  if (!isset($property_type)) {
66  $property_type = 'metadata';
67  }
68 
69  $qb = Select::fromTable('metadata', 'n_table');
70 
71  switch ($property_type) {
72  case 'attribute':
73  if (!in_array($property, ElggEntity::$primary_attr_names)) {
74  throw new InvalidParameterException("'$property' is not a valid attribute");
75  }
76 
80  $alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e');
81  $qb->addSelect("{$function}({$alias}.{$property}) AS calculation");
82  break;
83 
84  case 'metadata' :
85  $alias = 'n_table';
86  if (!empty($this->options->metadata_name_value_pairs) && $this->options->metadata_name_value_pairs[0]->names != $property) {
87  $alias = $qb->joinMetadataTable('n_table', 'entity_guid', $property);
88  }
89  $qb->addSelect("{$function}($alias.value) AS calculation");
90  break;
91 
92  case 'annotation' :
93  $alias = $qb->joinAnnotationTable('n_table', 'entity_guid', $property);
94  $qb->addSelect("{$function}({$alias}.value) AS calculation");
95  break;
96 
97  case 'private_setting' :
98  $alias = $qb->joinPrivateSettingsTable('n_table', 'entity_guid', $property);
99  $qb->addSelect("{$function}({$alias}.value) AS calculation");
100  break;
101  }
102 
103  $qb = $this->buildQuery($qb);
104 
105  $result = _elgg_services()->db->getDataRow($qb);
106 
107  if (empty($result)) {
108  return 0;
109  }
110 
111  return (int) $result->calculation;
112  }
113 
123  public function get($limit = null, $offset = null, $callback = null) {
124 
125  $qb = Select::fromTable('metadata', 'n_table');
126 
127  $distinct = $this->options->distinct ? "DISTINCT" : "";
128  $qb->select("$distinct n_table.*");
129 
130  $this->expandInto($qb, 'n_table');
131 
132  $qb = $this->buildQuery($qb);
133 
134  // Keeping things backwards compatible
135  $original_order = elgg_extract('order_by', $this->options->__original_options);
136  if (empty($original_order) && $original_order !== false) {
137  $qb->addOrderBy('n_table.time_created', 'asc');
138  $qb->addOrderBy('n_table.id', 'asc');
139  }
140 
141  if ($limit > 0) {
142  $qb->setMaxResults((int) $limit);
143  $qb->setFirstResult((int) $offset);
144  }
145 
146  $callback = $callback ? : $this->options->callback;
147  if (!isset($callback)) {
148  $callback = function ($row) {
149  return new ElggMetadata($row);
150  };
151  }
152 
153  return _elgg_services()->db->getData($qb, $callback);
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->buildPairedMetadataClause($qb, $this->options->metadata_name_value_pairs, $this->options->metadata_name_value_pairs_operator);
211  $ands[] = $this->buildEntityWhereClause($qb);
212  $ands[] = $this->buildPairedMetadataClause($qb, $this->options->search_name_value_pairs, 'OR');
213  $ands[] = $this->buildPairedAnnotationClause($qb, $this->options->annotation_name_value_pairs, $this->options->annotation_name_value_pairs_operator);
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 
236  // Even if all of these properties are empty, we want to add this clause regardless,
237  // to ensure that entity access clauses are appended to the query
238 
239  $joined_alias = $qb->joinEntitiesTable('n_table', 'entity_guid', 'inner', 'e');
240  return EntityWhereClause::factory($this->options)->prepare($qb, $joined_alias);
241  }
242 
253  protected function buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
254  $parts = [];
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 buildPairedAnnotationClause(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->joinAnnotationTable('n_table', 'entity_guid');
280  } else {
281  $joined_alias = $qb->joinAnnotationTable('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 
326  protected function buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean = 'AND') {
327  $parts = [];
328 
329  foreach ($clauses as $clause) {
330  if (strtoupper($boolean) == 'OR' || count($clauses) > 1) {
331  $joined_alias = $qb->joinRelationshipTable('n_table', 'entity_guid', null, $clause->inverse);
332  } else {
333  $joined_alias = $qb->joinRelationshipTable('n_table', 'entity_guid', $clause->names, $clause->inverse);
334  }
335  $parts[] = $clause->prepare($qb, $joined_alias);
336  }
337 
338  return $qb->merge($parts, $boolean);
339  }
340 }
buildQuery(QueryBuilder $qb)
Build a database query.
Definition: Metadata.php:198
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
calculate($function, $property, $property_type=null)
Performs a mathematical calculation on metadata or metadata entity&#39;s properties.
Definition: Metadata.php:59
count()
{Count rows.int}
Definition: Metadata.php:32
if(!$count) $offset
Definition: pagination.php:26
buildEntityWhereClause(QueryBuilder $qb)
Process entity attribute wheres Joins entities table on entity guid in metadata table and applies whe...
Definition: Metadata.php:234
Database abstraction query builder.
joinEntitiesTable($from_alias= '', $from_column= 'guid', $join_type= 'inner', $joined_alias=null)
Join entity table from alias and return joined table alias.
Metadata repository contains methods for fetching metadata from database or performing calculations o...
Definition: Metadata.php:27
Abstract methods for interfacing with the database.
Definition: Repository.php:15
$limit
Definition: userpicker.php:52
execute()
Execute the query resolving calculation, count and/or batch options.
Definition: Metadata.php:162
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
buildPairedAnnotationClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process annotation name value pairs Joins annotation table on entity_guid in the metadata table and a...
Definition: Metadata.php:274
buildPairedPrivateSettingsClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process private settings name value pairs Joins private settings table on entity_guid in the metadata...
Definition: Metadata.php:299
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: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.
merge($parts=null, $boolean= 'AND')
Merges multiple composite expressions with a boolean.
buildPairedRelationshipClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process relationship name value pairs Joins relationship table on entity_guid in the metadata table a...
Definition: Metadata.php:326
_elgg_services()
Get the global service provider.
Definition: elgglib.php:1292
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.
elgg ElggEntity
Definition: ElggEntity.js:15
buildPairedMetadataClause(QueryBuilder $qb, $clauses, $boolean= 'AND')
Process metadata name value pairs Applies where clauses to the selected metadata table.
Definition: Metadata.php:253