Elgg  Version 6.2
ElggEntity.php
Go to the documentation of this file.
1 <?php
2 
6 use Elgg\Exceptions\DomainException as ElggDomainException;
7 use Elgg\Exceptions\InvalidArgumentException as ElggInvalidArgumentException;
8 use Elgg\Traits\Entity\AccessCollections;
10 use Elgg\Traits\Entity\Icons;
12 use Elgg\Traits\Entity\Relationships;
13 use Elgg\Traits\Entity\Subscriptions;
14 
52 abstract class ElggEntity extends \ElggData {
53 
54  use AccessCollections;
55  use Annotations;
56  use Icons;
57  use Metadata;
58  use Relationships;
59  use Subscriptions;
60 
61  public const PRIMARY_ATTR_NAMES = [
62  'guid',
63  'type',
64  'subtype',
65  'owner_guid',
66  'container_guid',
67  'access_id',
68  'time_created',
69  'time_updated',
70  'last_action',
71  'enabled',
72  'deleted',
73  'time_deleted',
74  ];
75 
79  protected const INTEGER_ATTR_NAMES = [
80  'guid',
81  'owner_guid',
82  'container_guid',
83  'access_id',
84  'time_created',
85  'time_updated',
86  'last_action',
87  'time_deleted',
88  ];
89 
95  protected $volatile = [];
96 
101  protected $orig_attributes = [];
102 
106  protected $_is_cacheable = true;
107 
122  public function __construct(?\stdClass $row = null) {
123  $this->initializeAttributes();
124 
125  if (!empty($row) && !$this->load($row)) {
126  throw new IOException('Failed to load new ' . get_class() . " for GUID: {$row->guid}");
127  }
128  }
129 
137  protected function initializeAttributes() {
138  parent::initializeAttributes();
139 
140  $this->attributes['guid'] = null;
141  $this->attributes['type'] = null;
142  $this->attributes['subtype'] = null;
143 
144  $this->attributes['owner_guid'] = _elgg_services()->session_manager->getLoggedInUserGuid();
145  $this->attributes['container_guid'] = _elgg_services()->session_manager->getLoggedInUserGuid();
146 
147  $this->attributes['access_id'] = ACCESS_PRIVATE;
148  $this->attributes['time_updated'] = null;
149  $this->attributes['last_action'] = null;
150  $this->attributes['enabled'] = 'yes';
151  $this->attributes['deleted'] = 'no';
152  $this->attributes['time_deleted'] = null;
153  }
154 
165  public function __clone() {
166  $orig_entity = get_entity($this->guid);
167  if (!$orig_entity) {
168  _elgg_services()->logger->error("Failed to clone entity with GUID $this->guid");
169  return;
170  }
171 
172  $metadata_array = elgg_get_metadata([
173  'guid' => $this->guid,
174  'limit' => false,
175  ]);
176 
177  $this->attributes['guid'] = null;
178  $this->attributes['time_created'] = null;
179  $this->attributes['time_updated'] = null;
180  $this->attributes['last_action'] = null;
181 
182  $this->attributes['subtype'] = $orig_entity->getSubtype();
183 
184  // copy metadata over to new entity - slightly convoluted due to
185  // handling of metadata arrays
186  if (is_array($metadata_array)) {
187  // create list of metadata names
188  $metadata_names = [];
189  foreach ($metadata_array as $metadata) {
190  $metadata_names[] = $metadata->name;
191  }
192 
193  // arrays are stored with multiple entries per name
194  $metadata_names = array_unique($metadata_names);
195 
196  // move the metadata over
197  foreach ($metadata_names as $name) {
198  $this->__set($name, $orig_entity->$name);
199  }
200  }
201  }
202 
218  public function __set($name, $value) {
219  if ($this->$name === $value) {
220  // quick return if value is not changing
221  return;
222  }
223 
224  if (array_key_exists($name, $this->attributes)) {
225  // if an attribute is 1 (integer) and it's set to "1" (string), don't consider that a change.
226  if (is_int($this->attributes[$name])
227  && is_string($value)
228  && ((string) $this->attributes[$name] === $value)) {
229  return;
230  }
231 
232  // keep original values
233  if ($this->guid && !array_key_exists($name, $this->orig_attributes)) {
234  $this->orig_attributes[$name] = $this->attributes[$name];
235  }
236 
237  // Certain properties should not be manually changed!
238  switch ($name) {
239  case 'guid':
240  case 'last_action':
241  case 'time_deleted':
242  case 'time_updated':
243  case 'type':
244  return;
245  case 'subtype':
246  throw new ElggInvalidArgumentException(elgg_echo('ElggEntity:Error:SetSubtype', ['setSubtype()']));
247  case 'enabled':
248  throw new ElggInvalidArgumentException(elgg_echo('ElggEntity:Error:SetEnabled', ['enable() / disable()']));
249  case 'deleted':
250  throw new ElggInvalidArgumentException(elgg_echo('ElggEntity:Error:SetDeleted', ['delete() / restore()']));
251  case 'access_id':
252  case 'owner_guid':
253  case 'container_guid':
254  if ($value !== null) {
255  $this->attributes[$name] = (int) $value;
256  } else {
257  $this->attributes[$name] = null;
258  }
259  break;
260  default:
261  $this->attributes[$name] = $value;
262  break;
263  }
264 
265  return;
266  }
267 
268  $this->setMetadata($name, $value);
269  }
270 
276  public function getOriginalAttributes(): array {
277  return $this->orig_attributes;
278  }
279 
293  public function __get($name) {
294  if (array_key_exists($name, $this->attributes)) {
295  return $this->attributes[$name];
296  }
297 
298  return $this->getMetadata($name);
299  }
300 
306  public function getDisplayName(): string {
307  return (string) $this->name;
308  }
309 
317  public function setDisplayName(string $display_name): void {
318  $this->name = $display_name;
319  }
320 
328  public function getVolatileData(string $name) {
329  return array_key_exists($name, $this->volatile) ? $this->volatile[$name] : null;
330  }
331 
340  public function setVolatileData(string $name, $value): void {
341  $this->volatile[$name] = $value;
342  }
343 
349  public function removeAllRelatedRiverItems(): void {
350  elgg_delete_river(['subject_guid' => $this->guid, 'limit' => false]);
351  elgg_delete_river(['object_guid' => $this->guid, 'limit' => false]);
352  elgg_delete_river(['target_guid' => $this->guid, 'limit' => false]);
353  }
354 
361  public function countComments(): int {
362  if (!$this->hasCapability('commentable')) {
363  return 0;
364  }
365 
366  $params = ['entity' => $this];
367  $num = _elgg_services()->events->triggerResults('comments:count', $this->getType(), $params);
368 
369  if (is_int($num)) {
370  return $num;
371  }
372 
373  return \Elgg\Comments\DataService::instance()->getCommentsCount($this);
374  }
375 
384  public function hasAccess(int $user_guid = 0): bool {
385  return _elgg_services()->accessCollections->hasAccessToEntity($this, $user_guid);
386  }
387 
397  public function canEdit(int $user_guid = 0): bool {
398  return _elgg_services()->userCapabilities->canEdit($this, $user_guid);
399  }
400 
411  public function canDelete(int $user_guid = 0): bool {
412  return _elgg_services()->userCapabilities->canDelete($this, $user_guid);
413  }
414 
425  public function canWriteToContainer(int $user_guid = 0, string $type = '', string $subtype = ''): bool {
426  if (empty($type) || empty($subtype)) {
427  throw new ElggInvalidArgumentException(__METHOD__ . ' requires $type and $subtype to be set');
428  }
429 
430  return _elgg_services()->userCapabilities->canWriteToContainer($this, $type, $subtype, $user_guid);
431  }
432 
442  public function canComment(int $user_guid = 0): bool {
443  return _elgg_services()->userCapabilities->canComment($this, $user_guid);
444  }
445 
460  public function canAnnotate(int $user_guid = 0, string $annotation_name = ''): bool {
461  return _elgg_services()->userCapabilities->canAnnotate($this, $user_guid, $annotation_name);
462  }
463 
469  public function getGUID(): ?int {
470  return $this->guid;
471  }
472 
478  public function getType(): string {
479  return (string) $this->attributes['type'];
480  }
481 
490  public function setSubtype(string $subtype): void {
491  // keep original values
492  if ($this->guid && !array_key_exists('subtype', $this->orig_attributes)) {
493  $this->orig_attributes['subtype'] = $this->attributes['subtype'];
494  }
495 
496  $this->attributes['subtype'] = $subtype;
497  }
498 
504  public function getSubtype(): string {
505  return (string) $this->attributes['subtype'];
506  }
507 
513  public function getOwnerGUID(): int {
514  return (int) $this->owner_guid;
515  }
516 
522  public function getOwnerEntity(): ?\ElggEntity {
523  return $this->owner_guid ? get_entity($this->owner_guid) : null;
524  }
525 
533  public function setContainerGUID(int $container_guid): void {
535  }
536 
542  public function getContainerGUID(): int {
543  return (int) $this->container_guid;
544  }
545 
552  public function getContainerEntity(): ?\ElggEntity {
553  return $this->container_guid ? get_entity($this->getContainerGUID()) : null;
554  }
555 
561  public function getTimeUpdated(): int {
562  return (int) $this->time_updated;
563  }
564 
573  public function getURL(): string {
574  $url = elgg_generate_entity_url($this, 'view');
575 
576  $url = _elgg_services()->events->triggerResults('entity:url', "{$this->getType()}:{$this->getSubtype()}", ['entity' => $this], $url);
577  $url = _elgg_services()->events->triggerResults('entity:url', $this->getType(), ['entity' => $this], $url);
578  if (empty($url)) {
579  return '';
580  }
581 
582  return elgg_normalize_url($url);
583  }
584 
588  public function save(): bool {
589  if ($this->guid > 0) {
590  $result = $this->update();
591  } else {
592  $result = $this->create() !== false;
593  }
594 
595  if ($result) {
596  $this->cache();
597  }
598 
599  return $result;
600  }
601 
614  protected function create() {
615 
616  $type = $this->attributes['type'];
617  if (!in_array($type, \Elgg\Config::ENTITY_TYPES)) {
618  throw new ElggDomainException('Entity type must be one of the allowed types: ' . implode(', ', \Elgg\Config::ENTITY_TYPES));
619  }
620 
621  $subtype = $this->attributes['subtype'];
622  if (!$subtype) {
623  throw new ElggInvalidArgumentException('All entities must have a subtype');
624  }
625 
626  $owner_guid = (int) $this->attributes['owner_guid'];
627  $access_id = (int) $this->attributes['access_id'];
628  $now = $this->getCurrentTime()->getTimestamp();
629  $time_created = isset($this->attributes['time_created']) ? (int) $this->attributes['time_created'] : $now;
630  $deleted = $this->attributes['deleted'];
631  $time_deleted = (int) $this->attributes['time_deleted'];
632 
633  $container_guid = $this->attributes['container_guid'];
634  if ($container_guid == 0) {
636  $this->attributes['container_guid'] = $container_guid;
637  }
638 
640 
641  if ($access_id === ACCESS_DEFAULT) {
642  throw new ElggInvalidArgumentException('ACCESS_DEFAULT is not a valid access level. See its documentation in constants.php');
643  }
644 
645  if ($access_id === ACCESS_FRIENDS) {
646  throw new ElggInvalidArgumentException('ACCESS_FRIENDS is not a valid access level. See its documentation in constants.php');
647  }
648 
649  $user_guid = _elgg_services()->session_manager->getLoggedInUserGuid();
650 
651  // If given an owner, verify it can be loaded
652  if (!empty($owner_guid)) {
653  $owner = $this->getOwnerEntity();
654  if (!$owner instanceof \ElggEntity) {
655  $error = "User {$user_guid} tried to create a ({$type}, {$subtype}),";
656  $error .= " but the given owner {$owner_guid} could not be loaded.";
657  throw new ElggInvalidArgumentException($error);
658  }
659 
660  // If different owner than logged in, verify can write to container.
661  if ($user_guid !== $owner_guid && !$owner->canEdit() && !$owner->canWriteToContainer($user_guid, $type, $subtype)) {
662  $error = "User {$user_guid} tried to create a ({$type}, {$subtype}) with owner {$owner_guid},";
663  $error .= " but the user wasn't permitted to write to the owner's container.";
664  throw new ElggInvalidArgumentException($error);
665  }
666  }
667 
668  // If given a container, verify it can be loaded and that the current user can write to it
669  if (!empty($container_guid)) {
670  $container = $this->getContainerEntity();
671  if (!$container instanceof \ElggEntity) {
672  $error = "User {$user_guid} tried to create a ({$type}, {$subtype}),";
673  $error .= " but the given container {$container_guid} could not be loaded.";
674  throw new ElggInvalidArgumentException($error);
675  }
676 
677  if (!$container->canWriteToContainer($user_guid, $type, $subtype)) {
678  $error = "User {$user_guid} tried to create a ({$type}, {$subtype}),";
679  $error .= " but was not permitted to write to container {$container_guid}.";
680  throw new ElggInvalidArgumentException($error);
681  }
682  }
683 
684  if (!_elgg_services()->events->triggerBefore('create', $this->type, $this)) {
685  return false;
686  }
687 
688  // Create primary table row
689  $guid = _elgg_services()->entityTable->insertRow((object) [
690  'type' => $type,
691  'subtype' => $subtype,
692  'owner_guid' => $owner_guid,
693  'container_guid' => $container_guid,
694  'access_id' => $access_id,
695  'time_created' => $time_created,
696  'time_updated' => $now,
697  'last_action' => $now,
698  'deleted' => $deleted,
699  'time_deleted' => $time_deleted
700  ], $this->attributes);
701 
702  if (!$guid) {
703  throw new IOException("Unable to save new object's base entity information!");
704  }
705 
706  $this->attributes['subtype'] = $subtype;
707  $this->attributes['guid'] = (int) $guid;
708  $this->attributes['time_created'] = (int) $time_created;
709  $this->attributes['time_updated'] = (int) $now;
710  $this->attributes['last_action'] = (int) $now;
711  $this->attributes['container_guid'] = (int) $container_guid;
712  $this->attributes['deleted'] = $deleted;
713  $this->attributes['time_deleted'] = (int) $time_deleted;
714 
715  // We are writing this new entity to cache to make sure subsequent calls
716  // to get_entity() load the entity from cache and not from the DB. This
717  // MUST come before the metadata and annotation writes below!
718  $this->cache();
719 
720  // Save any unsaved metadata
721  if (count($this->temp_metadata) > 0) {
722  foreach ($this->temp_metadata as $name => $value) {
723  // temp metadata is always an array, but if there is only one value return just the value
724  $this->setMetadata($name, $value, '', count($value) > 1);
725  }
726 
727  $this->temp_metadata = [];
728  }
729 
730  // Save any unsaved annotations.
731  if (count($this->temp_annotations) > 0) {
732  foreach ($this->temp_annotations as $name => $value) {
733  $this->annotate($name, $value);
734  }
735 
736  $this->temp_annotations = [];
737  }
738 
739  if (isset($container) && !$container instanceof \ElggUser) {
740  // users have their own logic for setting last action
741  $container->updateLastAction();
742  }
743 
744  // for BC reasons this event is still needed (for example for notifications)
745  _elgg_services()->events->trigger('create', $this->type, $this);
746 
747  _elgg_services()->events->triggerAfter('create', $this->type, $this);
748 
749  return $guid;
750  }
751 
759  protected function update(): bool {
760 
761  if (!$this->canEdit()) {
762  return false;
763  }
764 
765  // give old update event a chance to stop the update
766  if (!_elgg_services()->events->trigger('update', $this->type, $this)) {
767  return false;
768  }
769 
770  $this->invalidateCache();
771 
772  // See #6225. We copy these after the update event in case a handler changed one of them.
773  $guid = (int) $this->guid;
774  $owner_guid = (int) $this->owner_guid;
775  $access_id = (int) $this->access_id;
776  $container_guid = (int) $this->container_guid;
777  $time_created = (int) $this->time_created;
778  $time = $this->getCurrentTime()->getTimestamp();
780  $time_deleted = (int) $this->time_deleted;
781 
782  if ($access_id == ACCESS_DEFAULT) {
783  throw new ElggInvalidArgumentException('ACCESS_DEFAULT is not a valid access level. See its documentation in constants.php');
784  }
785 
786  if ($access_id == ACCESS_FRIENDS) {
787  throw new ElggInvalidArgumentException('ACCESS_FRIENDS is not a valid access level. See its documentation in constants.php');
788  }
789 
790  // Update primary table
791  $ret = _elgg_services()->entityTable->updateRow($guid, (object) [
792  'owner_guid' => $owner_guid,
793  'container_guid' => $container_guid,
794  'access_id' => $access_id,
795  'time_created' => $time_created,
796  'time_updated' => $time,
797  'guid' => $guid,
798  'deleted' => $deleted,
799  'time_deleted' => $time_deleted
800  ]);
801  if ($ret === false) {
802  return false;
803  }
804 
805  $this->attributes['time_updated'] = $time;
806 
807  _elgg_services()->events->triggerAfter('update', $this->type, $this);
808 
809  $this->orig_attributes = [];
810 
811  $this->cache();
812 
813  // Handle cases where there was no error BUT no rows were updated!
814  return true;
815  }
816 
824  protected function load(stdClass $row): bool {
825  $attributes = array_merge($this->attributes, (array) $row);
826 
827  if (array_diff(self::PRIMARY_ATTR_NAMES, array_keys($attributes)) !== []) {
828  // Some primary attributes are missing
829  return false;
830  }
831 
832  foreach ($attributes as $name => $value) {
833  if (!in_array($name, self::PRIMARY_ATTR_NAMES)) {
834  $this->setVolatileData("select:{$name}", $value);
835  unset($attributes[$name]);
836  continue;
837  }
838 
839  if (in_array($name, static::INTEGER_ATTR_NAMES)) {
840  $attributes[$name] = (int) $value;
841  }
842  }
843 
844  $this->attributes = $attributes;
845 
846  $this->cache();
847 
848  return true;
849  }
850 
868  public function disable(string $reason = '', bool $recursive = true): bool {
869  if (!$this->guid) {
870  return false;
871  }
872 
873  if (!_elgg_services()->events->trigger('disable', $this->type, $this)) {
874  return false;
875  }
876 
877  if (!$this->canEdit()) {
878  return false;
879  }
880 
881  if ($this instanceof ElggUser && !$this->isBanned()) {
882  // temporarily ban to prevent using the site during disable
883  // not using ban function to bypass events
884  $this->setMetadata('banned', 'yes');
885  $unban_after = true;
886  } else {
887  $unban_after = false;
888  }
889 
890  if (!empty($reason)) {
891  $this->disable_reason = $reason;
892  }
893 
894  $guid = (int) $this->guid;
895 
896  if ($recursive) {
898  $base_options = [
899  'wheres' => [
900  function(QueryBuilder $qb, $main_alias) use ($guid) {
901  return $qb->compare("{$main_alias}.guid", '!=', $guid, ELGG_VALUE_GUID);
902  },
903  ],
904  'limit' => false,
905  'batch' => true,
906  'batch_inc_offset' => false,
907  ];
908 
909  foreach (['owner_guid', 'container_guid'] as $db_column) {
910  $options = $base_options;
911  $options[$db_column] = $guid;
912 
913  $subentities = elgg_get_entities($options);
914  /* @var $subentity \ElggEntity */
915  foreach ($subentities as $subentity) {
916  if (!$subentity->isEnabled()) {
917  continue;
918  }
919 
920  $subentity->addRelationship($guid, 'disabled_with');
921  $subentity->disable($reason, true);
922  }
923  }
924  });
925  }
926 
927  $disabled = _elgg_services()->entityTable->disable($this);
928 
929  if ($unban_after) {
930  $this->setMetadata('banned', 'no');
931  }
932 
933  if ($disabled) {
934  $this->invalidateCache();
935 
936  $this->attributes['enabled'] = 'no';
937  _elgg_services()->events->triggerAfter('disable', $this->type, $this);
938  }
939 
940  return $disabled;
941  }
942 
950  public function enable(bool $recursive = true): bool {
951  if (empty($this->guid)) {
952  return false;
953  }
954 
955  if (!_elgg_services()->events->trigger('enable', $this->type, $this)) {
956  return false;
957  }
958 
959  if (!$this->canEdit()) {
960  return false;
961  }
962 
964  $result = _elgg_services()->entityTable->enable($this);
965 
966  $this->deleteMetadata('disable_reason');
967 
968  if ($recursive) {
969  $disabled_with_it = elgg_get_entities([
970  'relationship' => 'disabled_with',
971  'relationship_guid' => $this->guid,
972  'inverse_relationship' => true,
973  'limit' => false,
974  'batch' => true,
975  'batch_inc_offset' => false,
976  ]);
977 
978  foreach ($disabled_with_it as $e) {
979  $e->enable($recursive);
980  $e->removeRelationship($this->guid, 'disabled_with');
981  }
982  }
983 
984  return $result;
985  });
986 
987  if ($result) {
988  $this->attributes['enabled'] = 'yes';
989  _elgg_services()->events->triggerAfter('enable', $this->type, $this);
990  }
991 
992  return $result;
993  }
994 
1000  public function isEnabled(): bool {
1001  return $this->enabled == 'yes';
1002  }
1003 
1021  public function delete(bool $recursive = true, ?bool $persistent = null): bool {
1022  if (!$this->canDelete()) {
1023  return false;
1024  }
1025 
1026  if (!elgg_get_config('trash_enabled')) {
1027  $persistent = true;
1028  }
1029 
1030  if (!isset($persistent)) {
1031  $persistent = !$this->hasCapability('restorable');
1032  }
1033 
1034  try {
1035  if (empty($this->guid) || $persistent) {
1036  return $this->persistentDelete($recursive);
1037  } else {
1038  return $this->trash($recursive);
1039  }
1040  } catch (DatabaseException $ex) {
1041  elgg_log($ex, \Psr\Log\LogLevel::ERROR);
1042  return false;
1043  }
1044  }
1045 
1054  protected function persistentDelete(bool $recursive = true): bool {
1055  return _elgg_services()->entityTable->delete($this, $recursive);
1056  }
1057 
1066  protected function trash(bool $recursive = true): bool {
1067  $result = _elgg_services()->entityTable->trash($this, $recursive);
1068  if ($result) {
1069  $this->attributes['deleted'] = 'yes';
1070  }
1071 
1072  return $result;
1073  }
1074 
1083  public function restore(bool $recursive = true): bool {
1084  if (!$this->isDeleted()) {
1085  return true;
1086  }
1087 
1088  if (empty($this->guid) || !$this->canEdit()) {
1089  return false;
1090  }
1091 
1092  return _elgg_services()->events->triggerSequence('restore', $this->type, $this, function () use ($recursive) {
1094  if (!_elgg_services()->entityTable->restore($this)) {
1095  return false;
1096  }
1097 
1098  $this->attributes['deleted'] = 'no';
1099  $this->attributes['time_deleted'] = 0;
1100 
1101  $this->removeAllRelationships('deleted_by');
1102  $this->removeAllRelationships('deleted_with');
1103 
1104  if (!$recursive) {
1105  return true;
1106  }
1107 
1108  set_time_limit(0);
1109 
1110  /* @var $deleted_with_it \ElggBatch */
1111  $deleted_with_it = elgg_get_entities([
1112  'relationship' => 'deleted_with',
1113  'relationship_guid' => $this->guid,
1114  'inverse_relationship' => true,
1115  'limit' => false,
1116  'batch' => true,
1117  'batch_inc_offset' => false,
1118  ]);
1119 
1120  /* @var $e \ElggEntity */
1121  foreach ($deleted_with_it as $e) {
1122  if (!$e->restore($recursive)) {
1123  $deleted_with_it->reportFailure();
1124  continue;
1125  }
1126  }
1127 
1128  return true;
1129  });
1130  });
1131  }
1132 
1138  public function isDeleted(): bool {
1139  return $this->deleted === 'yes';
1140  }
1141 
1149  public function toObject(array $params = []) {
1150  $object = $this->prepareObject(new \Elgg\Export\Entity());
1151 
1152  $params['entity'] = $this;
1153 
1154  return _elgg_services()->events->triggerResults('to:object', 'entity', $params, $object);
1155  }
1156 
1164  protected function prepareObject(\Elgg\Export\Entity $object) {
1165  $object->guid = $this->guid;
1166  $object->type = $this->getType();
1167  $object->subtype = $this->getSubtype();
1168  $object->owner_guid = $this->getOwnerGUID();
1169  $object->container_guid = $this->getContainerGUID();
1170  $object->time_created = date('c', $this->getTimeCreated());
1171  $object->time_updated = date('c', $this->getTimeUpdated());
1172  $object->url = $this->getURL();
1173  $object->read_access = (int) $this->access_id;
1174  return $object;
1175  }
1176 
1185  public function setLatLong(float $lat, float $long): void {
1186  $this->{'geo:lat'} = $lat;
1187  $this->{'geo:long'} = $long;
1188  }
1189 
1195  public function getLatitude(): float {
1196  return (float) $this->{'geo:lat'};
1197  }
1198 
1204  public function getLongitude(): float {
1205  return (float) $this->{'geo:long'};
1206  }
1207 
1208  /*
1209  * SYSTEM LOG INTERFACE
1210  */
1211 
1215  public function getSystemLogID(): int {
1216  return (int) $this->getGUID();
1217  }
1218 
1227  public function getObjectFromID(int $id): ?\ElggEntity {
1229  }
1230 
1242  public function updateLastAction(?int $posted = null): int {
1243  $posted = _elgg_services()->entityTable->updateLastAction($this, $posted);
1244 
1245  $this->attributes['last_action'] = $posted;
1246  $this->cache();
1247 
1248  return $posted;
1249  }
1250 
1259  public function updateTimeDeleted(?int $deleted = null): int {
1260  $deleted = _elgg_services()->entityTable->updateTimeDeleted($this, $deleted);
1261 
1262  $this->attributes['time_deleted'] = $deleted;
1263  $this->cache();
1264 
1265  return $deleted;
1266  }
1267 
1274  public function disableCaching(): void {
1275  $this->_is_cacheable = false;
1276  if ($this->guid) {
1277  _elgg_services()->entityCache->delete($this->guid);
1278  }
1279  }
1280 
1287  public function enableCaching(): void {
1288  $this->_is_cacheable = true;
1289  }
1290 
1297  public function isCacheable(): bool {
1298  if (!$this->guid) {
1299  return false;
1300  }
1301 
1302  if (_elgg_services()->session_manager->getIgnoreAccess()) {
1303  return false;
1304  }
1305 
1306  return $this->_is_cacheable;
1307  }
1308 
1315  public function cache(): void {
1316  if (!$this->isCacheable()) {
1317  return;
1318  }
1319 
1320  _elgg_services()->entityCache->save($this->guid, $this);
1321  }
1322 
1329  public function invalidateCache(): void {
1330  if (!$this->guid) {
1331  return;
1332  }
1333 
1334  _elgg_services()->entityCache->delete($this->guid);
1335  _elgg_services()->metadataCache->delete($this->guid);
1336  }
1337 
1346  public function hasCapability(string $capability): bool {
1347  return _elgg_services()->entity_capabilities->hasCapability($this->getType(), $this->getSubtype(), $capability);
1348  }
1349 
1355  public static function getDefaultFields(): array {
1356  return [];
1357  }
1358 
1364  final public function getFields(): array {
1365  return _elgg_services()->fields->get($this->getType(), $this->getSubtype());
1366  }
1367 }
$error
Bad request error.
Definition: 400.php:6
getCurrentTime($modifier='')
Get the (cloned) time.
Definition: TimeUsing.php:25
$site name
Definition: settings.php:15
$guid
Reset an ElggUpgrade.
Definition: reset.php:6
$deleted
Definition: delete.php:25
if(! $user||! $user->canDelete()) $name
Definition: delete.php:22
$id
Generic annotation delete action.
Definition: delete.php:6
$owner
Definition: upload.php:7
$comment access_id
Definition: save.php:55
if($entity instanceof \ElggComment) $comment container_guid
Definition: save.php:54
if(! $new_container instanceof \ElggEntity) if(! $new_container->canWriteToContainer(0, $entity->type, $entity->subtype)) $display_name
$subtype
Definition: delete.php:22
$type
Definition: delete.php:21
$container
Definition: delete.php:23
$params
Saves global plugin settings.
Definition: save.php:13
return[ 'admin/delete_admin_notices'=>['access'=> 'admin'], 'admin/menu/save'=>['access'=> 'admin'], 'admin/plugins/activate'=>['access'=> 'admin'], 'admin/plugins/activate_all'=>['access'=> 'admin'], 'admin/plugins/deactivate'=>['access'=> 'admin'], 'admin/plugins/deactivate_all'=>['access'=> 'admin'], 'admin/plugins/set_priority'=>['access'=> 'admin'], 'admin/security/security_txt'=>['access'=> 'admin'], 'admin/security/settings'=>['access'=> 'admin'], 'admin/security/regenerate_site_secret'=>['access'=> 'admin'], 'admin/site/cache/invalidate'=>['access'=> 'admin'], 'admin/site/flush_cache'=>['access'=> 'admin'], 'admin/site/icons'=>['access'=> 'admin'], 'admin/site/set_maintenance_mode'=>['access'=> 'admin'], 'admin/site/set_robots'=>['access'=> 'admin'], 'admin/site/theme'=>['access'=> 'admin'], 'admin/site/unlock_upgrade'=>['access'=> 'admin'], 'admin/site/settings'=>['access'=> 'admin'], 'admin/upgrade'=>['access'=> 'admin'], 'admin/upgrade/reset'=>['access'=> 'admin'], 'admin/user/ban'=>['access'=> 'admin'], 'admin/user/bulk/ban'=>['access'=> 'admin'], 'admin/user/bulk/delete'=>['access'=> 'admin'], 'admin/user/bulk/unban'=>['access'=> 'admin'], 'admin/user/bulk/validate'=>['access'=> 'admin'], 'admin/user/change_email'=>['access'=> 'admin'], 'admin/user/delete'=>['access'=> 'admin'], 'admin/user/login_as'=>['access'=> 'admin'], 'admin/user/logout_as'=>[], 'admin/user/makeadmin'=>['access'=> 'admin'], 'admin/user/resetpassword'=>['access'=> 'admin'], 'admin/user/removeadmin'=>['access'=> 'admin'], 'admin/user/unban'=>['access'=> 'admin'], 'admin/user/validate'=>['access'=> 'admin'], 'annotation/delete'=>[], 'avatar/upload'=>[], 'comment/save'=>[], 'diagnostics/download'=>['access'=> 'admin'], 'entity/chooserestoredestination'=>[], 'entity/delete'=>[], 'entity/mute'=>[], 'entity/restore'=>[], 'entity/subscribe'=>[], 'entity/trash'=>[], 'entity/unmute'=>[], 'entity/unsubscribe'=>[], 'login'=>['access'=> 'logged_out'], 'logout'=>[], 'notifications/mute'=>['access'=> 'public'], 'plugins/settings/remove'=>['access'=> 'admin'], 'plugins/settings/save'=>['access'=> 'admin'], 'plugins/usersettings/save'=>[], 'register'=>['access'=> 'logged_out', 'middleware'=>[\Elgg\Router\Middleware\RegistrationAllowedGatekeeper::class,],], 'river/delete'=>[], 'settings/notifications'=>[], 'settings/notifications/subscriptions'=>[], 'user/changepassword'=>['access'=> 'public'], 'user/requestnewpassword'=>['access'=> 'public'], 'useradd'=>['access'=> 'admin'], 'usersettings/save'=>[], 'widgets/add'=>[], 'widgets/delete'=>[], 'widgets/move'=>[], 'widgets/save'=>[],]
Definition: actions.php:73
$attributes
Elgg AJAX loader.
Definition: ajax_loader.php:10
if(! $annotation instanceof ElggAnnotation) $time
Definition: time.php:20
A generic class that contains shared code among \ElggExtender, \ElggEntity, and \ElggRelationship.
Definition: ElggData.php:12
initializeAttributes()
Initialize the attributes array.
Definition: ElggEntity.php:137
getVolatileData(string $name)
Get a piece of volatile (non-persisted) data on this entity.
Definition: ElggEntity.php:328
getType()
Returns the entity type.
Definition: ElggEntity.php:478
restore(bool $recursive=true)
Restore the entity.
__set($name, $value)
Set an attribute or metadata value for this entity.
Definition: ElggEntity.php:218
disable(string $reason='', bool $recursive=true)
Disable this entity.
Definition: ElggEntity.php:868
getObjectFromID(int $id)
For a given ID, return the object associated with it.
setContainerGUID(int $container_guid)
Set the container for this object.
Definition: ElggEntity.php:533
trash(bool $recursive=true)
Move the entity to the trash.
toObject(array $params=[])
Export an entity.
getSystemLogID()
{Return an identification for the object for storage in the system log.This id must be an integer....
canWriteToContainer(int $user_guid=0, string $type='', string $subtype='')
Can a user add an entity to this container.
Definition: ElggEntity.php:425
setVolatileData(string $name, $value)
Set a piece of volatile (non-persisted) data on this entity.
Definition: ElggEntity.php:340
canEdit(int $user_guid=0)
Can a user edit this entity?
Definition: ElggEntity.php:397
getFields()
Helper function to easily retrieve form fields for this entity.
updateTimeDeleted(?int $deleted=null)
Update the time_deleted column in the entities table.
getSubtype()
Get the entity subtype.
Definition: ElggEntity.php:504
static getDefaultFields()
Returns a default set of fields to be used for forms related to this entity.
getOriginalAttributes()
Get the original values of attribute(s) that have been modified since the entity was persisted.
Definition: ElggEntity.php:276
getContainerGUID()
Gets the container GUID for this entity.
Definition: ElggEntity.php:542
__get($name)
Get an attribute or metadata value.
Definition: ElggEntity.php:293
hasAccess(int $user_guid=0)
Check if the given user has access to this entity.
Definition: ElggEntity.php:384
disableCaching()
Disable runtime caching for entity.
enableCaching()
Enable runtime caching for entity.
invalidateCache()
Invalidate cache for entity.
canComment(int $user_guid=0)
Can a user comment on an entity?
Definition: ElggEntity.php:442
update()
Update the entity in the database.
Definition: ElggEntity.php:759
getDisplayName()
Get the entity's display name.
Definition: ElggEntity.php:306
getOwnerEntity()
Gets the \ElggEntity that owns this entity.
Definition: ElggEntity.php:522
create()
Create a new entry in the entities table.
Definition: ElggEntity.php:614
removeAllRelatedRiverItems()
Removes all river items related to this entity.
Definition: ElggEntity.php:349
getContainerEntity()
Get the container entity for this object.
Definition: ElggEntity.php:552
save()
Save this data to the appropriate database table.bool
Definition: ElggEntity.php:588
getURL()
Gets the URL for this entity.
Definition: ElggEntity.php:573
getLongitude()
Return the entity's longitude.
const INTEGER_ATTR_NAMES
Definition: ElggEntity.php:79
__construct(?\stdClass $row=null)
Create a new entity.
Definition: ElggEntity.php:122
hasCapability(string $capability)
Checks a specific capability is enabled for the entity type/subtype.
setSubtype(string $subtype)
Set the subtype of the entity.
Definition: ElggEntity.php:490
getTimeUpdated()
Returns the UNIX epoch time that this entity was last updated.
Definition: ElggEntity.php:561
isCacheable()
Is entity cacheable in the runtime cache.
isDeleted()
Is the entity marked as deleted.
isEnabled()
Is this entity enabled?
canDelete(int $user_guid=0)
Can a user delete this entity?
Definition: ElggEntity.php:411
persistentDelete(bool $recursive=true)
Permanently delete the entity from the database.
load(stdClass $row)
Loads attributes from the entities table into the object.
Definition: ElggEntity.php:824
getGUID()
Returns the guid.
Definition: ElggEntity.php:469
setDisplayName(string $display_name)
Sets the title or name of this entity.
Definition: ElggEntity.php:317
enable(bool $recursive=true)
Enable the entity.
Definition: ElggEntity.php:950
prepareObject(\Elgg\Export\Entity $object)
Prepare an object copy for toObject()
const PRIMARY_ATTR_NAMES
Definition: ElggEntity.php:61
canAnnotate(int $user_guid=0, string $annotation_name='')
Can a user annotate an entity?
Definition: ElggEntity.php:460
cache()
Cache the entity in a session cache.
__clone()
Clone an entity.
Definition: ElggEntity.php:165
getOwnerGUID()
Get the guid of the entity's owner.
Definition: ElggEntity.php:513
getLatitude()
Return the entity's latitude.
countComments()
Count the number of comments attached to this entity.
Definition: ElggEntity.php:361
setLatLong(float $lat, float $long)
Set latitude and longitude metadata tags for a given entity.
updateLastAction(?int $posted=null)
Update the last_action column in the entities table.
Database abstraction query builder.
A generic parent class for database exceptions.
Exception thrown if a value does not adhere to a defined valid data domain.
An IO Exception, throw when an IO Exception occurs.
Definition: IOException.php:12
Exception thrown if an argument is not of the expected type.
$owner_guid
$container_guid
elgg_get_config(string $name, $default=null)
Get an Elgg configuration value.
const ELGG_IGNORE_ACCESS
elgg_call() flags
Definition: constants.php:121
const ELGG_HIDE_DISABLED_ENTITIES
Definition: constants.php:124
const ELGG_SHOW_DISABLED_ENTITIES
Definition: constants.php:123
const ELGG_VALUE_GUID
Definition: constants.php:113
const ACCESS_PRIVATE
Definition: constants.php:10
const ACCESS_FRIENDS
Definition: constants.php:13
const ELGG_SHOW_DELETED_ENTITIES
Definition: constants.php:127
const ACCESS_DEFAULT
Controls access levels on \ElggEntity entities, metadata, and annotations.
Definition: constants.php:9
if($who_can_change_language==='nobody') elseif($who_can_change_language==='admin_only' &&!elgg_is_admin_logged_in()) $options
Definition: language.php:20
if(! $user instanceof \ElggUser) $time_created
Definition: online.php:13
foreach($plugin_guids as $guid) if(empty($deactivated_plugins)) $url
Definition: deactivate.php:39
if($email instanceof \Elgg\Email) $object
Definition: body.php:24
$posted
Definition: sidebar.php:21
elgg_log($message, $level=\Psr\Log\LogLevel::NOTICE)
Log a message.
Definition: elgglib.php:88
_elgg_services()
Get the global service provider.
Definition: elgglib.php:353
elgg_call(int $flags, Closure $closure)
Calls a callable autowiring the arguments using public DI services and applying logic based on flags.
Definition: elgglib.php:306
elgg_get_metadata(array $options=[])
Fetch metadata or perform a calculation on them.
Definition: metadata.php:32
get_entity(int $guid)
Loads and returns an entity object from a guid.
Definition: entities.php:70
elgg_get_entities(array $options=[])
Fetches/counts entities or performs a calculation on their properties.
Definition: entities.php:507
$value
Definition: generic.php:51
elgg_echo(string $message_key, array $args=[], string $language='')
Elgg language module Functions to manage language and translations.
Definition: languages.php:17
$user_guid
Definition: login_as.php:10
$persistent
Definition: login_as.php:21
setMetadata(string $name, mixed $value, string $value_type='', bool $multiple=false)
Set metadata on this entity.
Definition: Metadata.php:78
getMetadata(string $name)
Return the value of a piece of metadata.
Definition: Metadata.php:27
annotate($name, $value, $access_id=ACCESS_PRIVATE, $owner_guid=0, $value_type='')
Adds an annotation to an entity.
trait Metadata
Bundle all metadata related functions for an \ElggEntity.
Definition: Metadata.php:10
trait Annotations
Bundle all annotations related functions for an \ElggEntity.
Definition: Annotations.php:10
deleteMetadata(?string $name=null)
Deletes all metadata on this object (metadata.entity_guid = $this->guid).
Definition: Metadata.php:198
elgg_normalize_url(string $url)
Definition: output.php:163
elgg_generate_entity_url(ElggEntity $entity, string $resource='view', ?string $subresource=null, array $parameters=[])
Generate entity URL from a named route.
$qb
Definition: queue.php:12
elgg_delete_river(array $options=[])
Delete river items based on $options.
Definition: river.php:135
if(parse_url(elgg_get_site_url(), PHP_URL_PATH) !=='/') if(file_exists(elgg_get_root_path() . 'robots.txt'))
Set robots.txt.
Definition: robots.php:10
$metadata
Output annotation metadata.
Definition: metadata.php:9
$access_id
Definition: access.php:10