Passed
Push — master ( c0a3a7...3b84a4 )
by Jeroen
58:51
created

engine/classes/Elgg/Database/EntityTable.php (7 issues)

1
<?php
2
3
namespace Elgg\Database;
4
5
use ClassException;
6
use DatabaseException;
7
use Elgg\Cache\EntityCache;
8
use Elgg\Cache\MetadataCache;
9
use Elgg\Config;
10
use Elgg\Database;
11
use Elgg\Database\Clauses\EntityWhereClause;
12
use Elgg\Database\Clauses\OrderByClause;
13
use Elgg\Database\EntityTable\UserFetchFailureException;
14
use Elgg\EntityPreloader;
15
use Elgg\EventsService;
16
use Elgg\I18n\Translator;
17
use Elgg\Logger;
18
use ElggBatch;
19
use ElggEntity;
20
use ElggGroup;
21
use ElggObject;
22
use ElggSession;
23
use ElggSite;
24
use ElggUser;
25
use InvalidParameterException;
26
use stdClass;
27
28
/**
29
 * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
30
 *
31
 * @access     private
32
 *
33
 * @package    Elgg.Core
34
 * @subpackage Database
35
 * @since      1.10.0
36
 */
37
class EntityTable {
38
39
	use \Elgg\TimeUsing;
40
41
	/**
42
	 * @var Config
43
	 */
44
	protected $config;
45
46
	/**
47
	 * @var Database
48
	 */
49
	protected $db;
50
51
	/**
52
	 * @var string
53
	 */
54
	protected $table;
55
56
	/**
57
	 * @var array
58
	 */
59
	protected $entity_classes;
60
61
	/**
62
	 * @var EntityCache
63
	 */
64
	protected $entity_cache;
65
66
	/**
67
	 * @var EntityPreloader
68
	 */
69
	protected $entity_preloader;
70
71
	/**
72
	 * @var MetadataCache
73
	 */
74
	protected $metadata_cache;
75
76
	/**
77
	 * @var EventsService
78
	 */
79
	protected $events;
80
81
	/**
82
	 * @var ElggSession
83
	 */
84
	protected $session;
85
86
	/**
87
	 * @var Translator
88
	 */
89
	protected $translator;
90
91
	/**
92
	 * @var Logger
93
	 */
94
	protected $logger;
95
96
	/**
97
	 * Constructor
98
	 *
99
	 * @param Config        $config         Config
100
	 * @param Database      $db             Database
101
	 * @param EntityCache   $entity_cache   Entity cache
102
	 * @param MetadataCache $metadata_cache Metadata cache
103
	 * @param EventsService $events         Events service
104
	 * @param ElggSession   $session        Session
105
	 * @param Translator    $translator     Translator
106
	 * @param Logger        $logger         Logger
107
	 */
108 4417
	public function __construct(
109
		Config $config,
110
		Database $db,
111
		EntityCache $entity_cache,
112
		MetadataCache $metadata_cache,
113
		EventsService $events,
114
		ElggSession $session,
115
		Translator $translator,
116
		Logger $logger
117
	) {
118 4417
		$this->config = $config;
119 4417
		$this->db = $db;
120 4417
		$this->table = $this->db->prefix . 'entities';
121 4417
		$this->entity_cache = $entity_cache;
122 4417
		$this->metadata_cache = $metadata_cache;
123 4417
		$this->events = $events;
124 4417
		$this->session = $session;
125 4417
		$this->translator = $translator;
126 4417
		$this->logger = $logger;
127 4417
	}
128
129
	/**
130
	 * Sets class constructor name for entities with given type and subtype
131
	 *
132
	 * @param string $type    Entity type
133
	 * @param string $subtype Entity subtype
134
	 * @param string $class   Entity class
135
	 *
136
	 * @return void
137
	 * @throws InvalidParameterException
138
	 */
139 4791
	public function setEntityClass($type, $subtype, $class = '') {
140 4791
		if (!in_array($type, Config::getEntityTypes())) {
141
			throw new InvalidParameterException("$type is not a valid entity type");
142
		}
143
144 4791
		$this->entity_classes[$type][$subtype] = $class;
145 4791
	}
146
147
	/**
148
	 * Returns class name registered as a constructor for a given type and subtype
149
	 *
150
	 * @param string $type    Entity type
151
	 * @param string $subtype Entity subtype
152
	 *
153
	 * @return string
154
	 */
155 5313
	public function getEntityClass($type, $subtype) {
156 5313
		if (isset($this->entity_classes[$type][$subtype])) {
157 5137
			return $this->entity_classes[$type][$subtype];
158
		}
159
160 770
		return '';
161
	}
162
163
	/**
164
	 * Returns a database row from the entities table.
165
	 *
166
	 * @see     entity_row_to_elggstar()
167
	 *
168
	 * @tip     Use get_entity() to return the fully loaded entity.
169
	 *
170
	 * @warning This will only return results if a) it exists, b) you have access to it.
171
	 * see {@link _elgg_get_access_where_sql()}.
172
	 *
173
	 * @param int $guid      The GUID of the object to extract
174
	 * @param int $user_guid GUID of the user accessing the row
175
	 *                       Defaults to logged in user if null
176
	 *                       Builds an access query for a logged out user if 0
177
	 *
178
	 * @return stdClass|false
179
	 * @access  private
180
	 */
181 523
	public function getRow($guid, $user_guid = null) {
182
183 523
		if (!$guid) {
184
			return false;
185
		}
186
187 523
		$where = new EntityWhereClause();
188 523
		$where->guids = (int) $guid;
189 523
		$where->viewer_guid = $user_guid;
190
191 523
		$select = Select::fromTable('entities');
192 523
		$select->select('*');
193 523
		$select->addClause($where);
194
195 523
		return $this->db->getDataRow($select);
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->db->getDataRow($select) returns the type array which is incompatible with the documented return type stdClass|false.
Loading history...
196
	}
197
198
	/**
199
	 * Adds a new row to the entity table
200
	 *
201
	 * @param stdClass $row        Entity base information
202
	 * @param array    $attributes All primary table attributes
203
	 *                             Used by database mock services to allow mocking
204
	 *                             entities that were instantiated using new keyword
205
	 *                             and calling ElggEntity::save()
206
	 *
207
	 * @return int|false
208
	 */
209 509
	public function insertRow(stdClass $row, array $attributes = []) {
210
211
		$sql = "
212 509
			INSERT INTO {$this->db->prefix}entities
213
			(type, subtype, owner_guid, container_guid, access_id, time_created, time_updated, last_action)
214
			VALUES
215
			(:type, :subtype, :owner_guid, :container_guid, :access_id, :time_created, :time_updated, :last_action)
216
		";
217
218 509
		return $this->db->insertData($sql, [
219 509
			':type' => $row->type,
220 509
			':subtype' => $row->subtype,
221 509
			':owner_guid' => $row->owner_guid,
222 509
			':container_guid' => $row->container_guid,
223 509
			':access_id' => $row->access_id,
224 509
			':time_created' => $row->time_created,
225 509
			':time_updated' => $row->time_updated,
226 509
			':last_action' => $row->last_action,
227
		]);
228
	}
229
230
	/**
231
	 * Update entity table row
232
	 *
233
	 * @param int      $guid Entity guid
234
	 * @param stdClass $row  Updated data
235
	 *
236
	 * @return int|false
237
	 */
238 172
	public function updateRow($guid, stdClass $row) {
239
		$sql = "
240 172
			UPDATE {$this->db->prefix}entities
241
			SET owner_guid = :owner_guid,
242
			    access_id = :access_id,
243
				container_guid = :container_guid,
244
				time_created = :time_created,
245
				time_updated = :time_updated
246
			WHERE guid = :guid
247
		";
248
249
		$params = [
250 172
			':owner_guid' => $row->owner_guid,
251 172
			':access_id' => $row->access_id,
252 172
			':container_guid' => $row->container_guid,
253 172
			':time_created' => $row->time_created,
254 172
			':time_updated' => $row->time_updated,
255 172
			':guid' => $guid,
256
		];
257
258 172
		return $this->db->updateData($sql, false, $params);
0 ignored issues
show
Bug Best Practice introduced by Ismayil Khayredinov
The expression return $this->db->update...a($sql, false, $params) returns the type true which is incompatible with the documented return type integer|false.
Loading history...
259
	}
260
261
	/**
262
	 * Create an Elgg* object from a given entity row.
263
	 *
264
	 * Handles loading all tables into the correct class.
265
	 *
266
	 * @see    get_entity_as_row()
267
	 * @see    get_entity()
268
	 *
269
	 * @access private
270
	 *
271
	 * @param stdClass $row The row of the entry in the entities table.
272
	 *
273
	 * @return ElggEntity|false
274
	 * @throws ClassException
275
	 * @throws InvalidParameterException
276
	 */
277 5313
	public function rowToElggStar(stdClass $row) {
278 5313
		if (!isset($row->guid) || !isset($row->subtype)) {
279
			return false;
280
		}
281
282 5313
		$class_name = $this->getEntityClass($row->type, $row->subtype);
283 5313
		if ($class_name && !class_exists($class_name)) {
284
			$this->logger->error("Class '$class_name' was not found, missing plugin?");
285
			$class_name = '';
286
		}
287
288 5313
		if (!$class_name) {
289
			$map = [
290 770
				'object' => ElggObject::class,
291
				'user' => ElggUser::class,
292
				'group' => ElggGroup::class,
293
				'site' => ElggSite::class,
294
			];
295
296 770
			if (isset($map[$row->type])) {
297 770
				$class_name = $map[$row->type];
298
			} else {
299
				throw new InvalidParameterException("Entity type {$row->type} is not supported.");
300
			}
301
		}
302
303 5313
		$entity = new $class_name($row);
304 5313
		if (!$entity instanceof ElggEntity) {
305
			throw new ClassException("$class_name must extend " . ElggEntity::class);
306
		}
307
308 5313
		return $entity;
309
	}
310
311
	/**
312
	 * Get an entity from the in-memory or memcache caches
313
	 *
314
	 * @param int $guid GUID
315
	 *
316
	 * @return \ElggEntity|false
317
	 */
318 5292
	public function getFromCache($guid) {
319 5292
		$entity = $this->entity_cache->load($guid);
320 5292
		if ($entity) {
321 499
			return $entity;
322
		}
323
324 5291
		$cache = _elgg_services()->dataCache->entities;
325 5291
		$entity = $cache->load($guid);
326 5291
		if (!$entity instanceof ElggEntity) {
327 5284
			return false;
328
		}
329
330
		// Validate accessibility if from cache
331 345
		if (!elgg_get_ignore_access() && !has_access_to_entity($entity)) {
332 1
			return false;
333
		}
334
335 344
		$entity->cache(false);
336
337 344
		return $entity;
338
	}
339
340
	/**
341
	 * Invalidate cache for entity
342
	 *
343
	 * @param int $guid GUID
344
	 * @return void
345
	 */
346 1065
	public function invalidateCache($guid) {
347 1065
		$ia = $this->session->setIgnoreAccess(true);
348 1065
		$ha = access_get_show_hidden_status();
349 1065
		access_show_hidden_entities(true);
350 1065
		$entity = $this->get($guid);
351 1065
		if ($entity) {
352 1065
			$entity->invalidateCache();
353
		}
354 1065
		access_show_hidden_entities($ha);
355 1065
		$this->session->setIgnoreAccess($ia);
356 1065
	}
357
358
	/**
359
	 * Loads and returns an entity object from a guid.
360
	 *
361
	 * @param int    $guid The GUID of the entity
362
	 * @param string $type The type of the entity. If given, even an existing entity with the given GUID
363
	 *                     will not be returned unless its type matches.
364
	 *
365
	 * @return ElggEntity|false The correct Elgg or custom object based upon entity type and subtype
366
	 * @throws ClassException
367
	 * @throws InvalidParameterException
368
	 */
369 5292
	public function get($guid, $type = '') {
370
		// We could also use: if (!(int) $guid) { return false },
371
		// but that evaluates to a false positive for $guid = true.
372
		// This is a bit slower, but more thorough.
373 5292
		if (!is_numeric($guid) || $guid === 0 || $guid === '0') {
374 70
			return false;
375
		}
376
377 5292
		$guid = (int) $guid;
378
379 5292
		$entity = $this->getFromCache($guid);
380 5292
		if ($entity && (!$type || elgg_instanceof($entity, $type))) {
381 802
			return $entity;
382
		}
383
384 5284
		$row = $this->getRow($guid);
385 5284
		if (!$row) {
386 42
			return false;
387
		}
388
389 5284
		if ($type && $row->type != $type) {
390 2
			return false;
391
		}
392
393 5284
		$entity = $row;
394
395 5284
		if ($entity instanceof \stdClass) {
396 5284
			$entity = $this->rowToElggStar($entity);
397
		}
398
399 5284
		$entity->cache();
400
401 5284
		return $entity;
402
	}
403
404
	/**
405
	 * Does an entity exist?
406
	 *
407
	 * This function checks for the existence of an entity independent of access
408
	 * permissions. It is useful for situations when a user cannot access an entity
409
	 * and it must be determined whether entity has been deleted or the access level
410
	 * has changed.
411
	 *
412
	 * @param int $guid The GUID of the entity
413
	 *
414
	 * @return bool
415
	 */
416 150
	public function exists($guid) {
417
418
		// need to ignore access and show hidden entities to check existence
419 150
		$ia = $this->session->setIgnoreAccess(true);
420 150
		$show_hidden = access_show_hidden_entities(true);
421
422 150
		$result = $this->getRow($guid);
423
424 150
		$this->session->setIgnoreAccess($ia);
425 150
		access_show_hidden_entities($show_hidden);
426
427 150
		return !empty($result);
428
	}
429
430
	/**
431
	 * Enable an entity.
432
	 *
433
	 * @param int  $guid      GUID of entity to enable
434
	 * @param bool $recursive Recursively enable all entities disabled with the entity?
435
	 *
436
	 * @return bool
437
	 */
438
	public function enable($guid, $recursive = true) {
439
440
		// Override access only visible entities
441
		$old_access_status = access_get_show_hidden_status();
442
		access_show_hidden_entities(true);
443
444
		$result = false;
445
		$entity = get_entity($guid);
446
		if ($entity) {
447
			$result = $entity->enable($recursive);
448
		}
449
450
		access_show_hidden_entities($old_access_status);
451
452
		return $result;
453
	}
454
455
	/**
456
	 * Returns an array of entities with optional filtering.
457
	 *
458
	 * Entities are the basic unit of storage in Elgg.  This function
459
	 * provides the simplest way to get an array of entities.  There
460
	 * are many options available that can be passed to filter
461
	 * what sorts of entities are returned.
462
	 *
463
	 * @param QueryBuilder $query   Query
464
	 * @param array        $options Options
465
	 *
466
	 * @return ElggEntity[]
467
	 * @throws DatabaseException
468
	 */
469 1171
	public function fetch(QueryBuilder $query, array $options = []) {
470 1171
		$results = $this->db->getData($query, $options['callback']);
471
472 1171
		if (empty($results)) {
473 889
			return [];
474
		}
475
476 512
		$preload = array_filter($results, function ($e) {
477 512
			return $e instanceof ElggEntity;
478 512
		});
479
		/* @var $preload ElggEntity[] */
480
481 512
		$this->metadata_cache->populateFromEntities($preload);
0 ignored issues
show
$preload of type ElggEntity[] is incompatible with the type integer[] expected by parameter $guids of Elgg\Cache\MetadataCache::populateFromEntities(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

481
		$this->metadata_cache->populateFromEntities(/** @scrutinizer ignore-type */ $preload);
Loading history...
482
483 512
		$props_to_preload = [];
484 512
		if (elgg_extract('preload_owners', $options, false)) {
485 1
			$props_to_preload[] = 'owner_guid';
486
		}
487 512
		if (elgg_extract('preload_containers', $options, false)) {
488
			$props_to_preload[] = 'container_guid';
489
		}
490
491 512
		if ($props_to_preload) {
492 1
			_elgg_services()->entityPreloader->preload($preload, $props_to_preload);
493
		}
494
495 512
		return $results;
496
	}
497
498
	/**
499
	 * Returns a list of months in which entities were updated or created.
500
	 *
501
	 * @tip     Use this to generate a list of archives by month for when entities were added or updated.
502
	 *
503
	 * @warning Months are returned in the form YYYYMM.
504
	 *
505
	 * @param string $type           The type of entity
506
	 * @param string $subtype        The subtype of entity
507
	 * @param int    $container_guid The container GUID that the entities belong to
508
	 * @param string $order_by       Order_by SQL order by clause
509
	 *
510
	 * @return array|false Either an array months as YYYYMM, or false on failure
511
	 */
512
	public function getDates($type = '', $subtype = '', $container_guid = 0, $order_by = 'time_created') {
513
514
		$options = [
515
			'types' => $type,
516
			'subtypes' => $subtype,
517
			'container_guids' => $container_guid,
518
			'callback' => false,
519
			'order_by' => [
520
				new OrderByClause($order_by),
521
			],
522
		];
523
524
		$options = new QueryOptions($options);
525
526
		$qb = Select::fromTable('entities');
527
		$qb->select("DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth");
528
		$qb->addClause(EntityWhereClause::factory($options));
529
530
		$results = _elgg_services()->db->getData($qb);
531
		if (empty($results)) {
532
			return false;
533
		}
534
535
		return array_map(function ($e) {
536
			return $e->yearmonth;
537
		}, $results);
538
	}
539
540
	/**
541
	 * Update the last_action column in the entities table for $guid.
542
	 *
543
	 * @warning This is different to time_updated.  Time_updated is automatically set,
544
	 * while last_action is only set when explicitly called.
545
	 *
546
	 * @param ElggEntity $entity Entity annotation|relationship action carried out on
547
	 * @param int        $posted Timestamp of last action
548
	 *
549
	 * @return int
550
	 * @access  private
551
	 */
552 122
	public function updateLastAction(ElggEntity $entity, $posted = null) {
553
554 122
		if (!$posted) {
0 ignored issues
show
Bug Best Practice introduced by Evan Winslow
The expression $posted of type null|integer is loosely compared to false; this is ambiguous if the integer can be 0. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
555 2
			$posted = $this->getCurrentTime()->getTimestamp();
556
		}
557
558
		$query = "
559 122
			UPDATE {$this->db->prefix}entities
560
			SET last_action = :last_action
561
			WHERE guid = :guid
562
		";
563
564
		$params = [
565 122
			':last_action' => (int) $posted,
566 122
			':guid' => (int) $entity->guid,
567
		];
568
569 122
		$this->db->updateData($query, true, $params);
570
571 122
		return (int) $posted;
572
	}
573
574
	/**
575
	 * Get a user by GUID even if the entity is hidden or disabled
576
	 *
577
	 * @param int $guid User GUID. Default is logged in user
578
	 *
579
	 * @return ElggUser|false
580
	 * @throws ClassException
581
	 * @throws InvalidParameterException
582
	 * @access private
583
	 */
584 1228
	public function getUserForPermissionsCheck($guid = 0) {
585 1228
		if (!$guid) {
586 1219
			return $this->session->getLoggedInUser();
587
		}
588
589
		// need to ignore access and show hidden entities for potential hidden/disabled users
590 315
		$ia = $this->session->setIgnoreAccess(true);
591 315
		$show_hidden = access_show_hidden_entities(true);
592
593 315
		$user = $this->get($guid, 'user');
594 315
		if ($user) {
595 308
			$this->metadata_cache->populateFromEntities([$user->guid]);
596
		}
597
598 315
		$this->session->setIgnoreAccess($ia);
599 315
		access_show_hidden_entities($show_hidden);
600
601 315
		if (!$user) {
602
			// requested to check access for a specific user_guid, but there is no user entity, so the caller
603
			// should cancel the check and return false
604 7
			$message = $this->translator->translate('UserFetchFailureException', [$guid]);
605
			// $this->logger->warn($message);
606
607 7
			throw new UserFetchFailureException($message);
608
		}
609
610 308
		return $user;
611
	}
612
613
	/**
614
	 * Disables all entities owned and contained by a user (or another entity)
615
	 *
616
	 * @param ElggEntity $entity Owner/container entity
617
	 *
618
	 * @return bool
619
	 * @throws DatabaseException
620
	 */
621 1
	public function disableEntities(ElggEntity $entity) {
622 1
		if (!$entity->canEdit()) {
623
			return false;
624
		}
625
626 1
		if (!$this->events->trigger('disable', $entity->type, $entity)) {
627
			return false;
628
		}
629
630 1
		$qb = Update::table('entities');
631 1
		$qb->set('enabled', $qb->param('no', ELGG_VALUE_STRING))
632 1
			->where($qb->compare('owner_guid', '=', $entity->guid, ELGG_VALUE_INTEGER))
633 1
			->orWhere($qb->compare('container_guid', '=', $entity->guid, ELGG_VALUE_INTEGER));
634
635 1
		$this->db->updateData($qb, true);
636
637 1
		$entity->invalidateCache();
638
639 1
		return true;
640
	}
641
642
	/**
643
	 * Delete entity and all of its properties
644
	 *
645
	 * @param ElggEntity $entity    Entity
646
	 * @param bool       $recursive Delete all owned and contained entities
647
	 *
648
	 * @return bool
649
	 * @throws DatabaseException
650
	 */
651 215
	public function delete(\ElggEntity $entity, $recursive = true) {
652 215
		$guid = $entity->guid;
653 215
		if (!$guid) {
654 2
			return false;
655
		}
656
657 214
		if (!_elgg_services()->hooks->getEvents()->triggerBefore('delete', $entity->type, $entity)) {
0 ignored issues
show
$entity of type ElggEntity is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerBefore(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

657
		if (!_elgg_services()->hooks->getEvents()->triggerBefore('delete', $entity->type, /** @scrutinizer ignore-type */ $entity)) {
Loading history...
658
			return false;
659
		}
660
661
		// now trigger an event to let others know this entity is about to be deleted
662
		// so they can prevent it or take their own actions
663 214
		if (!_elgg_services()->hooks->getEvents()->triggerDeprecated('delete', $entity->type, $entity)) {
0 ignored issues
show
$entity of type ElggEntity is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerDeprecated(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

663
		if (!_elgg_services()->hooks->getEvents()->triggerDeprecated('delete', $entity->type, /** @scrutinizer ignore-type */ $entity)) {
Loading history...
664
			return false;
665
		}
666
667 214
		if ($entity instanceof ElggUser) {
668
			// ban to prevent using the site during delete
669 70
			$entity->ban();
670
		}
671
672 214
		if ($recursive) {
673 214
			$this->deleteRelatedEntities($entity);
674
		}
675
676 214
		$this->deleteEntityProperties($entity);
677
678 214
		$qb = Delete::fromTable('entities');
679 214
		$qb->where($qb->compare('guid', '=', $guid, ELGG_VALUE_INTEGER));
680
681 214
		$this->db->deleteData($qb);
682
683 214
		_elgg_services()->hooks->getEvents()->triggerAfter('delete', $entity->type, $entity);
0 ignored issues
show
$entity of type ElggEntity is incompatible with the type string expected by parameter $object of Elgg\EventsService::triggerAfter(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

683
		_elgg_services()->hooks->getEvents()->triggerAfter('delete', $entity->type, /** @scrutinizer ignore-type */ $entity);
Loading history...
684
685 214
		return true;
686
	}
687
688
	/**
689
	 * Deletes entities owned or contained by the entity being deletes
690
	 *
691
	 * @param ElggEntity $entity Entity
692
	 *
693
	 * @return void
694
	 * @throws DatabaseException
695
	 */
696 214
	protected function deleteRelatedEntities(ElggEntity $entity) {
697
		// Temporarily overriding access controls
698 214
		$entity_disable_override = access_get_show_hidden_status();
699 214
		access_show_hidden_entities(true);
700 214
		$ia = elgg_set_ignore_access(true);
701
702
		$options = [
703 214
			'wheres' => function (QueryBuilder $qb) use ($entity) {
704 214
				$ors = $qb->merge([
705 214
					$qb->compare('e.owner_guid', '=', $entity->guid, ELGG_VALUE_INTEGER),
706 214
					$qb->compare('e.container_guid', '=', $entity->guid, ELGG_VALUE_INTEGER),
707
				]);
708
709 214
				return $qb->merge([
710 214
					$ors,
711 214
					$qb->compare('e.guid', 'neq', $entity->guid, ELGG_VALUE_INTEGER),
712
				]);
713 214
			},
714
			'limit' => false,
715
		];
716
717 214
		$batch = new ElggBatch('elgg_get_entities', $options);
718 214
		$batch->setIncrementOffset(false);
719
720
		/* @var $e \ElggEntity */
721 214
		foreach ($batch as $e) {
722 7
			$this->delete($e, true);
723
		}
724
725 214
		access_show_hidden_entities($entity_disable_override);
726 214
		elgg_set_ignore_access($ia);
727 214
	}
728
729
	/**
730
	 * Clear data from secondary tables
731
	 *
732
	 * @param ElggEntity $entity Entity
733
	 *
734
	 * @return void
735
	 */
736 214
	protected function deleteEntityProperties(ElggEntity $entity) {
737
738 214
		$guid = $entity->guid;
739
740 214
		$entity_disable_override = access_get_show_hidden_status();
741 214
		access_show_hidden_entities(true);
742 214
		$ia = elgg_set_ignore_access(true);
743
744 214
		elgg_delete_river(['subject_guid' => $guid, 'limit' => false]);
745 214
		elgg_delete_river(['object_guid' => $guid, 'limit' => false]);
746 214
		elgg_delete_river(['target_guid' => $guid, 'limit' => false]);
747
748 214
		remove_all_private_settings($guid);
749 214
		$entity->deleteOwnedAccessCollections();
750 214
		$entity->deleteAccessCollectionMemberships();
751 214
		$entity->deleteRelationships();
752 214
		$entity->deleteOwnedAnnotations();
753 214
		$entity->deleteAnnotations();
754 214
		$entity->deleteMetadata();
755
756 214
		access_show_hidden_entities($entity_disable_override);
757 214
		elgg_set_ignore_access($ia);
758
759 214
		$dir = new \Elgg\EntityDirLocator($guid);
760 214
		$file_path = _elgg_config()->dataroot . $dir;
761 214
		delete_directory($file_path);
762
763 214
	}
764
}
765