aboutsummaryrefslogtreecommitdiff
path: root/engine/classes/ElggEntity.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/classes/ElggEntity.php')
-rw-r--r--engine/classes/ElggEntity.php807
1 files changed, 623 insertions, 184 deletions
diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php
index 66aca035e..a563f6fad 100644
--- a/engine/classes/ElggEntity.php
+++ b/engine/classes/ElggEntity.php
@@ -23,8 +23,18 @@
* instead of this class.
*
* @package Elgg.Core
- * @subpackage DataMode.Entities
- * @link http://docs.elgg.org/DataModel/ElggEntity
+ * @subpackage DataModel.Entities
+ *
+ * @property string $type object, user, group, or site (read-only after save)
+ * @property string $subtype Further clarifies the nature of the entity (read-only after save)
+ * @property int $guid The unique identifier for this entity (read only)
+ * @property int $owner_guid The GUID of the creator of this entity
+ * @property int $container_guid The GUID of the entity containing this entity
+ * @property int $site_guid The GUID of the website this entity is associated with
+ * @property int $access_id Specifies the visibility level of this entity
+ * @property int $time_created A UNIX timestamp of when the entity was created (read-only, set on first save)
+ * @property int $time_updated A UNIX timestamp of when the entity was last updated (automatically updated on save)
+ * @property-read string $enabled
*/
abstract class ElggEntity extends ElggData implements
Notable, // Calendar interface
@@ -55,24 +65,16 @@ abstract class ElggEntity extends ElggData implements
protected $temp_annotations = array();
/**
- * Volatile data structure for this object, allows for storage of data
- * in-memory that isn't sync'd back to the metadata table.
+ * Holds private settings until entity is saved. Once the entity is saved,
+ * private settings are written immediately to the database.
*/
- protected $volatile = array();
+ protected $temp_private_settings = array();
/**
- * Initialise the attributes array.
- *
- * This is vital to distinguish between metadata and base parameters.
- *
- * @return void
- * @deprecated 1.8 Use initializeAttributes()
+ * Volatile data structure for this object, allows for storage of data
+ * in-memory that isn't sync'd back to the metadata table.
*/
- protected function initialise_attributes() {
- elgg_deprecated_notice('ElggEntity::initialise_attributes() is deprecated by ::initializeAttributes()', 1.8);
-
- $this->initializeAttributes();
- }
+ protected $volatile = array();
/**
* Initialize the attributes array.
@@ -83,20 +85,19 @@ abstract class ElggEntity extends ElggData implements
*/
protected function initializeAttributes() {
parent::initializeAttributes();
-
- initialise_entity_cache();
- $this->attributes['guid'] = "";
- $this->attributes['type'] = "";
- $this->attributes['subtype'] = "";
+ $this->attributes['guid'] = NULL;
+ $this->attributes['type'] = NULL;
+ $this->attributes['subtype'] = NULL;
- $this->attributes['owner_guid'] = get_loggedin_userid();
- $this->attributes['container_guid'] = get_loggedin_userid();
+ $this->attributes['owner_guid'] = elgg_get_logged_in_user_guid();
+ $this->attributes['container_guid'] = elgg_get_logged_in_user_guid();
- $this->attributes['site_guid'] = 0;
+ $this->attributes['site_guid'] = NULL;
$this->attributes['access_id'] = ACCESS_PRIVATE;
- $this->attributes['time_updated'] = "";
- $this->attributes['last_action'] = '';
+ $this->attributes['time_created'] = NULL;
+ $this->attributes['time_updated'] = NULL;
+ $this->attributes['last_action'] = NULL;
$this->attributes['enabled'] = "yes";
// There now follows a bit of a hack
@@ -138,7 +139,10 @@ abstract class ElggEntity extends ElggData implements
return;
}
- $metadata_array = get_metadata_for_entity($this->guid);
+ $metadata_array = elgg_get_metadata(array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ ));
$this->attributes['guid'] = "";
@@ -183,7 +187,7 @@ abstract class ElggEntity extends ElggData implements
*/
public function get($name) {
// See if its in our base attributes
- if (isset($this->attributes[$name])) {
+ if (array_key_exists($name, $this->attributes)) {
return $this->attributes[$name];
}
@@ -197,8 +201,11 @@ abstract class ElggEntity extends ElggData implements
/**
* Sets the value of a property.
*
- * If $name is defined in $this->attributes that value is set, otherwise it will
- * set the appropriate item of metadata.
+ * If $name is defined in $this->attributes that value is set, otherwise it is
+ * saved as metadata.
+ *
+ * @warning Metadata set this way will inherit the entity's owner and access ID. If you want
+ * to set metadata with a different owner, use create_metadata().
*
* @warning It is important that your class populates $this->attributes with keys
* for all base attributes, anything not in their gets set as METADATA.
@@ -219,7 +226,6 @@ abstract class ElggEntity extends ElggData implements
// Certain properties should not be manually changed!
switch ($name) {
case 'guid':
- case 'time_created':
case 'time_updated':
case 'last_action':
return FALSE;
@@ -243,21 +249,53 @@ abstract class ElggEntity extends ElggData implements
* @return mixed The value, or NULL if not found.
*/
public function getMetaData($name) {
- if ((int) ($this->guid) > 0) {
- $md = get_metadata_byname($this->getGUID(), $name);
- } else {
+ $guid = $this->getGUID();
+
+ if (! $guid) {
if (isset($this->temp_metadata[$name])) {
- return $this->temp_metadata[$name];
+ // md is returned as an array only if more than 1 entry
+ if (count($this->temp_metadata[$name]) == 1) {
+ return $this->temp_metadata[$name][0];
+ } else {
+ return $this->temp_metadata[$name];
+ }
+ } else {
+ return null;
}
}
+ // upon first cache miss, just load/cache all the metadata and retry.
+ // if this works, the rest of this function may not be needed!
+ $cache = elgg_get_metadata_cache();
+ if ($cache->isKnown($guid, $name)) {
+ return $cache->load($guid, $name);
+ } else {
+ $cache->populateFromEntities(array($guid));
+ // in case ignore_access was on, we have to check again...
+ if ($cache->isKnown($guid, $name)) {
+ return $cache->load($guid, $name);
+ }
+ }
+
+ $md = elgg_get_metadata(array(
+ 'guid' => $guid,
+ 'metadata_name' => $name,
+ 'limit' => 0,
+ ));
+
+ $value = null;
+
if ($md && !is_array($md)) {
- return $md->value;
+ $value = $md->value;
+ } elseif (count($md) == 1) {
+ $value = $md[0]->value;
} else if ($md && is_array($md)) {
- return metadata_array_to_values($md);
+ $value = metadata_array_to_values($md);
}
- return null;
+ $cache->save($guid, $name, $value);
+
+ return $value;
}
/**
@@ -273,73 +311,136 @@ abstract class ElggEntity extends ElggData implements
if (array_key_exists($name, $this->attributes)) {
$this->attributes[$name] = "";
} else {
- $this->clearMetaData($name);
+ $this->deleteMetadata($name);
}
}
/**
* Set a piece of metadata.
*
- * @tip Plugin authors should use the magic methods.
+ * Plugin authors should use the magic methods or create_metadata().
+ *
+ * @warning The metadata will inherit the parent entity's owner and access ID.
+ * If you want to write metadata with a different owner, use create_metadata().
*
* @access private
*
* @param string $name Name of the metadata
- * @param mixed $value Value of the metadata
+ * @param mixed $value Value of the metadata (doesn't support assoc arrays)
* @param string $value_type Types supported: integer and string. Will auto-identify if not set
* @param bool $multiple Allow multiple values for a single name (doesn't support assoc arrays)
*
* @return bool
*/
- public function setMetaData($name, $value, $value_type = "", $multiple = false) {
+ public function setMetaData($name, $value, $value_type = null, $multiple = false) {
+
+ // normalize value to an array that we will loop over
+ // remove indexes if value already an array.
if (is_array($value)) {
- unset($this->temp_metadata[$name]);
- remove_metadata($this->getGUID(), $name);
- foreach ($value as $v) {
- if ((int) $this->guid > 0) {
- $multiple = true;
- if (!create_metadata($this->getGUID(), $name, $v, $value_type,
- $this->getOwner(), $this->getAccessID(), $multiple)) {
- return false;
- }
- } else {
- if (($multiple) && (isset($this->temp_metadata[$name]))) {
- if (!is_array($this->temp_metadata[$name])) {
- $tmp = $this->temp_metadata[$name];
- $this->temp_metadata[$name] = array();
- $this->temp_metadata[$name][] = $tmp;
- }
-
- $this->temp_metadata[$name][] = $value;
- } else {
- $this->temp_metadata[$name] = $value;
- }
+ $value = array_values($value);
+ } else {
+ $value = array($value);
+ }
+
+ // saved entity. persist md to db.
+ if ($this->guid) {
+ // if overwriting, delete first.
+ if (!$multiple) {
+ $options = array(
+ 'guid' => $this->getGUID(),
+ 'metadata_name' => $name,
+ 'limit' => 0
+ );
+ // @todo in 1.9 make this return false if can't add metadata
+ // https://github.com/elgg/elgg/issues/4520
+ //
+ // need to remove access restrictions right now to delete
+ // because this is the expected behavior
+ $ia = elgg_set_ignore_access(true);
+ if (false === elgg_delete_metadata($options)) {
+ return false;
}
+ elgg_set_ignore_access($ia);
}
- return true;
- } else {
- unset($this->temp_metadata[$name]);
- if ((int) $this->guid > 0) {
- $result = create_metadata($this->getGUID(), $name, $value, $value_type,
- $this->getOwner(), $this->getAccessID(), $multiple);
- return (bool)$result;
- } else {
- if (($multiple) && (isset($this->temp_metadata[$name]))) {
- if (!is_array($this->temp_metadata[$name])) {
- $tmp = $this->temp_metadata[$name];
- $this->temp_metadata[$name] = array();
- $this->temp_metadata[$name][] = $tmp;
- }
-
- $this->temp_metadata[$name][] = $value;
- } else {
- $this->temp_metadata[$name] = $value;
+ // add new md
+ $result = true;
+ foreach ($value as $value_tmp) {
+ // at this point $value should be appended because it was cleared above if needed.
+ $md_id = create_metadata($this->getGUID(), $name, $value_tmp, $value_type,
+ $this->getOwnerGUID(), $this->getAccessId(), true);
+ if (!$md_id) {
+ return false;
}
+ }
- return true;
+ return $result;
+ } else {
+ // unsaved entity. store in temp array
+ // returning single entries instead of an array of 1 element is decided in
+ // getMetaData(), just like pulling from the db.
+ //
+ // if overwrite, delete first
+ if (!$multiple || !isset($this->temp_metadata[$name])) {
+ $this->temp_metadata[$name] = array();
}
+
+ // add new md
+ $this->temp_metadata[$name] = array_merge($this->temp_metadata[$name], $value);
+ return true;
+ }
+ }
+
+ /**
+ * Deletes all metadata on this object (metadata.entity_guid = $this->guid).
+ * If you pass a name, only metadata matching that name will be deleted.
+ *
+ * @warning Calling this with no $name will clear all metadata on the entity.
+ *
+ * @param null|string $name The name of the metadata to remove.
+ * @return bool
+ * @since 1.8
+ */
+ public function deleteMetadata($name = null) {
+
+ if (!$this->guid) {
+ return false;
}
+
+ $options = array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['metadata_name'] = $name;
+ }
+
+ return elgg_delete_metadata($options);
+ }
+
+ /**
+ * Deletes all metadata owned by this object (metadata.owner_guid = $this->guid).
+ * If you pass a name, only metadata matching that name will be deleted.
+ *
+ * @param null|string $name The name of metadata to delete.
+ * @return bool
+ * @since 1.8
+ */
+ public function deleteOwnedMetadata($name = null) {
+ // access is turned off for this because they might
+ // no longer have access to an entity they created metadata on.
+ $ia = elgg_set_ignore_access(true);
+ $options = array(
+ 'metadata_owner_guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['metadata_name'] = $name;
+ }
+
+ $r = elgg_delete_metadata($options);
+ elgg_set_ignore_access($ia);
+ return $r;
}
/**
@@ -348,17 +449,53 @@ abstract class ElggEntity extends ElggData implements
* @warning Calling this with no or empty arguments will clear all metadata on the entity.
*
* @param string $name The name of the metadata to clear
- *
* @return mixed bool
+ * @deprecated 1.8 Use deleteMetadata()
*/
- public function clearMetaData($name = "") {
- if (empty($name)) {
- return clear_metadata($this->getGUID());
- } else {
- return remove_metadata($this->getGUID(), $name);
+ public function clearMetaData($name = '') {
+ elgg_deprecated_notice('ElggEntity->clearMetadata() is deprecated by ->deleteMetadata()', 1.8);
+ return $this->deleteMetadata($name);
+ }
+
+ /**
+ * Disables metadata for this entity, optionally based on name.
+ *
+ * @param string $name An options name of metadata to disable.
+ * @return bool
+ * @since 1.8
+ */
+ public function disableMetadata($name = '') {
+ $options = array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['metadata_name'] = $name;
}
+
+ return elgg_disable_metadata($options);
}
+ /**
+ * Enables metadata for this entity, optionally based on name.
+ *
+ * @warning Before calling this, you must use {@link access_show_hidden_entities()}
+ *
+ * @param string $name An options name of metadata to enable.
+ * @return bool
+ * @since 1.8
+ */
+ public function enableMetadata($name = '') {
+ $options = array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['metadata_name'] = $name;
+ }
+
+ return elgg_enable_metadata($options);
+ }
/**
* Get a piece of volatile (non-persisted) data on this entity.
@@ -379,7 +516,6 @@ abstract class ElggEntity extends ElggData implements
}
}
-
/**
* Set a piece of volatile (non-persisted) data on this entity
*
@@ -396,7 +532,6 @@ abstract class ElggEntity extends ElggData implements
$this->volatile[$name] = $value;
}
-
/**
* Remove all relationships to and from this entity.
*
@@ -405,13 +540,26 @@ abstract class ElggEntity extends ElggData implements
* @see ElggEntity::addRelationship()
* @see ElggEntity::removeRelationship()
*/
- public function clearRelationships() {
+ public function deleteRelationships() {
remove_entity_relationships($this->getGUID());
remove_entity_relationships($this->getGUID(), "", true);
return true;
}
/**
+ * Remove all relationships to and from this entity.
+ *
+ * @return bool
+ * @see ElggEntity::addRelationship()
+ * @see ElggEntity::removeRelationship()
+ * @deprecated 1.8 Use ->deleteRelationship()
+ */
+ public function clearRelationships() {
+ elgg_deprecated_notice('ElggEntity->clearRelationships() is deprecated by ->deleteRelationships()', 1.8);
+ return $this->deleteRelationships();
+ }
+
+ /**
* Add a relationship between this an another entity.
*
* @tip Read the relationship like "$guid is a $relationship of this entity."
@@ -451,10 +599,14 @@ abstract class ElggEntity extends ElggData implements
* @param mixed $value Value of private setting
*
* @return bool
- * @link http://docs.elgg.org/DataModel/Entities/PrivateSettings
*/
function setPrivateSetting($name, $value) {
- return set_private_setting($this->getGUID(), $name, $value);
+ if ((int) $this->guid > 0) {
+ return set_private_setting($this->getGUID(), $name, $value);
+ } else {
+ $this->temp_private_settings[$name] = $value;
+ return true;
+ }
}
/**
@@ -465,7 +617,14 @@ abstract class ElggEntity extends ElggData implements
* @return mixed
*/
function getPrivateSetting($name) {
- return get_private_setting($this->getGUID(), $name);
+ if ((int) ($this->guid) > 0) {
+ return get_private_setting($this->getGUID(), $name);
+ } else {
+ if (isset($this->temp_private_settings[$name])) {
+ return $this->temp_private_settings[$name];
+ }
+ }
+ return null;
}
/**
@@ -480,10 +639,117 @@ abstract class ElggEntity extends ElggData implements
}
/**
+ * Deletes all annotations on this object (annotations.entity_guid = $this->guid).
+ * If you pass a name, only annotations matching that name will be deleted.
+ *
+ * @warning Calling this with no or empty arguments will clear all annotations on the entity.
+ *
+ * @param null|string $name The annotations name to remove.
+ * @return bool
+ * @since 1.8
+ */
+ public function deleteAnnotations($name = null) {
+ $options = array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ return elgg_delete_annotations($options);
+ }
+
+ /**
+ * Deletes all annotations owned by this object (annotations.owner_guid = $this->guid).
+ * If you pass a name, only annotations matching that name will be deleted.
+ *
+ * @param null|string $name The name of annotations to delete.
+ * @return bool
+ * @since 1.8
+ */
+ public function deleteOwnedAnnotations($name = null) {
+ // access is turned off for this because they might
+ // no longer have access to an entity they created annotations on.
+ $ia = elgg_set_ignore_access(true);
+ $options = array(
+ 'annotation_owner_guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ $r = elgg_delete_annotations($options);
+ elgg_set_ignore_access($ia);
+ return $r;
+ }
+
+ /**
+ * Disables annotations for this entity, optionally based on name.
+ *
+ * @param string $name An options name of annotations to disable.
+ * @return bool
+ * @since 1.8
+ */
+ public function disableAnnotations($name = '') {
+ $options = array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ return elgg_disable_annotations($options);
+ }
+
+ /**
+ * Enables annotations for this entity, optionally based on name.
+ *
+ * @warning Before calling this, you must use {@link access_show_hidden_entities()}
+ *
+ * @param string $name An options name of annotations to enable.
+ * @return bool
+ * @since 1.8
+ */
+ public function enableAnnotations($name = '') {
+ $options = array(
+ 'guid' => $this->guid,
+ 'limit' => 0
+ );
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ return elgg_enable_annotations($options);
+ }
+
+ /**
+ * Helper function to return annotation calculation results
+ *
+ * @param string $name The annotation name.
+ * @param string $calculation A valid MySQL function to run its values through
+ * @return mixed
+ */
+ private function getAnnotationCalculation($name, $calculation) {
+ $options = array(
+ 'guid' => $this->getGUID(),
+ 'annotation_name' => $name,
+ 'annotation_calculation' => $calculation
+ );
+
+ return elgg_get_annotations($options);
+ }
+
+ /**
* Adds an annotation to an entity.
*
* @warning By default, annotations are private.
*
+ * @warning Annotating an unsaved entity more than once with the same name
+ * will only save the last annotation.
+ *
* @param string $name Annotation name
* @param mixed $value Annotation value
* @param int $access_id Access ID
@@ -491,8 +757,6 @@ abstract class ElggEntity extends ElggData implements
* @param string $vartype The type of annotation value
*
* @return bool
- *
- * @link http://docs.elgg.org/DataModel/Annotations
*/
function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_id = 0, $vartype = "") {
if ((int) $this->guid > 0) {
@@ -509,15 +773,29 @@ abstract class ElggEntity extends ElggData implements
* @param string $name Annotation name
* @param int $limit Limit
* @param int $offset Offset
- * @param string $order asc or desc
+ * @param string $order Order by time: asc or desc
*
* @return array
*/
function getAnnotations($name, $limit = 50, $offset = 0, $order = "asc") {
if ((int) ($this->guid) > 0) {
- return get_annotations($this->getGUID(), "", "", $name, "", 0, $limit, $offset, $order);
+
+ $options = array(
+ 'guid' => $this->guid,
+ 'annotation_name' => $name,
+ 'limit' => $limit,
+ 'offset' => $offset,
+ );
+
+ if ($order != 'asc') {
+ $options['reverse_order_by'] = true;
+ }
+
+ return elgg_get_annotations($options);
+ } else if (isset($this->temp_annotations[$name])) {
+ return array($this->temp_annotations[$name]);
} else {
- return $this->temp_annotations[$name];
+ return array();
}
}
@@ -528,11 +806,12 @@ abstract class ElggEntity extends ElggData implements
* all annotations on the entity.
*
* @param string $name Annotation name
- *
* @return bool
+ * @deprecated 1.8 Use ->deleteAnnotations()
*/
function clearAnnotations($name = "") {
- return clear_annotations($this->getGUID(), $name);
+ elgg_deprecated_notice('ElggEntity->clearAnnotations() is deprecated by ->deleteAnnotations()', 1.8);
+ return $this->deleteAnnotations($name);
}
/**
@@ -543,7 +822,7 @@ abstract class ElggEntity extends ElggData implements
* @return int
*/
function countAnnotations($name = "") {
- return count_annotations($this->getGUID(), "", "", $name);
+ return $this->getAnnotationCalculation($name, 'count');
}
/**
@@ -554,7 +833,7 @@ abstract class ElggEntity extends ElggData implements
* @return int
*/
function getAnnotationsAvg($name) {
- return get_annotations_avg($this->getGUID(), "", "", $name);
+ return $this->getAnnotationCalculation($name, 'avg');
}
/**
@@ -565,7 +844,7 @@ abstract class ElggEntity extends ElggData implements
* @return int
*/
function getAnnotationsSum($name) {
- return get_annotations_sum($this->getGUID(), "", "", $name);
+ return $this->getAnnotationCalculation($name, 'sum');
}
/**
@@ -576,7 +855,7 @@ abstract class ElggEntity extends ElggData implements
* @return int
*/
function getAnnotationsMin($name) {
- return get_annotations_min($this->getGUID(), "", "", $name);
+ return $this->getAnnotationCalculation($name, 'min');
}
/**
@@ -587,7 +866,24 @@ abstract class ElggEntity extends ElggData implements
* @return int
*/
function getAnnotationsMax($name) {
- return get_annotations_max($this->getGUID(), "", "", $name);
+ return $this->getAnnotationCalculation($name, 'max');
+ }
+
+ /**
+ * Count the number of comments attached to this entity.
+ *
+ * @return int Number of comments
+ * @since 1.8.0
+ */
+ function countComments() {
+ $params = array('entity' => $this);
+ $num = elgg_trigger_plugin_hook('comments:count', $this->getType(), $params);
+
+ if (is_int($num)) {
+ return $num;
+ } else {
+ return $this->getAnnotationCalculation('generic_comment', 'count');
+ }
}
/**
@@ -644,19 +940,19 @@ abstract class ElggEntity extends ElggData implements
* @param ElggMetadata $metadata The piece of metadata to specifically check
* @param int $user_guid The user GUID, optionally (default: logged in user)
*
- * @return true|false
+ * @return bool
*/
function canEditMetadata($metadata = null, $user_guid = 0) {
return can_edit_entity_metadata($this->getGUID(), $user_guid, $metadata);
}
/**
- * Can a user write to this entity
+ * Can a user add an entity to this container
+ *
+ * @param int $user_guid The user.
+ * @param string $type The type of entity we're looking to write
+ * @param string $subtype The subtype of the entity we're looking to write
*
- * @param int $user_guid The user.
- * @param string $type The type of entity we're looking to write
- * @param string $subtype The subtype of the entity we're looking to write
- *
* @return bool
*/
public function canWriteToContainer($user_guid = 0, $type = 'all', $subtype = 'all') {
@@ -664,6 +960,61 @@ abstract class ElggEntity extends ElggData implements
}
/**
+ * Can a user comment on an entity?
+ *
+ * @tip Can be overridden by registering for the permissions_check:comment,
+ * <entity type> plugin hook.
+ *
+ * @param int $user_guid User guid (default is logged in user)
+ *
+ * @return bool
+ */
+ public function canComment($user_guid = 0) {
+ if ($user_guid == 0) {
+ $user_guid = elgg_get_logged_in_user_guid();
+ }
+ $user = get_entity($user_guid);
+
+ // By default, we don't take a position of whether commenting is allowed
+ // because it is handled by the subclasses of ElggEntity
+ $params = array('entity' => $this, 'user' => $user);
+ return elgg_trigger_plugin_hook('permissions_check:comment', $this->type, $params, null);
+ }
+
+ /**
+ * Can a user annotate an entity?
+ *
+ * @tip Can be overridden by registering for the permissions_check:annotate,
+ * <entity type> plugin hook.
+ *
+ * @tip If you want logged out users to annotate an object, do not call
+ * canAnnotate(). It's easier than using the plugin hook.
+ *
+ * @param int $user_guid User guid (default is logged in user)
+ * @param string $annotation_name The name of the annotation (default is unspecified)
+ *
+ * @return bool
+ */
+ public function canAnnotate($user_guid = 0, $annotation_name = '') {
+ if ($user_guid == 0) {
+ $user_guid = elgg_get_logged_in_user_guid();
+ }
+ $user = get_entity($user_guid);
+
+ $return = true;
+ if (!$user) {
+ $return = false;
+ }
+
+ $params = array(
+ 'entity' => $this,
+ 'user' => $user,
+ 'annotation_name' => $annotation_name,
+ );
+ return elgg_trigger_plugin_hook('permissions_check:annotate', $this->type, $params, $return);
+ }
+
+ /**
* Returns the access_id.
*
* @return int The access ID
@@ -675,7 +1026,7 @@ abstract class ElggEntity extends ElggData implements
/**
* Returns the guid.
*
- * @return int GUID
+ * @return int|null GUID
*/
public function getGUID() {
return $this->get('guid');
@@ -707,18 +1058,29 @@ abstract class ElggEntity extends ElggData implements
}
/**
+ * Get the guid of the entity's owner.
+ *
+ * @return int The owner GUID
+ */
+ public function getOwnerGUID() {
+ return $this->owner_guid;
+ }
+
+ /**
* Return the guid of the entity's owner.
*
* @return int The owner GUID
+ * @deprecated 1.8 Use getOwnerGUID()
*/
public function getOwner() {
- return $this->owner_guid;
+ elgg_deprecated_notice("ElggEntity::getOwner deprecated for ElggEntity::getOwnerGUID", 1.8);
+ return $this->getOwnerGUID();
}
/**
- * Returns the ElggEntity or child object of the owner of the entity.
+ * Gets the ElggEntity that owns this entity.
*
- * @return ElggEntity The owning user
+ * @return ElggEntity The owning entity
*/
public function getOwnerEntity() {
return get_entity($this->owner_guid);
@@ -731,30 +1093,57 @@ abstract class ElggEntity extends ElggData implements
*
* @return bool
*/
+ public function setContainerGUID($container_guid) {
+ $container_guid = (int)$container_guid;
+
+ return $this->set('container_guid', $container_guid);
+ }
+
+ /**
+ * Set the container for this object.
+ *
+ * @param int $container_guid The ID of the container.
+ *
+ * @return bool
+ * @deprecated 1.8 use setContainerGUID()
+ */
public function setContainer($container_guid) {
+ elgg_deprecated_notice("ElggObject::setContainer deprecated for ElggEntity::setContainerGUID", 1.8);
$container_guid = (int)$container_guid;
return $this->set('container_guid', $container_guid);
}
/**
- * Returns the container GUID of this object.
+ * Gets the container GUID for this entity.
*
* @return int
*/
+ public function getContainerGUID() {
+ return $this->get('container_guid');
+ }
+
+ /**
+ * Gets the container GUID for this entity.
+ *
+ * @return int
+ * @deprecated 1.8 Use getContainerGUID()
+ */
public function getContainer() {
+ elgg_deprecated_notice("ElggObject::getContainer deprecated for ElggEntity::getContainerGUID", 1.8);
return $this->get('container_guid');
}
/**
- * Returns the container entity for this object.
+ * Get the container entity for this object.
*
* @return ElggEntity
+ * @since 1.8.0
*/
public function getContainerEntity() {
- return get_entity($this->getContainer());
+ return get_entity($this->getContainerGUID());
}
-
+
/**
* Returns the UNIX epoch time that this entity was last updated
*
@@ -793,18 +1182,49 @@ abstract class ElggEntity extends ElggData implements
}
/**
+ * Get the URL for this entity's icon
+ *
+ * Plugins can register for the 'entity:icon:url', <type> plugin hook
+ * to customize the icon for an entity.
+ *
+ * @param string $size Size of the icon: tiny, small, medium, large
+ *
+ * @return string The URL
+ * @since 1.8.0
+ */
+ public function getIconURL($size = 'medium') {
+ $size = elgg_strtolower($size);
+
+ if (isset($this->icon_override[$size])) {
+ elgg_deprecated_notice("icon_override on an individual entity is deprecated", 1.8);
+ return $this->icon_override[$size];
+ }
+
+ $type = $this->getType();
+ $params = array(
+ 'entity' => $this,
+ 'size' => $size,
+ );
+
+ $url = elgg_trigger_plugin_hook('entity:icon:url', $type, $params, null);
+ if ($url == null) {
+ $url = "_graphics/icons/default/$size.png";
+ }
+
+ return elgg_normalize_url($url);
+ }
+
+ /**
* Returns a URL for the entity's icon.
*
* @param string $size Either 'large', 'medium', 'small' or 'tiny'
*
* @return string The url or false if no url could be worked out.
- * @see get_entity_icon_url()
+ * @deprecated Use getIconURL()
*/
public function getIcon($size = 'medium') {
- if (isset($this->icon_override[$size])) {
- return $this->icon_override[$size];
- }
- return get_entity_icon_url($this, $size);
+ elgg_deprecated_notice("getIcon() deprecated by getIconURL()", 1.8);
+ return $this->getIconURL($size);
}
/**
@@ -816,8 +1236,11 @@ abstract class ElggEntity extends ElggData implements
* @param string $size The size its for.
*
* @return bool
+ * @deprecated 1.8 See getIconURL() for the plugin hook to use
*/
public function setIcon($url, $size = 'medium') {
+ elgg_deprecated_notice("icon_override on an individual entity is deprecated", 1.8);
+
$url = sanitise_string($url);
$size = sanitise_string($size);
@@ -839,22 +1262,31 @@ abstract class ElggEntity extends ElggData implements
}
/**
- * Save attributes to the entities table.
+ * Save an entity.
*
- * @return bool
+ * @return bool|int
* @throws IOException
*/
public function save() {
- $guid = (int) $this->guid;
+ $guid = $this->getGUID();
if ($guid > 0) {
- cache_entity($this);
- return update_entity(
- $this->get('guid'),
+ // See #5600. This ensures the lower level can_edit_entity() check will use a
+ // fresh entity from the DB so it sees the persisted owner_guid
+ _elgg_disable_caching_for_entity($guid);
+
+ $ret = update_entity(
+ $guid,
$this->get('owner_guid'),
$this->get('access_id'),
- $this->get('container_guid')
+ $this->get('container_guid'),
+ $this->get('time_created')
);
+
+ _elgg_enable_caching_for_entity($guid);
+ _elgg_cache_entity($this);
+
+ return $ret;
} else {
// Create a new entity (nb: using attribute array directly
// 'cos set function does something special!)
@@ -876,8 +1308,7 @@ abstract class ElggEntity extends ElggData implements
}
}
- // Save any unsaved annotations metadata.
- // @todo How to capture extra information (access id etc)
+ // Save any unsaved annotations.
if (sizeof($this->temp_annotations) > 0) {
foreach ($this->temp_annotations as $name => $value) {
$this->annotate($name, $value);
@@ -885,14 +1316,19 @@ abstract class ElggEntity extends ElggData implements
}
}
+ // Save any unsaved private settings.
+ if (sizeof($this->temp_private_settings) > 0) {
+ foreach ($this->temp_private_settings as $name => $value) {
+ $this->setPrivateSetting($name, $value);
+ unset($this->temp_private_settings[$name]);
+ }
+ }
+
// set the subtype to id now rather than a string
$this->attributes['subtype'] = get_subtype_id($this->attributes['type'],
$this->attributes['subtype']);
- // Cache object handle
- if ($this->attributes['guid']) {
- cache_entity($this);
- }
+ _elgg_cache_entity($this);
return $this->attributes['guid'];
}
@@ -901,12 +1337,16 @@ abstract class ElggEntity extends ElggData implements
/**
* Loads attributes from the entities table into the object.
*
- * @param int $guid GUID of Entity
+ * @param mixed $guid GUID of entity or stdClass object from entities table
*
* @return bool
*/
protected function load($guid) {
- $row = get_entity_as_row($guid);
+ if ($guid instanceof stdClass) {
+ $row = $guid;
+ } else {
+ $row = get_entity_as_row($guid);
+ }
if ($row) {
// Create the array if necessary - all subclasses should test before creating
@@ -925,9 +1365,12 @@ abstract class ElggEntity extends ElggData implements
$this->attributes['tables_loaded']++;
}
+ // guid needs to be an int https://github.com/elgg/elgg/issues/4111
+ $this->attributes['guid'] = (int)$this->attributes['guid'];
+
// Cache object handle
if ($this->attributes['guid']) {
- cache_entity($this);
+ _elgg_cache_entity($this);
}
return true;
@@ -996,10 +1439,12 @@ abstract class ElggEntity extends ElggData implements
/**
* Delete this entity.
*
+ * @param bool $recursive Whether to delete all the entities contained by this entity
+ *
* @return bool
*/
- public function delete() {
- return delete_entity($this->get('guid'));
+ public function delete($recursive = true) {
+ return delete_entity($this->get('guid'), $recursive);
}
/*
@@ -1007,19 +1452,25 @@ abstract class ElggEntity extends ElggData implements
*/
/**
+ * Gets the 'location' metadata for the entity
+ *
+ * @return string The location
+ */
+ public function getLocation() {
+ return $this->location;
+ }
+
+ /**
* Sets the 'location' metadata for the entity
*
* @todo Unimplemented
*
* @param string $location String representation of the location
*
- * @return true
+ * @return bool
*/
public function setLocation($location) {
- $location = sanitise_string($location);
-
$this->location = $location;
-
return true;
}
@@ -1029,13 +1480,10 @@ abstract class ElggEntity extends ElggData implements
* @param float $lat Latitude
* @param float $long Longitude
*
- * @return true
+ * @return bool
* @todo Unimplemented
*/
public function setLatLong($lat, $long) {
- $lat = sanitise_string($lat);
- $long = sanitise_string($long);
-
$this->set('geo:lat', $lat);
$this->set('geo:long', $long);
@@ -1045,29 +1493,20 @@ abstract class ElggEntity extends ElggData implements
/**
* Return the entity's latitude.
*
- * @return int
+ * @return float
* @todo Unimplemented
*/
public function getLatitude() {
- return $this->get('geo:lat');
+ return (float)$this->get('geo:lat');
}
/**
* Return the entity's longitude
*
- * @return Int
+ * @return float
*/
public function getLongitude() {
- return $this->get('geo:long');
- }
-
- /**
- * Return the entity's location
- *
- * @return string
- */
- public function getLocation() {
- return $this->get('location');
+ return (float)$this->get('geo:long');
}
/*
@@ -1174,36 +1613,36 @@ abstract class ElggEntity extends ElggData implements
foreach ($this->attributes as $k => $v) {
$meta = NULL;
- if (in_array( $k, $exportable_values)) {
+ if (in_array($k, $exportable_values)) {
switch ($k) {
- case 'guid' : // Dont use guid in OpenDD
- case 'type' : // Type and subtype already taken care of
- case 'subtype' :
- break;
+ case 'guid': // Dont use guid in OpenDD
+ case 'type': // Type and subtype already taken care of
+ case 'subtype':
+ break;
- case 'time_created' : // Created = published
+ case 'time_created': // Created = published
$odd->setAttribute('published', date("r", $v));
- break;
+ break;
- case 'site_guid' : // Container
+ case 'site_guid': // Container
$k = 'site_uuid';
$v = guid_to_uuid($v);
$meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
- break;
+ break;
- case 'container_guid' : // Container
+ case 'container_guid': // Container
$k = 'container_uuid';
$v = guid_to_uuid($v);
$meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
- break;
+ break;
- case 'owner_guid' : // Convert owner guid to uuid, this will be stored in metadata
+ case 'owner_guid': // Convert owner guid to uuid, this will be stored in metadata
$k = 'owner_uuid';
$v = guid_to_uuid($v);
$meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
- break;
+ break;
- default :
+ default:
$meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v);
}
@@ -1221,7 +1660,7 @@ abstract class ElggEntity extends ElggData implements
*/
elgg_set_viewtype('default');
- $view = elgg_view_entity($this, true);
+ $view = elgg_view_entity($this, array('full_view' => true));
elgg_set_viewtype();
$tmp[] = new ODDMetaData($uuid . "volatile/renderedentity/", $uuid,
@@ -1237,9 +1676,11 @@ abstract class ElggEntity extends ElggData implements
/**
* Import data from an parsed ODD xml data array.
*
- * @param array $data XML data
+ * @param ODD $data XML data
*
* @return true
+ *
+ * @throws InvalidParameterException
*/
public function import(ODD $data) {
if (!($data instanceof ODDEntity)) {
@@ -1251,7 +1692,7 @@ abstract class ElggEntity extends ElggData implements
$this->attributes['subtype'] = $data->getAttribute('subclass');
// Set owner
- $this->attributes['owner_guid'] = get_loggedin_userid(); // Import as belonging to importer.
+ $this->attributes['owner_guid'] = elgg_get_logged_in_user_guid(); // Import as belonging to importer.
// Set time
$this->attributes['time_created'] = strtotime($data->getAttribute('published'));
@@ -1301,8 +1742,6 @@ abstract class ElggEntity extends ElggData implements
* @return array
*/
public function getTags($tag_names = NULL) {
- global $CONFIG;
-
if ($tag_names && !is_array($tag_names)) {
$tag_names = array($tag_names);
}
@@ -1328,4 +1767,4 @@ abstract class ElggEntity extends ElggData implements
return $entity_tags;
}
-} \ No newline at end of file
+}