Elgg  Version 2.2
 All Classes Namespaces Files Functions Variables Pages
RelationshipsTable.php
Go to the documentation of this file.
1 <?php
2 namespace Elgg\Database;
3 
4 use Elgg\Database;
6 
17 
21  private $db;
22 
26  private $entities;
27 
31  private $metadata;
32 
36  private $events;
37 
46  public function __construct(Database $db, EntityTable $entities, MetadataTable $metadata, EventsService $events) {
47  $this->db = $db;
48  $this->entities = $entities;
49  $this->metadata = $metadata;
50  $this->events = $events;
51  }
52 
60  public function get($id) {
61  $row = $this->getRow($id);
62  if (!$row) {
63  return false;
64  }
65 
66  return new \ElggRelationship($row);
67  }
68 
77  public function getRow($id) {
78  $id = (int)$id;
79 
80  return $this->db->getDataRow("SELECT * FROM {$this->db->getTablePrefix()}entity_relationships WHERE id = $id");
81  }
82 
91  public function delete($id, $call_event = true) {
92  $id = (int)$id;
93 
94  $relationship = $this->get($id);
95 
96  if ($call_event && !$this->events->trigger('delete', 'relationship', $relationship)) {
97  return false;
98  }
99 
100  return $this->db->deleteData("DELETE FROM {$this->db->getTablePrefix()}entity_relationships WHERE id = $id");
101  }
102 
117  public function add($guid_one, $relationship, $guid_two, $return_id = false) {
118  if (strlen($relationship) > \ElggRelationship::RELATIONSHIP_LIMIT) {
119  $msg = "relationship name cannot be longer than " . \ElggRelationship::RELATIONSHIP_LIMIT;
120  throw new \InvalidArgumentException($msg);
121  }
122 
123  // Check for duplicates
124  // note: escape $relationship after this call, we don't want to double-escape
125  if ($this->check($guid_one, $relationship, $guid_two)) {
126  return false;
127  }
128 
129  $sql = "
130  INSERT INTO {$this->db->getTablePrefix()}entity_relationships
131  (guid_one, relationship, guid_two, time_created)
132  VALUES (:guid1, :relationship, :guid2, :time)
133  ON DUPLICATE KEY UPDATE time_created = :time
134  ";
135  $params = [
136  ':guid1' => (int)$guid_one,
137  ':guid2' => (int)$guid_two,
138  ':relationship' => $relationship,
139  ':time' => time(),
140  ];
141 
142  $id = $this->db->insertData($sql, $params);
143  if (!$id) {
144  return false;
145  }
146 
147  $obj = $this->get($id);
148 
149  $result = $this->events->trigger('create', 'relationship', $obj);
150  if (!$result) {
151  $this->delete($id, false);
152  return false;
153  }
154 
155  return $return_id ? $obj->id : true;
156  }
157 
169  public function check($guid_one, $relationship, $guid_two) {
170  $query = "
171  SELECT * FROM {$this->db->getTablePrefix()}entity_relationships
172  WHERE guid_one = :guid1
173  AND relationship = :relationship
174  AND guid_two = :guid2
175  LIMIT 1
176  ";
177  $params = [
178  ':guid1' => (int)$guid_one,
179  ':guid2' => (int)$guid_two,
180  ':relationship' => $relationship,
181  ];
182  $row = $this->rowToElggRelationship($this->db->getDataRow($query, null, $params));
183  if ($row) {
184  return $row;
185  }
186 
187  return false;
188  }
189 
201  public function remove($guid_one, $relationship, $guid_two) {
202  $obj = $this->check($guid_one, $relationship, $guid_two);
203  if (!$obj) {
204  return false;
205  }
206 
207  return $this->delete($obj->id);
208  }
209 
221  public function removeAll($guid, $relationship = "", $inverse_relationship = false, $type = '') {
222  $guid = (int) $guid;
223  $params = [];
224 
225  if (!empty($relationship)) {
226  $where = "AND er.relationship = :relationship";
227  $params[':relationship'] = $relationship;
228  } else {
229  $where = "";
230  }
231 
232  if (!empty($type)) {
233  if (!$inverse_relationship) {
234  $join = "JOIN {$this->db->getTablePrefix()}entities e ON e.guid = er.guid_two";
235  } else {
236  $join = "JOIN {$this->db->getTablePrefix()}entities e ON e.guid = er.guid_one";
237  $where .= " AND ";
238  }
239  $where .= " AND e.type = :type";
240  $params[':type'] = $type;
241  } else {
242  $join = "";
243  }
244 
245  $guid_col = $inverse_relationship ? "guid_two" : "guid_one";
246 
247  $this->db->deleteData("
248  DELETE er FROM {$this->db->getTablePrefix()}entity_relationships AS er
249  $join
250  WHERE $guid_col = $guid
251  $where
252  ", $params);
253 
254  return true;
255  }
256 
266  public function getAll($guid, $inverse_relationship = false) {
267  $params[':guid'] = (int)$guid;
268 
269  $where = ($inverse_relationship ? "guid_two = :guid" : "guid_one = :guid");
270 
271  $query = "SELECT * from {$this->db->getTablePrefix()}entity_relationships WHERE {$where}";
272 
273  return $this->db->getData($query, [$this, 'rowToElggRelationship'], $params);
274  }
275 
317  public function getEntities($options) {
318  $defaults = array(
319  'relationship' => null,
320  'relationship_guid' => null,
321  'inverse_relationship' => false,
322  'relationship_join_on' => 'guid',
323 
324  'relationship_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
325  'relationship_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
326  );
327 
328  $options = array_merge($defaults, $options);
329 
330  $join_column = "e.{$options['relationship_join_on']}";
331 
332  $clauses = $this->getEntityRelationshipWhereSql($join_column, $options['relationship'],
333  $options['relationship_guid'], $options['inverse_relationship']);
334 
335  if ($clauses) {
336  // merge wheres to pass to get_entities()
337  if (isset($options['wheres']) && !is_array($options['wheres'])) {
338  $options['wheres'] = array($options['wheres']);
339  } elseif (!isset($options['wheres'])) {
340  $options['wheres'] = array();
341  }
342 
343  $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
344 
345  // limit based on time created
346  $time_wheres = $this->entities->getEntityTimeWhereSql('r',
347  $options['relationship_created_time_upper'],
348  $options['relationship_created_time_lower']);
349  if ($time_wheres) {
350  $options['wheres'] = array_merge($options['wheres'], array($time_wheres));
351  }
352  // merge joins to pass to get_entities()
353  if (isset($options['joins']) && !is_array($options['joins'])) {
354  $options['joins'] = array($options['joins']);
355  } elseif (!isset($options['joins'])) {
356  $options['joins'] = array();
357  }
358 
359  $options['joins'] = array_merge($options['joins'], $clauses['joins']);
360 
361  if (isset($options['selects']) && !is_array($options['selects'])) {
362  $options['selects'] = array($options['selects']);
363  } elseif (!isset($options['selects'])) {
364  $options['selects'] = array();
365  }
366 
367  $select = array('r.id');
368 
369  $options['selects'] = array_merge($options['selects'], $select);
370 
371  if (!isset($options['group_by'])) {
372  $options['group_by'] = $clauses['group_by'];
373  }
374  }
375 
376  return $this->metadata->getEntities($options);
377  }
378 
393  public function getEntityRelationshipWhereSql($column, $relationship = null,
394  $relationship_guid = null, $inverse_relationship = false) {
395 
396  if ($relationship == null && $relationship_guid == null) {
397  return '';
398  }
399 
400  $wheres = array();
401  $joins = array();
402  $group_by = '';
403 
404  if ($inverse_relationship) {
405  $joins[] = "JOIN {$this->db->getTablePrefix()}entity_relationships r on r.guid_one = $column";
406  } else {
407  $joins[] = "JOIN {$this->db->getTablePrefix()}entity_relationships r on r.guid_two = $column";
408  }
409 
410  if ($relationship) {
411  $wheres[] = "r.relationship = '" . $this->db->sanitizeString($relationship) . "'";
412  }
413 
414  if ($relationship_guid) {
415  if ($inverse_relationship) {
416  $wheres[] = "r.guid_two = '$relationship_guid'";
417  } else {
418  $wheres[] = "r.guid_one = '$relationship_guid'";
419  }
420  } else {
421  // See #5775. Queries that do not include a relationship_guid must be grouped by entity table alias,
422  // otherwise the result set is not unique
423  $group_by = $column;
424  }
425 
426  if ($where_str = implode(' AND ', $wheres)) {
427 
428  return array('wheres' => array("($where_str)"), 'joins' => $joins, 'group_by' => $group_by);
429  }
430 
431  return '';
432  }
433 
443  public function getEntitiesFromCount(array $options = array()) {
444  $options['selects'][] = "COUNT(e.guid) as total";
445  $options['group_by'] = 'r.guid_two';
446  $options['order_by'] = 'total desc';
447  return $this->getEntities($options);
448  }
449 
458  public function rowToElggRelationship($row) {
459  if ($row instanceof \stdClass) {
460  return new \ElggRelationship($row);
461  }
462 
463  return false;
464  }
465 }
getRow($id)
Get a database row from the relationship table.
rowToElggRelationship($row)
Convert a database row to a new .
$defaults
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.
$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:2001
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
if(!$collection_name) $id
Definition: add.php:17
if(!$display_name) $type
Definition: delete.php:27