Elgg  Version 2.3
RelationshipsTable.php
Go to the documentation of this file.
1 <?php
2 namespace Elgg\Database;
3 
7 
18 
20 
24  protected $db;
25 
29  protected $entities;
30 
34  protected $metadata;
35 
39  protected $events;
40 
50  $this->db = $db;
51  $this->entities = $entities;
52  $this->metadata = $metadata;
53  $this->events = $events;
54  }
55 
63  public function get($id) {
64  $row = $this->getRow($id);
65  if (!$row) {
66  return false;
67  }
68 
69  return new \ElggRelationship($row);
70  }
71 
80  public function getRow($id) {
81  $sql = "SELECT * FROM {$this->db->prefix}entity_relationships WHERE id = :id";
82  $params = [
83  ':id' => (int) $id,
84  ];
85  return $this->db->getDataRow($sql, null, $params);
86  }
87 
96  public function delete($id, $call_event = true) {
97  $id = (int)$id;
98 
99  $relationship = $this->get($id);
100 
101  if ($call_event && !$this->events->trigger('delete', 'relationship', $relationship)) {
102  return false;
103  }
104 
105  $sql = "DELETE FROM {$this->db->prefix}entity_relationships WHERE id = :id";
106  $params = [
107  ':id' => $id,
108  ];
109  return $this->db->deleteData($sql, $params);
110  }
111 
126  public function add($guid_one, $relationship, $guid_two, $return_id = false) {
127  if (strlen($relationship) > \ElggRelationship::RELATIONSHIP_LIMIT) {
128  $msg = "relationship name cannot be longer than " . \ElggRelationship::RELATIONSHIP_LIMIT;
129  throw new \InvalidArgumentException($msg);
130  }
131 
132  // Check for duplicates
133  // note: escape $relationship after this call, we don't want to double-escape
134  if ($this->check($guid_one, $relationship, $guid_two)) {
135  return false;
136  }
137 
138  $sql = "
139  INSERT INTO {$this->db->prefix}entity_relationships
140  (guid_one, relationship, guid_two, time_created)
141  VALUES (:guid1, :relationship, :guid2, :time)
142  ";
143  $params = [
144  ':guid1' => (int)$guid_one,
145  ':guid2' => (int)$guid_two,
146  ':relationship' => $relationship,
147  ':time' => $this->getCurrentTime()->getTimestamp(),
148  ];
149 
150  try {
151  $id = $this->db->insertData($sql, $params);
152  if (!$id) {
153  return false;
154  }
155  } catch (\DatabaseException $e) {
156  $prev = $e->getPrevious();
157  if ($prev instanceof UniqueConstraintViolationException) {
158  // duplicate key error see https://github.com/Elgg/Elgg/issues/9179
159  return false;
160  }
161  throw $e;
162  }
163 
164  $obj = $this->get($id);
165 
166  $result = $this->events->trigger('create', 'relationship', $obj);
167  if (!$result) {
168  $this->delete($id, false);
169  return false;
170  }
171 
172  return $return_id ? $obj->id : true;
173  }
174 
186  public function check($guid_one, $relationship, $guid_two) {
187  $query = "
188  SELECT * FROM {$this->db->prefix}entity_relationships
189  WHERE guid_one = :guid1
190  AND relationship = :relationship
191  AND guid_two = :guid2
192  LIMIT 1
193  ";
194  $params = [
195  ':guid1' => (int)$guid_one,
196  ':guid2' => (int)$guid_two,
197  ':relationship' => $relationship,
198  ];
199  $row = $this->rowToElggRelationship($this->db->getDataRow($query, null, $params));
200  if ($row) {
201  return $row;
202  }
203 
204  return false;
205  }
206 
218  public function remove($guid_one, $relationship, $guid_two) {
219  $obj = $this->check($guid_one, $relationship, $guid_two);
220  if (!$obj) {
221  return false;
222  }
223 
224  return $this->delete($obj->id);
225  }
226 
238  public function removeAll($guid, $relationship = "", $inverse_relationship = false, $type = '') {
239  $guid = (int) $guid;
240  $params = [];
241 
242  if (!empty($relationship)) {
243  $where = "AND er.relationship = :relationship";
244  $params[':relationship'] = $relationship;
245  } else {
246  $where = "";
247  }
248 
249  if (!empty($type)) {
250  if (!$inverse_relationship) {
251  $join = "JOIN {$this->db->prefix}entities e ON e.guid = er.guid_two";
252  } else {
253  $join = "JOIN {$this->db->prefix}entities e ON e.guid = er.guid_one";
254  $where .= " AND ";
255  }
256  $where .= " AND e.type = :type";
257  $params[':type'] = $type;
258  } else {
259  $join = "";
260  }
261 
262  $guid_col = $inverse_relationship ? "guid_two" : "guid_one";
263 
264  $this->db->deleteData("
265  DELETE er FROM {$this->db->prefix}entity_relationships AS er
266  $join
267  WHERE $guid_col = $guid
268  $where
269  ", $params);
270 
271  return true;
272  }
273 
283  public function getAll($guid, $inverse_relationship = false) {
284  $params[':guid'] = (int)$guid;
285 
286  $where = ($inverse_relationship ? "guid_two = :guid" : "guid_one = :guid");
287 
288  $query = "SELECT * from {$this->db->prefix}entity_relationships WHERE {$where}";
289 
290  return $this->db->getData($query, [$this, 'rowToElggRelationship'], $params);
291  }
292 
334  public function getEntities($options) {
335  $defaults = array(
336  'relationship' => null,
337  'relationship_guid' => null,
338  'inverse_relationship' => false,
339  'relationship_join_on' => 'guid',
340 
341  'relationship_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
342  'relationship_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
343  );
344 
345  $options = array_merge($defaults, $options);
346 
347  $join_column = "e.{$options['relationship_join_on']}";
348 
349  $clauses = $this->getEntityRelationshipWhereSql($join_column, $options['relationship'],
350  $options['relationship_guid'], $options['inverse_relationship']);
351 
352  if ($clauses) {
353  // merge wheres to pass to get_entities()
354  if (isset($options['wheres']) && !is_array($options['wheres'])) {
355  $options['wheres'] = array($options['wheres']);
356  } elseif (!isset($options['wheres'])) {
357  $options['wheres'] = array();
358  }
359 
360  $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
361 
362  // limit based on time created
363  $time_wheres = $this->entities->getEntityTimeWhereSql('r',
364  $options['relationship_created_time_upper'],
365  $options['relationship_created_time_lower']);
366  if ($time_wheres) {
367  $options['wheres'] = array_merge($options['wheres'], array($time_wheres));
368  }
369  // merge joins to pass to get_entities()
370  if (isset($options['joins']) && !is_array($options['joins'])) {
371  $options['joins'] = array($options['joins']);
372  } elseif (!isset($options['joins'])) {
373  $options['joins'] = array();
374  }
375 
376  $options['joins'] = array_merge($options['joins'], $clauses['joins']);
377 
378  if (isset($options['selects']) && !is_array($options['selects'])) {
379  $options['selects'] = array($options['selects']);
380  } elseif (!isset($options['selects'])) {
381  $options['selects'] = array();
382  }
383 
384  $select = array('r.id');
385 
386  $options['selects'] = array_merge($options['selects'], $select);
387 
388  if (!isset($options['group_by'])) {
389  $options['group_by'] = $clauses['group_by'];
390  }
391  }
392 
393  return $this->metadata->getEntities($options);
394  }
395 
410  public function getEntityRelationshipWhereSql($column, $relationship = null,
411  $relationship_guid = null, $inverse_relationship = false) {
412 
413  if ($relationship == null && $relationship_guid == null) {
414  return '';
415  }
416 
417  $wheres = array();
418  $joins = array();
419  $group_by = '';
420 
421  if ($inverse_relationship) {
422  $joins[] = "JOIN {$this->db->prefix}entity_relationships r on r.guid_one = $column";
423  } else {
424  $joins[] = "JOIN {$this->db->prefix}entity_relationships r on r.guid_two = $column";
425  }
426 
427  if ($relationship) {
428  $wheres[] = "r.relationship = '" . $this->db->sanitizeString($relationship) . "'";
429  }
430 
431  if ($relationship_guid) {
432  if ($inverse_relationship) {
433  $wheres[] = "r.guid_two = '$relationship_guid'";
434  } else {
435  $wheres[] = "r.guid_one = '$relationship_guid'";
436  }
437  } else {
438  // See #5775. Queries that do not include a relationship_guid must be grouped by entity table alias,
439  // otherwise the result set is not unique
440  $group_by = $column;
441  }
442 
443  if ($where_str = implode(' AND ', $wheres)) {
444 
445  return array('wheres' => array("($where_str)"), 'joins' => $joins, 'group_by' => $group_by);
446  }
447 
448  return '';
449  }
450 
460  public function getEntitiesFromCount(array $options = array()) {
461  $options['selects'][] = "COUNT(e.guid) as total";
462  $options['group_by'] = 'r.guid_two';
463  $options['order_by'] = 'total desc';
464  return $this->getEntities($options);
465  }
466 
475  public function rowToElggRelationship($row) {
476  if ($row instanceof \stdClass) {
477  return new \ElggRelationship($row);
478  }
479 
480  return false;
481  }
482 }
elgg menu metadata
for compatibility with Elgg 3.0
Definition: admin.css.php:1194
getRow($id)
Get a database row from the relationship table.
rowToElggRelationship($row)
Convert a database row to a new .
$e
Definition: metadata.php:12
$defaults
The Elgg database.
Definition: Database.php:17
if($selector) $select
Definition: filter.php:36
$column
Definition: add.php:13
getAll($guid, $inverse_relationship=false)
Get all the relationships for a given GUID.
check($guid_one, $relationship, $guid_two)
Check if a relationship exists between two entities.
getCurrentTime($modifier= '')
Get the (cloned) time.
Definition: TimeUsing.php:26
$guid
Removes an admin notice.
$options
Elgg admin footer.
Definition: footer.php:6
$params
Definition: login.php:72
getEntityRelationshipWhereSql($column, $relationship=null, $relationship_guid=null, $inverse_relationship=false)
Returns SQL appropriate for relationship joins and wheres.
const ELGG_ENTITIES_ANY_VALUE
Definition: elgglib.php:2095
add($guid_one, $relationship, $guid_two, $return_id=false)
Create a relationship between two entities.
removeAll($guid, $relationship="", $inverse_relationship=false, $type= '')
Removes all relationships originating from a particular entity.
getEntities($options)
Return entities matching a given query joining against a relationship.
__construct(Database $db, EntityTable $entities, MetadataTable $metadata, EventsService $events)
Constructor.
getEntitiesFromCount(array $options=array())
Gets the number of entities by a the number of entities related to them in a particular way...
$row
trait TimeUsing
Adds methods for setting the current time (for testing)
Definition: TimeUsing.php:11
if(!$collection_name) $id
Definition: add.php:17
http free of to any person obtaining a copy of this software and associated documentation to deal in the Software without including without limitation the rights to use
Definition: MIT-LICENSE.txt:5
if(!$display_name) $type
Definition: delete.php:27