Elgg  Version 4.3
RelationshipsTable.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Elgg\Database;
4 
6 use Elgg\Database;
14 
22 
23  use TimeUsing;
24 
29 
33  protected $db;
34 
38  protected $entities;
39 
43  protected $metadata;
44 
48  protected $events;
49 
59  $this->db = $db;
60  $this->entities = $entities;
61  $this->metadata = $metadata;
62  $this->events = $events;
63  }
64 
72  public function get(int $id): ?\ElggRelationship {
73  $select = Select::fromTable('entity_relationships');
74  $select->select('*')
75  ->where($select->compare('id', '=', $id, ELGG_VALUE_ID));
76 
77  return $this->db->getDataRow($select, [$this, 'rowToElggRelationship']) ?: null;
78  }
79 
88  public function delete(int $id, bool $call_event = true): bool {
89  $relationship = $this->get($id);
90  if (!$relationship instanceof \ElggRelationship) {
91  return false;
92  }
93 
94  if ($call_event && !$this->events->trigger('delete', 'relationship', $relationship)) {
95  return false;
96  }
97 
98  $delete = Delete::fromTable('entity_relationships');
99  $delete->where($delete->compare('id', '=', $id, ELGG_VALUE_ID));
100 
101  return (bool) $this->db->deleteData($delete);
102  }
103 
118  public function add(int $guid_one, string $relationship, int $guid_two, bool $return_id = false) {
119  if (strlen($relationship) > self::RELATIONSHIP_COLUMN_LENGTH) {
120  throw new InvalidArgumentException('Relationship name cannot be longer than ' . self::RELATIONSHIP_COLUMN_LENGTH);
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  // Check if the related entities exist
130  if (!$this->entities->exists($guid_one) || !$this->entities->exists($guid_two)) {
131  // one or both of the guids doesn't exist
132  return false;
133  }
134 
135  $insert = Insert::intoTable('entity_relationships');
136  $insert->values([
137  'guid_one' => $insert->param($guid_one, ELGG_VALUE_GUID),
138  'relationship' => $insert->param($relationship, ELGG_VALUE_STRING),
139  'guid_two' => $insert->param($guid_two, ELGG_VALUE_GUID),
140  'time_created' => $insert->param($this->getCurrentTime()->getTimestamp(), ELGG_VALUE_TIMESTAMP),
141  ]);
142 
143  try {
144  $id = $this->db->insertData($insert);
145  if (!$id) {
146  return false;
147  }
148  } catch (DatabaseException $e) {
149  $prev = $e->getPrevious();
150  if ($prev instanceof UniqueConstraintViolationException) {
151  // duplicate key error see https://github.com/Elgg/Elgg/issues/9179
152  return false;
153  }
154  throw $e;
155  }
156 
157  $obj = $this->get($id);
158 
159  $result = $this->events->trigger('create', 'relationship', $obj);
160  if (!$result) {
161  $this->delete($id, false);
162  return false;
163  }
164 
165  return $return_id ? $obj->id : true;
166  }
167 
179  public function check(int $guid_one, string $relationship, int $guid_two) {
180  $select = Select::fromTable('entity_relationships');
181  $select->select('*')
182  ->where($select->compare('guid_one', '=', $guid_one, ELGG_VALUE_GUID))
183  ->andWhere($select->compare('relationship', '=', $relationship, ELGG_VALUE_STRING))
184  ->andWhere($select->compare('guid_two', '=', $guid_two, ELGG_VALUE_GUID))
185  ->setMaxResults(1);
186 
187  $row = $this->db->getDataRow($select, [$this, 'rowToElggRelationship']);
188  if ($row instanceof \ElggRelationship) {
189  return $row;
190  }
191 
192  return false;
193  }
194 
206  public function remove(int $guid_one, string $relationship, int $guid_two): bool {
207  $obj = $this->check($guid_one, $relationship, $guid_two);
208  if (!$obj instanceof \ElggRelationship) {
209  return false;
210  }
211 
212  return $this->delete($obj->id);
213  }
214 
227  public function removeAll($guid, $relationship = '', $inverse_relationship = false, $type = '', bool $trigger_events = true) {
228 
229  if ($trigger_events) {
230  return $this->removeAllWithEvents($guid, $relationship, $inverse_relationship, $type);
231  }
232 
233  return $this->removeAllWithoutEvents($guid, $relationship, $inverse_relationship, $type);
234  }
235 
249  protected function removeAllWithoutEvents($guid, $relationship = '', $inverse_relationship = false, $type = '') {
250  $delete = Delete::fromTable('entity_relationships');
251 
252  if ((bool) $inverse_relationship) {
253  $delete->where($delete->compare('guid_two', '=', $guid, ELGG_VALUE_GUID));
254  } else {
255  $delete->where($delete->compare('guid_one', '=', $guid, ELGG_VALUE_GUID));
256  }
257 
258  if (!empty($relationship)) {
259  $delete->andWhere($delete->compare('relationship', '=', $relationship, ELGG_VALUE_STRING));
260  }
261 
262  if (!empty($type)) {
263  $entity_sub = $delete->subquery('entities');
264  $entity_sub->select('guid')
265  ->where($delete->compare('type', '=', $type, ELGG_VALUE_STRING));
266 
267  if (!(bool) $inverse_relationship) {
268  $delete->andWhere($delete->compare('guid_two', 'in', $entity_sub->getSQL()));
269  } else {
270  $delete->andWhere($delete->compare('guid_one', 'in', $entity_sub->getSQL()));
271  }
272  }
273 
274  $this->db->deleteData($delete);
275 
276  return true;
277  }
278 
292  protected function removeAllWithEvents($guid, $relationship = '', $inverse_relationship = false, $type = '') {
293  $select = Select::fromTable('entity_relationships');
294  $select->select('*');
295 
296  if ((bool) $inverse_relationship) {
297  $select->where($select->compare('guid_two', '=', $guid, ELGG_VALUE_GUID));
298  } else {
299  $select->where($select->compare('guid_one', '=', $guid, ELGG_VALUE_GUID));
300  }
301 
302  if (!empty($relationship)) {
303  $select->andWhere($select->compare('relationship', '=', $relationship, ELGG_VALUE_STRING));
304  }
305 
306  if (!empty($type)) {
307  $entity_sub = $select->subquery('entities');
308  $entity_sub->select('guid')
309  ->where($select->compare('type', '=', $type, ELGG_VALUE_STRING));
310 
311  if (!(bool) $inverse_relationship) {
312  $select->andWhere($select->compare('guid_two', 'in', $entity_sub->getSQL()));
313  } else {
314  $select->andWhere($select->compare('guid_one', 'in', $entity_sub->getSQL()));
315  }
316  }
317 
318  $remove_ids = [];
319 
320  $relationships = $this->db->getData($select, [$this, 'rowToElggRelationship']);
321 
322  /* @var $rel \ElggRelationship */
323  foreach ($relationships as $rel) {
324  if (!$this->events->trigger('delete', 'relationship', $rel)) {
325  continue;
326  }
327 
328  $remove_ids[] = $rel->id;
329  }
330 
331  // to prevent MySQL query length issues
332  $chunks = array_chunk($remove_ids, 250);
333  foreach ($chunks as $chunk) {
334  if (empty($chunk)) {
335  continue;
336  }
337 
338  $delete = Delete::fromTable('entity_relationships');
339  $delete->where($delete->compare('id', 'in', $chunk));
340 
341  $this->db->deleteData($delete);
342  }
343 
344  return true;
345  }
346 
357  public function getAll($guid, $inverse_relationship = false) {
358  $select = Select::fromTable('entity_relationships');
359  $select->select('*');
360 
361  if ((bool) $inverse_relationship) {
362  $select->where($select->compare('guid_two', '=', $guid, ELGG_VALUE_GUID));
363  } else {
364  $select->where($select->compare('guid_one', '=', $guid, ELGG_VALUE_GUID));
365  }
366 
367  return $this->db->getData($select, [$this, 'rowToElggRelationship']);
368  }
369 
379  public function getEntitiesFromCount(array $options = []) {
380  $options['selects'][] = new SelectClause("COUNT(e.guid) AS total");
381  $options['group_by'][] = new GroupByClause('r.guid_two');
382  $options['order_by'][] = new OrderByClause('total', 'desc');
383 
384  return Entities::find($options);
385  }
386 
394  public function rowToElggRelationship($row) {
395  if ($row instanceof \stdClass) {
396  return new \ElggRelationship($row);
397  }
398 
399  return false;
400  }
401 }
Exception thrown if an argument is not of the expected type.
static find(array $options=[])
Build and execute a new query from an array of legacy options.
Definition: Repository.php:86
rowToElggRelationship($row)
Convert a database row to a new .
The Elgg database.
Definition: Database.php:25
$relationship
Elgg default relationship view.
Definition: default.php:10
getAll($guid, $inverse_relationship=false)
Get all the relationships for a given GUID.
const ELGG_VALUE_GUID
Definition: constants.php:128
Events service.
Extends QueryBuilder with SELECT clauses.
$delete
$type
Definition: delete.php:21
const ELGG_VALUE_ID
Definition: constants.php:129
Extends QueryBuilder with GROUP BY statements.
trait TimeUsing
Adds methods for setting the current time (for testing)
Definition: TimeUsing.php:10
check(int $guid_one, string $relationship, int $guid_two)
Check if a relationship exists between two entities.
$options
Elgg admin footer.
Definition: footer.php:6
removeAllWithEvents($guid, $relationship= '', $inverse_relationship=false, $type= '')
Removes all relationships originating from a particular entity.
getCurrentTime($modifier= '')
Get the (cloned) time.
Definition: TimeUsing.php:25
static intoTable($table)
{}
Definition: Insert.php:13
Relationships table database service.
removeAllWithoutEvents($guid, $relationship= '', $inverse_relationship=false, $type= '')
Removes all relationships originating from a particular entity.
A generic parent class for database exceptions.
if(in_array('elgg-popup', $classes)) if(in_array('elgg-toggle', $classes)) $rel
Definition: url.php:155
getEntitiesFromCount(array $options=[])
Gets the number of entities by a the number of entities related to them in a particular way...
__construct(Database $db, EntityTable $entities, MetadataTable $metadata, EventsService $events)
Constructor.
Extends QueryBuilder with ORDER BY clauses.
const ELGG_VALUE_TIMESTAMP
Definition: constants.php:130
static fromTable($table, $alias=null)
{}
Definition: Select.php:13
const ELGG_VALUE_STRING
Definition: constants.php:127
add(int $guid_one, string $relationship, int $guid_two, bool $return_id=false)
Create a relationship between two entities.
removeAll($guid, $relationship= '', $inverse_relationship=false, $type= '', bool $trigger_events=true)
Removes all relationships originating from a particular entity.
$id
Generic annotation delete action.
Definition: delete.php:6
static fromTable($table, $alias=null)
{}
Definition: Delete.php:13
This class interfaces with the database to perform CRUD operations on metadata.
Entity table database service.
Definition: EntityTable.php:26
$guid
Reset an ElggUpgrade.
Definition: reset.php:6