attributes['guid'] = null; $this->attributes['type'] = null; $this->attributes['subtype'] = null; $this->attributes['owner_guid'] = _elgg_services()->session->getLoggedInUserGuid(); $this->attributes['container_guid'] = _elgg_services()->session->getLoggedInUserGuid(); $this->attributes['site_guid'] = null; $this->attributes['access_id'] = ACCESS_PRIVATE; $this->attributes['time_updated'] = null; $this->attributes['last_action'] = null; $this->attributes['enabled'] = "yes"; // There now follows a bit of a hack /* Problem: To speed things up, some objects are split over several tables, * this means that it requires n number of database reads to fully populate * an entity. This causes problems for caching and create events * since it is not possible to tell whether a subclassed entity is complete. * * Solution: We have two counters, one 'tables_split' which tells whatever is * interested how many tables are going to need to be searched in order to fully * populate this object, and 'tables_loaded' which is how many have been * loaded thus far. * * If the two are the same then this object is complete. * * Use: isFullyLoaded() to check */ $this->tables_split = 1; $this->tables_loaded = 0; } /** * Clone an entity * * Resets the guid so that the entity can be saved as a distinct entity from * the original. Creation time will be set when this new entity is saved. * The owner and container guids come from the original entity. The clone * method copies metadata but does not copy annotations or private settings. * * @note metadata will have its owner and access id set when the entity is saved * and it will be the same as that of the entity. * * @return void */ public function __clone() { $orig_entity = get_entity($this->guid); if (!$orig_entity) { _elgg_services()->logger->error("Failed to clone entity with GUID $this->guid"); return; } $metadata_array = elgg_get_metadata(array( 'guid' => $this->guid, 'limit' => 0 )); $this->attributes['guid'] = ""; $this->attributes['subtype'] = $orig_entity->getSubtype(); // copy metadata over to new entity - slightly convoluted due to // handling of metadata arrays if (is_array($metadata_array)) { // create list of metadata names $metadata_names = array(); foreach ($metadata_array as $metadata) { $metadata_names[] = $metadata['name']; } // arrays are stored with multiple enties per name $metadata_names = array_unique($metadata_names); // move the metadata over foreach ($metadata_names as $name) { $this->__set($name, $orig_entity->$name); } } } /** * Set an attribute or metadata value for this entity * * Anything that is not an attribute is saved as metadata. * * @warning Metadata set this way will inherit the entity's owner and * access ID. If you want more control over metadata, use \ElggEntity::setMetadata() * * @param string $name Name of the attribute or metadata * @param mixed $value The value to be set * @return void * @see \ElggEntity::setMetadata() */ public function __set($name, $value) { if ($this->$name === $value) { // quick return if value is not changing return; } if (array_key_exists($name, $this->attributes)) { // Certain properties should not be manually changed! switch ($name) { case 'guid': case 'time_updated': case 'last_action': return; break; case 'access_id': case 'owner_guid': case 'container_guid': if ($value !== null) { $this->attributes[$name] = (int)$value; } else { $this->attributes[$name] = null; } break; default: $this->attributes[$name] = $value; break; } } else { $this->setMetadata($name, $value); } } /** * Sets the value of an attribute or metadata * * @param string $name Name * @param mixed $value Value * * @return bool * @deprecated 1.9 */ public function set($name, $value) { elgg_deprecated_notice("Use -> instead of set()", 1.9); $this->__set($name, $value); return true; } /** * Get an attribute or metadata value * * If the name matches an attribute, the attribute is returned. If metadata * does not exist with that name, a null is returned. * * This only returns an array if there are multiple values for a particular * $name key. * * @param string $name Name of the attribute or metadata * @return mixed */ public function __get($name) { if (array_key_exists($name, $this->attributes)) { if ($name === 'subtype' && $this->attributes['guid']) { // note: only show deprecation notice if user reads ->subtype after save/load elgg_deprecated_notice("Use getSubtype()", 1.9); } return $this->attributes[$name]; } return $this->getMetadata($name); } /** * Return the value of an attribute or metadata * * @param string $name Name * @return mixed Returns the value of a given value, or null. * @deprecated 1.9 */ public function get($name) { elgg_deprecated_notice("Use -> instead of get()", 1.9); return $this->__get($name); } /** * Get the entity's display name * * @return string The title or name of this entity. */ abstract public function getDisplayName(); /** * Sets the title or name of this entity. * * @param string $displayName The title or name of this entity. * @return void */ abstract public function setDisplayName($displayName); /** * Return the value of a piece of metadata. * * @param string $name Name * * @return mixed The value, or null if not found. */ public function getMetadata($name) { $guid = $this->getGUID(); if (!$guid) { if (isset($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_services()->metadataCache; if ($cache->isLoaded($guid)) { return $cache->getSingle($guid, $name); } else { $cache->populateFromEntities(array($guid)); // in case ignore_access was on, we have to check again... if ($cache->isLoaded($guid)) { return $cache->getSingle($guid, $name); } } $md = elgg_get_metadata(array( 'guid' => $guid, 'metadata_name' => $name, 'limit' => 0, 'distinct' => false, )); $value = null; if ($md && !is_array($md)) { $value = $md->value; } elseif (count($md) == 1) { $value = $md[0]->value; } else if ($md && is_array($md)) { $value = metadata_array_to_values($md); } return $value; } /** * Unset a property from metadata or attribute. * * @warning If you use this to unset an attribute, you must save the object! * * @param string $name The name of the attribute or metadata. * * @return void * @todo some attributes should be set to null or other default values */ public function __unset($name) { if (array_key_exists($name, $this->attributes)) { $this->attributes[$name] = ""; } else { $this->deleteMetadata($name); } } /** * Set metadata on this entity. * * Plugin developers usually want to use the magic set method ($entity->name = 'value'). * Use this method if you want to explicitly set the owner or access of the metadata. * You cannot set the owner/access before the entity has been saved. * * @param string $name Name of the metadata * @param mixed $value Value of the metadata (doesn't support assoc arrays) * @param string $value_type 'text', 'integer', or '' for automatic detection * @param bool $multiple Allow multiple values for a single name. * Does not support associative arrays. * @param int $owner_guid GUID of entity that owns the metadata. * Default is owner of entity. * @param int $access_id Who can read the metadata relative to the owner. * Default is the access level of the entity. * * @return bool * @throws InvalidArgumentException */ public function setMetadata($name, $value, $value_type = '', $multiple = false, $owner_guid = 0, $access_id = null) { // normalize value to an array that we will loop over // remove indexes if value already an array. if (is_array($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); } $owner_guid = (int)$owner_guid; $access_id = ($access_id === null) ? $this->getAccessId() : (int)$access_id; $owner_guid = $owner_guid ? $owner_guid : $this->getOwnerGUID(); // add new md $result = true; foreach ($value as $value_tmp) { // at this point $value is appended because it was cleared above if needed. $md_id = create_metadata($this->getGUID(), $name, $value_tmp, $value_type, $owner_guid, $access_id, true); if (!$md_id) { return false; } } 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 ($owner_guid != 0 || $access_id !== null) { $msg = "owner guid and access id cannot be used in \ElggEntity::setMetadata() until entity is saved."; throw new \InvalidArgumentException($msg); } // 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; } /** * Remove metadata * * @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 = '') { 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. * * @param string $name The name of the volatile data * * @return mixed The value or null if not found. */ public function getVolatileData($name) { if (!is_array($this->volatile)) { $this->volatile = array(); } if (array_key_exists($name, $this->volatile)) { return $this->volatile[$name]; } else { return null; } } /** * Set a piece of volatile (non-persisted) data on this entity * * @param string $name Name * @param mixed $value Value * * @return void */ public function setVolatileData($name, $value) { if (!is_array($this->volatile)) { $this->volatile = array(); } $this->volatile[$name] = $value; } /** * Remove all relationships to and from this entity. * If you pass a relationship name, only relationships matching that name * will be deleted. * * @warning Calling this with no $relationship will clear all relationships * for this entity. * * @param null|string $relationship The name of the relationship to remove. * @return bool * @see \ElggEntity::addRelationship() * @see \ElggEntity::removeRelationship() */ public function deleteRelationships($relationship = null) { $relationship = (string)$relationship; $result = remove_entity_relationships($this->getGUID(), $relationship); return $result && remove_entity_relationships($this->getGUID(), $relationship, true); } /** * Remove all relationships to and from this entity. * * @return bool * @see \ElggEntity::addRelationship() * @see \ElggEntity::removeRelationship() * @deprecated 1.8 Use \ElggEntity::deleteRelationships() */ 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 "This entity is a $relationship of $guid_two." * * @param int $guid_two GUID of the target entity of the relationship. * @param string $relationship The type of relationship. * * @return bool * @see \ElggEntity::removeRelationship() * @see \ElggEntity::deleteRelationships() */ public function addRelationship($guid_two, $relationship) { return add_entity_relationship($this->getGUID(), $relationship, $guid_two); } /** * Remove a relationship * * @param int $guid_two GUID of the target entity of the relationship. * @param string $relationship The type of relationship. * * @return bool * @see \ElggEntity::addRelationship() * @see \ElggEntity::deleteRelationships() */ public function removeRelationship($guid_two, $relationship) { return remove_entity_relationship($this->getGUID(), $relationship, $guid_two); } /** * Adds a private setting to this entity. * * Private settings are similar to metadata but will not * be searched and there are fewer helper functions for them. * * @param string $name Name of private setting * @param mixed $value Value of private setting * * @return bool */ public function setPrivateSetting($name, $value) { if ((int) $this->guid > 0) { return set_private_setting($this->getGUID(), $name, $value); } else { $this->temp_private_settings[$name] = $value; return true; } } /** * Returns a private setting value * * @param string $name Name of the private setting * * @return mixed Null if the setting does not exist */ public function getPrivateSetting($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; } /** * Removes private setting * * @param string $name Name of the private setting * * @return bool */ public function removePrivateSetting($name) { return remove_private_setting($this->getGUID(), $name); } /** * 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(), 'distinct' => false, '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 * @param int $owner_guid GUID of the annotation owner * @param string $vartype The type of annotation value * * @return bool|int Returns int if an annotation is saved */ public function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_guid = 0, $vartype = "") { if ((int) $this->guid > 0) { return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_guid, $access_id); } else { $this->temp_annotations[$name] = $value; } return true; } /** * Gets an array of annotations. * * To retrieve annotations on an unsaved entity, pass array('name' => [annotation name]) * as the options array. * * @param array $options Array of options for elgg_get_annotations() except guid. This * may be passed a string annotation name, but this usage is deprecated. * @param int $limit Limit (deprecated) * @param int $offset Offset (deprecated) * @param string $order Order by time: asc or desc (deprecated) * * @return array * @see elgg_get_annotations() */ public function getAnnotations($options = array(), $limit = 50, $offset = 0, $order = "asc") { if (!is_array($options)) { elgg_deprecated_notice("\ElggEntity::getAnnotations() takes an array of options.", 1.9); } if ((int) ($this->guid) > 0) { if (!is_array($options)) { $options = array( 'guid' => $this->guid, 'annotation_name' => $options, 'limit' => $limit, 'offset' => $offset, ); if ($order != 'asc') { $options['reverse_order_by'] = true; } } else { $options['guid'] = $this->guid; } return elgg_get_annotations($options); } else { if (!is_array($options)) { $name = $options; } else { $name = elgg_extract('annotation_name', $options, ''); } if (isset($this->temp_annotations[$name])) { return array($this->temp_annotations[$name]); } } return array(); } /** * Remove an annotation or all annotations for this entity. * * @warning Calling this method with no or an empty argument will remove * all annotations on the entity. * * @param string $name Annotation name * @return bool * @deprecated 1.8 Use ->deleteAnnotations() */ public function clearAnnotations($name = "") { elgg_deprecated_notice('\ElggEntity->clearAnnotations() is deprecated by ->deleteAnnotations()', 1.8); return $this->deleteAnnotations($name); } /** * Count annotations. * * @param string $name The type of annotation. * * @return int */ public function countAnnotations($name = "") { return $this->getAnnotationCalculation($name, 'count'); } /** * Get the average of an integer type annotation. * * @param string $name Annotation name * * @return int */ public function getAnnotationsAvg($name) { return $this->getAnnotationCalculation($name, 'avg'); } /** * Get the sum of integer type annotations of a given name. * * @param string $name Annotation name * * @return int */ public function getAnnotationsSum($name) { return $this->getAnnotationCalculation($name, 'sum'); } /** * Get the minimum of integer type annotations of given name. * * @param string $name Annotation name * * @return int */ public function getAnnotationsMin($name) { return $this->getAnnotationCalculation($name, 'min'); } /** * Get the maximum of integer type annotations of a given name. * * @param string $name Annotation name * * @return int */ public function getAnnotationsMax($name) { return $this->getAnnotationCalculation($name, 'max'); } /** * Count the number of comments attached to this entity. * * @return int Number of comments * @since 1.8.0 */ public function countComments() { $params = array('entity' => $this); $num = _elgg_services()->hooks->trigger('comments:count', $this->getType(), $params); if (is_int($num)) { return $num; } else { return elgg_get_entities(array( 'type' => 'object', 'subtype' => 'comment', 'container_guid' => $this->getGUID(), 'count' => true, 'distinct' => false, )); } } /** * Gets an array of entities with a relationship to this entity. * * @param array $options Options array. See elgg_get_entities_from_relationship() * for a list of options. 'relationship_guid' is set to * this entity. * @param bool $inverse Is this an inverse relationship? (deprecated) * @param int $limit Number of elements to return (deprecated) * @param int $offset Indexing offset (deprecated) * * @return array|false An array of entities or false on failure * @see elgg_get_entities_from_relationship() */ public function getEntitiesFromRelationship($options = array(), $inverse = false, $limit = 50, $offset = 0) { if (is_array($options)) { $options['relationship_guid'] = $this->getGUID(); return elgg_get_entities_from_relationship($options); } else { elgg_deprecated_notice("\ElggEntity::getEntitiesFromRelationship takes an options array", 1.9); return elgg_get_entities_from_relationship(array( 'relationship' => $options, 'relationship_guid' => $this->getGUID(), 'inverse_relationship' => $inverse, 'limit' => $limit, 'offset' => $offset )); } } /** * Gets the number of entities from a specific relationship type * * @param string $relationship Relationship type (eg "friends") * @param bool $inverse_relationship Invert relationship * * @return int|false The number of entities or false on failure */ public function countEntitiesFromRelationship($relationship, $inverse_relationship = false) { return elgg_get_entities_from_relationship(array( 'relationship' => $relationship, 'relationship_guid' => $this->getGUID(), 'inverse_relationship' => $inverse_relationship, 'count' => true )); } /** * Can a user edit this entity? * * @tip Can be overridden by registering for the permissions_check plugin hook. * * @param int $user_guid The user GUID, optionally (default: logged in user) * * @return bool Whether this entity is editable by the given user. * @see elgg_set_ignore_access() */ public function canEdit($user_guid = 0) { $user_guid = (int)$user_guid; $user = get_entity($user_guid); if (!$user) { $user = _elgg_services()->session->getLoggedInUser(); } $return = false; // Test user if possible - should default to false unless a plugin hook says otherwise if ($user) { if ($this->getOwnerGUID() == $user->getGUID()) { $return = true; } if ($this->getContainerGUID() == $user->getGUID()) { $return = true; } if ($this->getGUID() == $user->getGUID()) { $return = true; } $container = $this->getContainerEntity(); if ($container && $container->canEdit($user->getGUID())) { $return = true; } } $params = array('entity' => $this, 'user' => $user); return _elgg_services()->hooks->trigger('permissions_check', $this->type, $params, $return); } /** * Can a user delete this entity? * * @tip Can be overridden by registering for the permissions_check:delete plugin hook. * * @param int $user_guid The user GUID, optionally (default: logged in user) * * @return bool Whether this entity is deletable by the given user. * @since 1.11 * @see elgg_set_ignore_access() */ public function canDelete($user_guid = 0) { $user_guid = (int) $user_guid; if (!$user_guid) { $user_guid = _elgg_services()->session->getLoggedInUserGuid(); } // need to ignore access and show hidden entities for potential hidden/disabled users $ia = elgg_set_ignore_access(true); $show_hidden = access_show_hidden_entities(true); $user = _elgg_services()->entityTable->get($user_guid, 'user'); elgg_set_ignore_access($ia); access_show_hidden_entities($show_hidden); if ($user_guid & !$user) { // requested to check access for a specific user_guid, but there is no user entity, so return false $message = _elgg_services()->translator->translate('entity:can_delete:invaliduser', array($user_guid)); _elgg_services()->logger->warning($message); return false; } $return = $this->canEdit($user_guid); $params = array('entity' => $this, 'user' => $user); return _elgg_services()->hooks->trigger('permissions_check:delete', $this->type, $params, $return); } /** * Can a user edit metadata on this entity? * * If no specific metadata is passed, it returns whether the user can * edit any metadata on the entity. * * @tip Can be overridden by by registering for the permissions_check:metadata * plugin hook. * * @param \ElggMetadata $metadata The piece of metadata to specifically check or null for any metadata * @param int $user_guid The user GUID, optionally (default: logged in user) * * @return bool * @see elgg_set_ignore_access() */ public function canEditMetadata($metadata = null, $user_guid = 0) { if (!$this->guid) { // @todo cannot edit metadata on unsaved entity? return false; } if ($user_guid) { $user = get_user($user_guid); if (!$user) { return false; } } else { $user = _elgg_services()->session->getLoggedInUser(); $user_guid = $user->guid; } $return = null; // if metadata is not owned or owned by the user, then can edit if ($metadata && ($metadata->owner_guid == 0 || $metadata->owner_guid == $user_guid)) { $return = true; } if (is_null($return)) { $return = $this->canEdit($user_guid); } // metadata and user may be null $params = array('entity' => $this, 'user' => $user, 'metadata' => $metadata); return _elgg_services()->hooks->trigger('permissions_check:metadata', $this->type, $params, $return); } /** * Can a user add an entity to this container * * @param int $user_guid The GUID of the user creating the entity (0 for logged in 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 * @see elgg_set_ignore_access() */ public function canWriteToContainer($user_guid = 0, $type = 'all', $subtype = 'all') { return can_write_to_container($user_guid, $this->guid, $type, $subtype); } /** * Can a user comment on an entity? * * @tip Can be overridden by registering for the permissions_check:comment, * 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_services()->session->getLoggedInUserGuid(); } $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_services()->hooks->trigger('permissions_check:comment', $this->type, $params, null); } /** * Can a user annotate an entity? * * @tip Can be overridden by registering for the plugin hook [permissions_check:annotate:, * ] or [permissions_check:annotate, ]. The hooks are called in that order. * * @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_services()->session->getLoggedInUserGuid(); } $user = get_entity($user_guid); $return = true; if (!$user) { $return = false; } $hooks = _elgg_services()->hooks; $params = array( 'entity' => $this, 'user' => $user, 'annotation_name' => $annotation_name, ); if ($annotation_name !== '') { $return = $hooks->trigger("permissions_check:annotate:$annotation_name", $this->type, $params, $return); } $return = $hooks->trigger('permissions_check:annotate', $this->type, $params, $return); return $return; } /** * Returns the access_id. * * @return int The access ID */ public function getAccessID() { return $this->access_id; } /** * Returns the guid. * * @return int|null GUID */ public function getGUID() { return $this->guid; } /** * Returns the entity type * * @return string The entity type */ public function getType() { return $this->type; } /** * Get the entity subtype * * @return string The entity subtype */ public function getSubtype() { // If this object hasn't been saved, then return the subtype string. if ($this->attributes['guid']) { return get_subtype_from_id($this->attributes['subtype']); } return $this->attributes['subtype']; } /** * Get the guid of the entity's owner. * * @return int The owner GUID */ public function getOwnerGUID() { return (int)$this->owner_guid; } /** * Return the guid of the entity's owner. * * @return int The owner GUID * @deprecated 1.8 Use getOwnerGUID() */ public function getOwner() { elgg_deprecated_notice("\ElggEntity::getOwner deprecated for \ElggEntity::getOwnerGUID", 1.8); return $this->getOwnerGUID(); } /** * Gets the \ElggEntity that owns this entity. * * @return \ElggEntity The owning entity */ public function getOwnerEntity() { return get_entity($this->owner_guid); } /** * Set the container for this object. * * @param int $container_guid The ID of the container. * * @return bool */ public function setContainerGUID($container_guid) { return $this->container_guid = (int)$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); return $this->setContainerGUID('container_guid', $container_guid); } /** * Gets the container GUID for this entity. * * @return int */ public function getContainerGUID() { return (int)$this->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->getContainerGUID(); } /** * Get the container entity for this object. * * @return \ElggEntity * @since 1.8.0 */ public function getContainerEntity() { return get_entity($this->getContainerGUID()); } /** * Returns the UNIX epoch time that this entity was last updated * * @return int UNIX epoch time */ public function getTimeUpdated() { return $this->time_updated; } /** * Gets the URL for this entity. * * Plugins can register for the 'entity:url', plugin hook to * customize the url for an entity. * * @return string The URL of the entity */ public function getURL() { $url = ""; // @todo remove when elgg_register_entity_url_handler() has been removed if ($this->guid) { global $CONFIG; if (isset($CONFIG->entity_url_handler[$this->getType()][$this->getSubtype()])) { $function = $CONFIG->entity_url_handler[$this->getType()][$this->getSubtype()]; if (is_callable($function)) { $url = call_user_func($function, $this); } } elseif (isset($CONFIG->entity_url_handler[$this->getType()]['all'])) { $function = $CONFIG->entity_url_handler[$this->getType()]['all']; if (is_callable($function)) { $url = call_user_func($function, $this); } } elseif (isset($CONFIG->entity_url_handler['all']['all'])) { $function = $CONFIG->entity_url_handler['all']['all']; if (is_callable($function)) { $url = call_user_func($function, $this); } } if ($url) { $url = elgg_normalize_url($url); } } $type = $this->getType(); $params = array('entity' => $this); $url = _elgg_services()->hooks->trigger('entity:url', $type, $params, $url); // @todo remove when \ElggEntity::setURL() has been removed if (!empty($this->url_override)) { $url = $this->url_override; } return elgg_normalize_url($url); } /** * Overrides the URL returned by getURL() * * @warning This override exists only for the life of the object. * * @param string $url The new item URL * * @return string The URL * @deprecated 1.9.0 See \ElggEntity::getURL() for details on the plugin hook */ public function setURL($url) { elgg_deprecated_notice('\ElggEntity::setURL() has been replaced by the "entity:url" plugin hook', 1.9); $this->url_override = $url; return $url; } /** * Get the URL for this entity's icon * * Plugins can register for the 'entity:icon:url', plugin hook * to customize the icon for an entity. * * @param mixed $params A string defining the size of the icon (e.g. tiny, small, medium, large) * or an array of parameters including 'size' * @return string The URL * @since 1.8.0 */ public function getIconURL($params = array()) { if (is_array($params)) { $size = elgg_extract('size', $params, 'medium'); } else { $size = is_string($params) ? $params : 'medium'; $params = array(); } $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]; } $params['entity'] = $this; $params['size'] = $size; $type = $this->getType(); $url = _elgg_services()->hooks->trigger('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. * @deprecated 1.8 Use getIconURL() */ public function getIcon($size = 'medium') { elgg_deprecated_notice("getIcon() deprecated by getIconURL()", 1.8); return $this->getIconURL($size); } /** * Set an icon override for an icon and size. * * @warning This override exists only for the life of the object. * * @param string $url The url of the icon. * @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); if (!$this->icon_override) { $this->icon_override = array(); } $this->icon_override[$size] = $url; return true; } /** * Add this entity to a site * * This creates a 'member_of_site' relationship. * * @param \ElggSite $site The site to add this entity to * * @return bool * @todo add \ElggSite type hint once we have removed addToSite() from \ElggUser * and \ElggObject */ public function addToSite($site) { if (!elgg_instanceof($site, 'site')) { return false; } return $site->addEntity($this); } /** * Remove this entity from a site * * This deletes the 'member_of_site' relationship. * * @param \ElggSite $site The site to remove this entity from * * @return bool * @todo add \ElggSite type hint once we have removed addToSite() from \ElggUser */ public function removeFromSite($site) { if (!elgg_instanceof($site, 'site')) { return false; } return $site->removeEntity($this); } /** * Gets the sites this entity is a member of * * Site membership is determined by relationships and not site_guid. * * @param array $options Options array for elgg_get_entities_from_relationship() * Parameters set automatically by this method: * 'relationship', 'relationship_guid', 'inverse_relationship' * * @return array * @todo add type hint when \ElggUser and \ElggObject have been updates */ public function getSites($options = array()) { $options['relationship'] = 'member_of_site'; $options['relationship_guid'] = $this->guid; $options['inverse_relationship'] = false; if (!isset($options['site_guid']) || !isset($options['site_guids'])) { $options['site_guids'] = ELGG_ENTITIES_ANY_VALUE; } return elgg_get_entities_from_relationship($options); } /** * Tests to see whether the object has been fully loaded. * * @return bool */ public function isFullyLoaded() { return ! ($this->tables_loaded < $this->tables_split); } /** * Save an entity. * * @return bool|int * @throws InvalidParameterException * @throws IOException */ public function save() { $guid = $this->getGUID(); if ($guid > 0) { return $this->update(); } else { $guid = $this->create(); if ($guid) { if (_elgg_services()->events->trigger('create', $this->type, $this)) { return $guid; } else { // plugins that return false to event don't need to override the access system $ia = elgg_set_ignore_access(true); $this->delete(); elgg_set_ignore_access($ia); } } } return false; } /** * Create a new entry in the entities table. * * Saves the base information in the entities table for the entity. Saving * the type-specific information is handled in the calling class method. * * @warning Entities must have an entry in both the entities table and their type table * or they will throw an exception when loaded. * * @return int The new entity's GUID * @throws InvalidParameterException If the entity's type has not been set. * @throws IOException If the new row fails to write to the DB. */ protected function create() { global $CONFIG; // Using attribute array directly; get function does something special! $type = $this->getDatabase()->sanitizeString($this->attributes['type']); if ($type == "") { throw new \InvalidParameterException("Entity type must be set."); } $subtype = $this->attributes['subtype']; $subtype_id = add_subtype($type, $subtype); $owner_guid = (int)$this->attributes['owner_guid']; $access_id = (int)$this->attributes['access_id']; $now = (string)time(); $time_created = isset($this->attributes['time_created']) ? (int)$this->attributes['time_created'] : $now; $site_guid = $this->attributes['site_guid']; if ($site_guid == 0) { $site_guid = $CONFIG->site_guid; } $site_guid = (int)$site_guid; $container_guid = $this->attributes['container_guid']; if ($container_guid == 0) { $container_guid = $owner_guid; $this->attributes['container_guid'] = $container_guid; } $container_guid = (int)$container_guid; if ($access_id == ACCESS_DEFAULT) { throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h'); } $owner = $this->getOwnerEntity(); if ($owner && !$owner->canWriteToContainer(0, $type, $subtype)) { return false; } if ($owner_guid != $container_guid) { $container = $this->getContainerEntity(); if ($container && !$container->canWriteToContainer(0, $type, $subtype)) { return false; } } $result = $this->getDatabase()->insertData("INSERT into {$CONFIG->dbprefix}entities (type, subtype, owner_guid, site_guid, container_guid, access_id, time_created, time_updated, last_action) values ('$type', $subtype_id, $owner_guid, $site_guid, $container_guid, $access_id, $time_created, $now, $now)"); if (!$result) { throw new \IOException("Unable to save new object's base entity information!"); } // for BC with 1.8, ->subtype always returns ID, ->getSubtype() the string $this->attributes['subtype'] = (int)$subtype_id; $this->attributes['guid'] = (int)$result; $this->attributes['time_created'] = (int)$time_created; $this->attributes['time_updated'] = (int)$now; $this->attributes['last_action'] = (int)$now; $this->attributes['site_guid'] = (int)$site_guid; $this->attributes['container_guid'] = (int)$container_guid; // Save any unsaved metadata if (sizeof($this->temp_metadata) > 0) { foreach ($this->temp_metadata as $name => $value) { $this->$name = $value; } $this->temp_metadata = array(); } // Save any unsaved annotations. if (sizeof($this->temp_annotations) > 0) { foreach ($this->temp_annotations as $name => $value) { $this->annotate($name, $value); } $this->temp_annotations = array(); } // Save any unsaved private settings. if (sizeof($this->temp_private_settings) > 0) { foreach ($this->temp_private_settings as $name => $value) { $this->setPrivateSetting($name, $value); } $this->temp_private_settings = array(); } _elgg_cache_entity($this); return $result; } /** * Update the entity in the database. * * @return bool Whether the update was successful. * * @throws InvalidParameterException */ protected function update() { global $CONFIG; // See #5600. This ensures canEdit() checks the BD persisted entity so it sees the // persisted owner_guid, container_guid, etc. _elgg_disable_caching_for_entity($this->guid); $persisted_entity = get_entity($this->guid); if (!$persisted_entity) { // Why worry about this case? If access control was off when the user fetched this object but // was turned back on again. Better to just bail than to turn access control off again. return false; } $allow_edit = $persisted_entity->canEdit(); unset($persisted_entity); if ($allow_edit) { // give old update event a chance to stop the update $allow_edit = _elgg_services()->events->trigger('update', $this->type, $this); } _elgg_enable_caching_for_entity($this->guid); if (!$allow_edit) { return false; } // See #6225. We copy these after the update event in case a handler changed one of them. $guid = (int)$this->guid; $owner_guid = (int)$this->owner_guid; $access_id = (int)$this->access_id; $container_guid = (int)$this->container_guid; $time_created = (int)$this->time_created; $time = time(); if ($access_id == ACCESS_DEFAULT) { throw new \InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.php'); } $ret = $this->getDatabase()->updateData("UPDATE {$CONFIG->dbprefix}entities set owner_guid='$owner_guid', access_id='$access_id', container_guid='$container_guid', time_created='$time_created', time_updated='$time' WHERE guid=$guid"); elgg_trigger_after_event('update', $this->type, $this); // TODO(evan): Move this to \ElggObject? if ($this instanceof \ElggObject) { update_river_access_by_object($guid, $access_id); } // If memcache is available then delete this entry from the cache static $newentity_cache; if ((!$newentity_cache) && (is_memcache_available())) { $newentity_cache = new \ElggMemcache('new_entity_cache'); } if ($newentity_cache) { $newentity_cache->delete($guid); } if ($ret !== false) { $this->attributes['time_updated'] = $time; } _elgg_cache_entity($this); // Handle cases where there was no error BUT no rows were updated! return $ret !== false; } /** * Loads attributes from the entities table into the object. * * @param mixed $guid GUID of entity or \stdClass object from entities table * * @return bool */ protected function load($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 if (!is_array($this->attributes)) { $this->attributes = array(); } // Now put these into the attributes array as core values $objarray = (array) $row; foreach ($objarray as $key => $value) { $this->attributes[$key] = $value; } // Increment the portion counter if (!$this->isFullyLoaded()) { $this->tables_loaded++; } // guid needs to be an int https://github.com/elgg/elgg/issues/4111 $this->attributes['guid'] = (int)$this->attributes['guid']; // for BC with 1.8, ->subtype always returns ID, ->getSubtype() the string $this->attributes['subtype'] = (int)$this->attributes['subtype']; // Cache object handle if ($this->attributes['guid']) { _elgg_cache_entity($this); } return true; } return false; } /** * Stores non-attributes from the loading of the entity as volatile data * * @param array $data Key value array * @return void */ protected function loadAdditionalSelectValues(array $data) { foreach ($data as $name => $value) { $this->setVolatileData("select:$name", $value); } } /** * Load new data from database into existing entity. Overwrites data but * does not change values not included in the latest data. * * @internal This is used when the same entity is selected twice during a * request in case different select clauses were used to load different data * into volatile data. * * @param \stdClass $row DB row with new entity data * @return bool * @access private */ public function refresh(\stdClass $row) { if ($row instanceof \stdClass) { return $this->load($row); } return false; } /** * Disable this entity. * * Disabled entities are not returned by getter functions. * To enable an entity, use {@link \ElggEntity::enable()}. * * Recursively disabling an entity will disable all entities * owned or contained by the parent entity. * * You can ignore the disabled field by using {@link access_show_hidden_entities()}. * * @note Internal: Disabling an entity sets the 'enabled' column to 'no'. * * @param string $reason Optional reason * @param bool $recursive Recursively disable all contained entities? * * @return bool * @see \ElggEntity::enable() */ public function disable($reason = "", $recursive = true) { if (!$this->guid) { return false; } if (!_elgg_services()->events->trigger('disable', $this->type, $this)) { return false; } if (!$this->canEdit()) { return false; } _elgg_invalidate_cache_for_entity($this->guid); if ($reason) { $this->disable_reason = $reason; } global $CONFIG; $guid = (int)$this->guid; if ($recursive) { $hidden = access_get_show_hidden_status(); access_show_hidden_entities(true); $ia = elgg_set_ignore_access(true); $sub_entities = $this->getDatabase()->getData("SELECT * FROM {$CONFIG->dbprefix}entities WHERE ( container_guid = $guid OR owner_guid = $guid OR site_guid = $guid ) AND enabled='yes'", 'entity_row_to_elggstar'); if ($sub_entities) { foreach ($sub_entities as $e) { add_entity_relationship($e->guid, 'disabled_with', $this->guid); $e->disable($reason); } } access_show_hidden_entities($hidden); elgg_set_ignore_access($ia); } $this->disableMetadata(); $this->disableAnnotations(); $res = $this->getDatabase()->updateData("UPDATE {$CONFIG->dbprefix}entities SET enabled = 'no' WHERE guid = $guid"); if ($res) { $this->attributes['enabled'] = 'no'; _elgg_services()->events->trigger('disable:after', $this->type, $this); } return $res; } /** * Enable the entity * * @warning Disabled entities can't be loaded unless * {@link access_show_hidden_entities(true)} has been called. * * @param bool $recursive Recursively enable all entities disabled with the entity? * @see access_show_hiden_entities() * @return bool */ public function enable($recursive = true) { $guid = (int)$this->guid; if (!$guid) { return false; } if (!_elgg_services()->events->trigger('enable', $this->type, $this)) { return false; } if (!$this->canEdit()) { return false; } global $CONFIG; // Override access only visible entities $old_access_status = access_get_show_hidden_status(); access_show_hidden_entities(true); $result = $this->getDatabase()->updateData("UPDATE {$CONFIG->dbprefix}entities SET enabled = 'yes' WHERE guid = $guid"); $this->deleteMetadata('disable_reason'); $this->enableMetadata(); $this->enableAnnotations(); if ($recursive) { $disabled_with_it = elgg_get_entities_from_relationship(array( 'relationship' => 'disabled_with', 'relationship_guid' => $guid, 'inverse_relationship' => true, 'limit' => 0, )); foreach ($disabled_with_it as $e) { $e->enable(); remove_entity_relationship($e->guid, 'disabled_with', $guid); } } access_show_hidden_entities($old_access_status); if ($result) { $this->attributes['enabled'] = 'yes'; _elgg_services()->events->trigger('enable:after', $this->type, $this); } return $result; } /** * Is this entity enabled? * * @return boolean Whether this entity is enabled. */ public function isEnabled() { return $this->enabled == 'yes'; } /** * Deletes the entity. * * Removes the entity and its metadata, annotations, relationships, * river entries, and private data. * * Optionally can remove entities contained and owned by this entity. * * @warning If deleting recursively, this bypasses ownership of items contained by * the entity. That means that if the container_guid = $this->guid, the item will * be deleted regardless of who owns it. * * @param bool $recursive If true (default) then all entities which are * owned or contained by $this will also be deleted. * * @return bool */ public function delete($recursive = true) { global $CONFIG; $guid = $this->guid; if (!$guid) { return false; } // first check if we can delete this entity // NOTE: in Elgg <= 1.10.3 this was after the delete event, // which could potentially remove some content if the user didn't have access if (!$this->canDelete()) { return false; } // now trigger an event to let others know this entity is about to be deleted // so they can prevent it or take their own actions if (!_elgg_services()->events->trigger('delete', $this->type, $this)) { return false; } _elgg_invalidate_cache_for_entity($guid); // If memcache is available then delete this entry from the cache static $newentity_cache; if ((!$newentity_cache) && (is_memcache_available())) { $newentity_cache = new \ElggMemcache('new_entity_cache'); } if ($newentity_cache) { $newentity_cache->delete($guid); } // Delete contained owned and otherwise releated objects (depth first) if ($recursive) { // Temporarily overriding access controls $entity_disable_override = access_get_show_hidden_status(); access_show_hidden_entities(true); $ia = elgg_set_ignore_access(true); // @todo there was logic in the original code that ignored // entities with owner or container guids of themselves. // this should probably be prevented in \ElggEntity instead of checked for here $options = array( 'wheres' => array( "((container_guid = $guid OR owner_guid = $guid OR site_guid = $guid)" . " AND guid != $guid)" ), 'limit' => 0 ); $batch = new \ElggBatch('elgg_get_entities', $options); $batch->setIncrementOffset(false); foreach ($batch as $e) { $e->delete(true); } access_show_hidden_entities($entity_disable_override); elgg_set_ignore_access($ia); } $entity_disable_override = access_get_show_hidden_status(); access_show_hidden_entities(true); $ia = elgg_set_ignore_access(true); // Now delete the entity itself $this->deleteMetadata(); $this->deleteOwnedMetadata(); $this->deleteAnnotations(); $this->deleteOwnedAnnotations(); $this->deleteRelationships(); $this->deleteAccessCollectionMemberships(); $this->deleteOwnedAccessCollections(); access_show_hidden_entities($entity_disable_override); elgg_set_ignore_access($ia); elgg_delete_river(array('subject_guid' => $guid)); elgg_delete_river(array('object_guid' => $guid)); elgg_delete_river(array('target_guid' => $guid)); remove_all_private_settings($guid); $res = $this->getDatabase()->deleteData("DELETE FROM {$CONFIG->dbprefix}entities WHERE guid = $guid"); if ($res) { $sub_table = ""; // Where appropriate delete the sub table switch ($this->type) { case 'object' : $sub_table = $CONFIG->dbprefix . 'objects_entity'; break; case 'user' : $sub_table = $CONFIG->dbprefix . 'users_entity'; break; case 'group' : $sub_table = $CONFIG->dbprefix . 'groups_entity'; break; case 'site' : $sub_table = $CONFIG->dbprefix . 'sites_entity'; break; } if ($sub_table) { $this->getDatabase()->deleteData("DELETE FROM $sub_table WHERE guid = $guid"); } } _elgg_clear_entity_files($this); return (bool)$res; } /** * {@inheritdoc} */ public function toObject() { $object = $this->prepareObject(new \stdClass()); $params = array('entity' => $this); $object = _elgg_services()->hooks->trigger('to:object', 'entity', $params, $object); return $object; } /** * Prepare an object copy for toObject() * * @param \stdClass $object Object representation of the entity * @return \stdClass */ protected function prepareObject($object) { $object->guid = $this->guid; $object->type = $this->getType(); $object->subtype = $this->getSubtype(); $object->owner_guid = $this->getOwnerGUID(); $object->container_guid = $this->getContainerGUID(); $object->site_guid = (int)$this->site_guid; $object->time_created = date('c', $this->getTimeCreated()); $object->time_updated = date('c', $this->getTimeUpdated()); $object->url = $this->getURL(); $object->read_access = (int)$this->access_id; return $object; } /* * LOCATABLE INTERFACE */ /** * Gets the 'location' metadata for the entity * * @return string The location */ public function getLocation() { return $this->location; } /** * Sets the 'location' metadata for the entity * * @param string $location String representation of the location * * @return void */ public function setLocation($location) { $this->location = $location; } /** * Set latitude and longitude metadata tags for a given entity. * * @param float $lat Latitude * @param float $long Longitude * * @return void * @todo Unimplemented */ public function setLatLong($lat, $long) { $this->{"geo:lat"} = $lat; $this->{"geo:long"} = $long; } /** * Return the entity's latitude. * * @return float * @todo Unimplemented */ public function getLatitude() { return (float)$this->{"geo:lat"}; } /** * Return the entity's longitude * * @return float * @todo Unimplemented */ public function getLongitude() { return (float)$this->{"geo:long"}; } /* * NOTABLE INTERFACE */ /** * Set the time and duration of an object * * @param int $hour If ommitted, now is assumed. * @param int $minute If ommitted, now is assumed. * @param int $second If ommitted, now is assumed. * @param int $day If ommitted, now is assumed. * @param int $month If ommitted, now is assumed. * @param int $year If ommitted, now is assumed. * @param int $duration Duration of event, remainder of the day is assumed. * * @return true * @deprecated 1.9 */ public function setCalendarTimeAndDuration($hour = null, $minute = null, $second = null, $day = null, $month = null, $year = null, $duration = null) { elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9); $start = mktime($hour, $minute, $second, $month, $day, $year); $end = $start + abs($duration); if (!$duration) { $end = get_day_end($day, $month, $year); } $this->calendar_start = $start; $this->calendar_end = $end; return true; } /** * Returns the start timestamp. * * @return int * @deprecated 1.9 */ public function getCalendarStartTime() { elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9); return (int)$this->calendar_start; } /** * Returns the end timestamp. * * @return int * @deprecated 1.9 */ public function getCalendarEndTime() { elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9); return (int)$this->calendar_end; } /* * EXPORTABLE INTERFACE */ /** * Returns an array of fields which can be exported. * * @return array * @deprecated 1.9 Use toObject() */ public function getExportableValues() { elgg_deprecated_notice(__METHOD__ . ' has been deprecated by toObject()', 1.9); return array( 'guid', 'type', 'subtype', 'time_created', 'time_updated', 'container_guid', 'owner_guid', 'site_guid' ); } /** * Export this class into an array of ODD Elements containing all necessary fields. * Override if you wish to return more information than can be found in * $this->attributes (shouldn't happen) * * @return array * @deprecated 1.9 */ public function export() { elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9); $tmp = array(); // Generate uuid $uuid = guid_to_uuid($this->getGUID()); // Create entity $odd = new ODDEntity( $uuid, $this->attributes['type'], get_subtype_from_id($this->attributes['subtype']) ); $tmp[] = $odd; $exportable_values = $this->getExportableValues(); // Now add its attributes foreach ($this->attributes as $k => $v) { $meta = null; 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 'time_created': // Created = published $odd->setAttribute('published', date("r", $v)); break; case 'site_guid': // Container $k = 'site_uuid'; $v = guid_to_uuid($v); $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); break; case 'container_guid': // Container $k = 'container_uuid'; $v = guid_to_uuid($v); $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); break; 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; default: $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); } // set the time of any metadata created if ($meta) { $meta->setAttribute('published', date("r", $this->time_created)); $tmp[] = $meta; } } } // Now we do something a bit special. /* * This provides a rendered view of the entity to foreign sites. */ elgg_set_viewtype('default'); $view = elgg_view_entity($this, array('full_view' => true)); elgg_set_viewtype(); $tmp[] = new ODDMetaData($uuid . "volatile/renderedentity/", $uuid, 'renderedentity', $view, 'volatile'); return $tmp; } /* * IMPORTABLE INTERFACE */ /** * Import data from an parsed ODD xml data array. * * @param ODD $data XML data * * @return true * * @throws InvalidParameterException * @deprecated 1.9 Use toObject() */ public function import(ODD $data) { elgg_deprecated_notice(__METHOD__ . ' has been deprecated', 1.9); if (!($data instanceof ODDEntity)) { throw new \InvalidParameterException("import() passed an unexpected ODD class"); } // Set type and subtype $this->attributes['type'] = $data->getAttribute('class'); $this->attributes['subtype'] = $data->getAttribute('subclass'); // Set owner $this->attributes['owner_guid'] = _elgg_services()->session->getLoggedInUserGuid(); // Import as belonging to importer. // Set time $this->attributes['time_created'] = strtotime($data->getAttribute('published')); $this->attributes['time_updated'] = time(); return true; } /* * SYSTEM LOG INTERFACE */ /** * Return an identification for the object for storage in the system log. * This id must be an integer. * * @return int */ public function getSystemLogID() { return $this->getGUID(); } /** * For a given ID, return the object associated with it. * This is used by the system log. It can be called on any Loggable object. * * @param int $id GUID. * @return int GUID */ public function getObjectFromID($id) { return get_entity($id); } /** * Returns tags for this entity. * * @warning Tags must be registered by {@link elgg_register_tag_metadata_name()}. * * @param array $tag_names Optionally restrict by tag metadata names. * * @return array */ public function getTags($tag_names = null) { if ($tag_names && !is_array($tag_names)) { $tag_names = array($tag_names); } $valid_tags = elgg_get_registered_tag_metadata_names(); $entity_tags = array(); foreach ($valid_tags as $tag_name) { if (is_array($tag_names) && !in_array($tag_name, $tag_names)) { continue; } if ($tags = $this->$tag_name) { // if a single tag, metadata returns a string. // if multiple tags, metadata returns an array. if (is_array($tags)) { $entity_tags = array_merge($entity_tags, $tags); } else { $entity_tags[] = $tags; } } } return $entity_tags; } /** * Remove the membership of all access collections for this entity (if the entity is a user) * * @return bool * @since 1.11 */ public function deleteAccessCollectionMemberships() { if (!$this->guid) { return false; } if ($this->type !== 'user') { return true; } $ac = _elgg_services()->accessCollections; $collections = $ac->getCollectionsByMember($this->guid); if (empty($collections)) { return true; } $result = true; foreach ($collections as $collection) { $result = $result & $ac->removeUser($this->guid, $collection->id); } return $result; } /** * Remove all access collections owned by this entity * * @return bool * @since 1.11 */ public function deleteOwnedAccessCollections() { if (!$this->guid) { return false; } $ac = _elgg_services()->accessCollections; $collections = $ac->getEntityCollections($this->guid); if (empty($collections)) { return true; } $result = true; foreach ($collections as $collection) { $result = $result & $ac->delete($collection->id); } return $result; } }