From 76dac45ebaf104b312a8527a05424601ca9d520a Mon Sep 17 00:00:00 2001 From: ewinslow Date: Mon, 6 Sep 2010 02:42:09 +0000 Subject: Refs #2220: Pulled most classes / interfaces out of lib files (except query.php and exception.php) into "classes" folder. Replaced inline classes with "require_once" statements for now. Ran unit tests to verify functionality before committing. git-svn-id: http://code.elgg.org/elgg/trunk@6908 36083f99-b078-4883-b0ff-0f9b5a30f544 --- engine/classes/CronException.php | 3 + engine/classes/ElggAccess.php | 32 + engine/classes/ElggAnnotation.php | 107 +++ engine/classes/ElggCache.php | 164 ++++ engine/classes/ElggDiskFilestore.php | 263 ++++++ engine/classes/ElggEntity.php | 1210 ++++++++++++++++++++++++++++ engine/classes/ElggExtender.php | 252 ++++++ engine/classes/ElggFile.php | 318 ++++++++ engine/classes/ElggFileCache.php | 164 ++++ engine/classes/ElggFilestore.php | 115 +++ engine/classes/ElggGroup.php | 299 +++++++ engine/classes/ElggHMACCache.php | 94 +++ engine/classes/ElggMemcache.php | 151 ++++ engine/classes/ElggMetadata.php | 114 +++ engine/classes/ElggObject.php | 199 +++++ engine/classes/ElggPlugin.php | 56 ++ engine/classes/ElggRelationship.php | 287 +++++++ engine/classes/ElggSession.php | 95 +++ engine/classes/ElggSharedMemoryCache.php | 34 + engine/classes/ElggSite.php | 299 +++++++ engine/classes/ElggStaticVariableCache.php | 66 ++ engine/classes/ElggUser.php | 427 ++++++++++ engine/classes/ElggWidget.php | 53 ++ engine/classes/ErrorResult.php | 44 + engine/classes/ExportException.php | 9 + engine/classes/Exportable.php | 21 + engine/classes/Friendable.php | 83 ++ engine/classes/GenericResult.php | 107 +++ engine/classes/ImportException.php | 8 + engine/classes/Importable.php | 16 + engine/classes/Locatable.php | 36 + engine/classes/Loggable.php | 49 ++ engine/classes/Notable.php | 30 + engine/classes/ODD.php | 94 +++ engine/classes/ODDDocument.php | 129 +++ engine/classes/ODDEntity.php | 60 ++ engine/classes/SuccessResult.php | 22 + engine/classes/XMLRPCArrayParameter.php | 48 ++ engine/classes/XMLRPCBase64Parameter.php | 24 + engine/classes/XMLRPCBoolParameter.php | 20 + engine/classes/XMLRPCCall.php | 60 ++ engine/classes/XMLRPCDateParameter.php | 27 + engine/classes/XMLRPCDoubleParameter.php | 19 + engine/classes/XMLRPCErrorResponse.php | 34 + engine/classes/XMLRPCIntParameter.php | 19 + engine/classes/XMLRPCParameter.php | 12 + engine/classes/XMLRPCResponse.php | 29 + engine/classes/XMLRPCStringParameter.php | 20 + engine/classes/XMLRPCStructParameter.php | 49 ++ engine/classes/XMLRPCSuccessResponse.php | 19 + engine/classes/XmlElement.php | 19 + 51 files changed, 5909 insertions(+) create mode 100644 engine/classes/CronException.php create mode 100644 engine/classes/ElggAccess.php create mode 100644 engine/classes/ElggAnnotation.php create mode 100644 engine/classes/ElggCache.php create mode 100644 engine/classes/ElggDiskFilestore.php create mode 100644 engine/classes/ElggEntity.php create mode 100644 engine/classes/ElggExtender.php create mode 100644 engine/classes/ElggFile.php create mode 100644 engine/classes/ElggFileCache.php create mode 100644 engine/classes/ElggFilestore.php create mode 100644 engine/classes/ElggGroup.php create mode 100644 engine/classes/ElggHMACCache.php create mode 100644 engine/classes/ElggMemcache.php create mode 100644 engine/classes/ElggMetadata.php create mode 100644 engine/classes/ElggObject.php create mode 100644 engine/classes/ElggPlugin.php create mode 100644 engine/classes/ElggRelationship.php create mode 100644 engine/classes/ElggSession.php create mode 100644 engine/classes/ElggSharedMemoryCache.php create mode 100644 engine/classes/ElggSite.php create mode 100644 engine/classes/ElggStaticVariableCache.php create mode 100644 engine/classes/ElggUser.php create mode 100644 engine/classes/ElggWidget.php create mode 100644 engine/classes/ErrorResult.php create mode 100644 engine/classes/ExportException.php create mode 100644 engine/classes/Exportable.php create mode 100644 engine/classes/Friendable.php create mode 100644 engine/classes/GenericResult.php create mode 100644 engine/classes/ImportException.php create mode 100644 engine/classes/Importable.php create mode 100644 engine/classes/Locatable.php create mode 100644 engine/classes/Loggable.php create mode 100644 engine/classes/Notable.php create mode 100644 engine/classes/ODD.php create mode 100644 engine/classes/ODDDocument.php create mode 100644 engine/classes/ODDEntity.php create mode 100644 engine/classes/SuccessResult.php create mode 100644 engine/classes/XMLRPCArrayParameter.php create mode 100644 engine/classes/XMLRPCBase64Parameter.php create mode 100644 engine/classes/XMLRPCBoolParameter.php create mode 100644 engine/classes/XMLRPCCall.php create mode 100644 engine/classes/XMLRPCDateParameter.php create mode 100644 engine/classes/XMLRPCDoubleParameter.php create mode 100644 engine/classes/XMLRPCErrorResponse.php create mode 100644 engine/classes/XMLRPCIntParameter.php create mode 100644 engine/classes/XMLRPCParameter.php create mode 100644 engine/classes/XMLRPCResponse.php create mode 100644 engine/classes/XMLRPCStringParameter.php create mode 100644 engine/classes/XMLRPCStructParameter.php create mode 100644 engine/classes/XMLRPCSuccessResponse.php create mode 100644 engine/classes/XmlElement.php (limited to 'engine/classes') diff --git a/engine/classes/CronException.php b/engine/classes/CronException.php new file mode 100644 index 000000000..3720c2c59 --- /dev/null +++ b/engine/classes/CronException.php @@ -0,0 +1,3 @@ +ignore_access; + } + + /** + * Set ignore access. + * + * @param $ignore bool true || false to ignore + * @return bool Previous setting + */ + public function set_ignore_access($ignore = true) { + $prev = $this->ignore_access; + $this->ignore_access = $ignore; + + return $prev; + } +} \ No newline at end of file diff --git a/engine/classes/ElggAnnotation.php b/engine/classes/ElggAnnotation.php new file mode 100644 index 000000000..fe85ca082 --- /dev/null +++ b/engine/classes/ElggAnnotation.php @@ -0,0 +1,107 @@ + + */ +class ElggAnnotation extends ElggExtender { + + /** + * Construct a new annotation, optionally from a given id value or db object. + * + * @param mixed $id + */ + function __construct($id = null) { + $this->attributes = array(); + + if (!empty($id)) { + if ($id instanceof stdClass) { + $annotation = $id; + } else { + $annotation = get_annotation($id); + } + + if ($annotation) { + $objarray = (array) $annotation; + + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + + $this->attributes['type'] = "annotation"; + } + } + } + + /** + * Class member get overloading + * + * @param string $name + * @return mixed + */ + function __get($name) { + return $this->get($name); + } + + /** + * Class member set overloading + * + * @param string $name + * @param mixed $value + * @return void + */ + function __set($name, $value) { + return $this->set($name, $value); + } + + /** + * Save this instance + * + * @return int an object id + */ + function save() { + if ($this->id > 0) { + return update_annotation($this->id, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id); + } else { + $this->id = create_annotation($this->entity_guid, $this->name, $this->value, + $this->value_type, $this->owner_guid, $this->access_id); + + if (!$this->id) { + throw new IOException(sprintf(elgg_echo('IOException:UnableToSaveNew'), get_class())); + } + return $this->id; + } + } + + /** + * Delete the annotation. + */ + function delete() { + return delete_annotation($this->id); + } + + /** + * Get a url for this annotation. + * + * @return string + */ + public function getURL() { + return get_annotation_url($this->id); + } + + // SYSTEM LOG INTERFACE //////////////////////////////////////////////////////////// + + /** + * For a given ID, return the object associated with it. + * This is used by the river functionality primarily. + * This is useful for checking access permissions etc on objects. + */ + public function getObjectFromID($id) { + return get_annotation($id); + } +} \ No newline at end of file diff --git a/engine/classes/ElggCache.php b/engine/classes/ElggCache.php new file mode 100644 index 000000000..c59285467 --- /dev/null +++ b/engine/classes/ElggCache.php @@ -0,0 +1,164 @@ + + * @package Elgg + * @subpackage API + */ +abstract class ElggCache implements + // Override for array access + ArrayAccess { + /** + * Variables for the cache object. + * + * @var array + */ + private $variables; + + /** + * Set the constructor. + */ + function __construct() { + $this->variables = array(); + } + + /** + * Set a cache variable. + * + * @param string $variable + * @param string $value + */ + public function set_variable($variable, $value) { + if (!is_array($this->variables)) { + $this->variables = array(); + } + + $this->variables[$variable] = $value; + } + + /** + * Get variables for this cache. + * + * @param string $variable + * @return mixed The variable or null; + */ + public function get_variable($variable) { + if (isset($this->variables[$variable])) { + return $this->variables[$variable]; + } + + return null; + } + + /** + * Class member get overloading, returning key using $this->load defaults. + * + * @param string $key + * @return mixed + */ + function __get($key) { + return $this->load($key); + } + + /** + * Class member set overloading, setting a key using $this->save defaults. + * + * @param string $key + * @param mixed $value + * @return mixed + */ + function __set($key, $value) { + return $this->save($key, $value); + } + + /** + * Supporting isset, using $this->load() with default values. + * + * @param string $key The name of the attribute or metadata. + * @return bool + */ + function __isset($key) { + return (bool)$this->load($key); + } + + /** + * Supporting unsetting of magic attributes. + * + * @param string $key The name of the attribute or metadata. + */ + function __unset($key) { + return $this->delete($key); + } + + /** + * Save data in a cache. + * + * @param string $key + * @param string $data + * @return bool + */ + abstract public function save($key, $data); + + /** + * Load data from the cache using a given key. + * + * @param string $key + * @param int $offset + * @param int $limit + * @return mixed The stored data or false. + */ + abstract public function load($key, $offset = 0, $limit = null); + + /** + * Invalidate a key + * + * @param string $key + * @return bool + */ + abstract public function delete($key); + + /** + * Clear out all the contents of the cache. + * + */ + abstract public function clear(); + + /** + * Add a key only if it doesn't already exist. + * Implemented simply here, if you extend this class and your caching engine provides a better way then + * override this accordingly. + * + * @param string $key + * @param string $data + * @return bool + */ + public function add($key, $data) { + if (!isset($this[$key])) { + return $this->save($key, $data); + } + + return false; + } + + // ARRAY ACCESS INTERFACE ////////////////////////////////////////////////////////// + function offsetSet($key, $value) { + $this->save($key, $value); + } + + function offsetGet($key) { + return $this->load($key); + } + + function offsetUnset($key) { + if ( isset($this->key) ) { + unset($this->key); + } + } + + function offsetExists($offset) { + return isset($this->$offset); + } +} \ No newline at end of file diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php new file mode 100644 index 000000000..6b0fa2554 --- /dev/null +++ b/engine/classes/ElggDiskFilestore.php @@ -0,0 +1,263 @@ +dir_root = $directory_root; + } else { + $this->dir_root = $CONFIG->dataroot; + } + } + + public function open(ElggFile $file, $mode) { + $fullname = $this->getFilenameOnFilestore($file); + + // Split into path and name + $ls = strrpos($fullname,"/"); + if ($ls===false) { + $ls = 0; + } + + $path = substr($fullname, 0, $ls); + $name = substr($fullname, $ls); + + // Try and create the directory + try { + $this->make_directory_root($path); + } catch (Exception $e) { + + } + + if (($mode!='write') && (!file_exists($fullname))) { + return false; + } + + switch ($mode) { + case "read" : + $mode = "rb"; + break; + case "write" : + $mode = "w+b"; + break; + case "append" : + $mode = "a+b"; + break; + default: + throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:UnrecognisedFileMode'), $mode)); + } + + return fopen($fullname, $mode); + + } + + public function write($f, $data) { + return fwrite($f, $data); + } + + public function read($f, $length, $offset = 0) { + if ($offset) { + $this->seek($f, $offset); + } + + return fread($f, $length); + } + + public function close($f) { + return fclose($f); + } + + public function delete(ElggFile $file) { + $filename = $this->getFilenameOnFilestore($file); + if (file_exists($filename)) { + return unlink($filename); + } else { + return true; + } + } + + public function seek($f, $position) { + return fseek($f, $position); + } + + public function tell($f) { + return ftell($f); + } + + public function eof($f) { + return feof($f); + } + + public function getFileSize(ElggFile $file) { + return filesize($this->getFilenameOnFilestore($file)); + } + + public function getFilenameOnFilestore(ElggFile $file) { + $owner = $file->getOwnerEntity(); + if (!$owner) { + $owner = get_loggedin_user(); + } + + if ((!$owner) || (!$owner->username)) { + throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:MissingOwner'), $file->getFilename(), $file->guid)); + } + + return $this->dir_root . $this->make_file_matrix($owner->guid) . $file->getFilename(); + } + + public function grabFile(ElggFile $file) { + return file_get_contents($file->getFilenameOnFilestore()); + } + + public function exists(ElggFile $file) { + return file_exists($this->getFilenameOnFilestore($file)); + } + + public function getSize($prefix,$container_guid) { + if ($container_guid) { + return get_dir_size($this->dir_root.$this->make_file_matrix($container_guid).$prefix); + } else { + return false; + } + } + + /** + * Make the directory root. + * + * @param string $dirroot + */ + protected function make_directory_root($dirroot) { + if (!file_exists($dirroot)) { + if (!@mkdir($dirroot, 0700, true)) { + throw new IOException(sprintf(elgg_echo('IOException:CouldNotMake'), $dirroot)); + } + } + + return true; + } + + /** + * Multibyte string tokeniser. + * + * Splits a string into an array. Will fail safely if mbstring is not installed (although this may still + * not handle . + * + * @param string $string String + * @param string $charset The charset, defaults to UTF8 + * @return array + */ + private function mb_str_split($string, $charset = 'UTF8') { + if (is_callable('mb_substr')) { + $length = mb_strlen($string); + $array = array(); + + while ($length) { + $array[] = mb_substr($string, 0, 1, $charset); + $string = mb_substr($string, 1, $length, $charset); + + $length = mb_strlen($string); + } + + return $array; + } else { + return str_split($string); + } + + return false; + } + + /** + * Construct the filename matrix. + * + * @param int | string $identifier + * @return str + */ + protected function make_file_matrix($identifier) { + if (is_numeric($identifier)) { + return $this->user_file_matrix($identifier); + } + + return $this->deprecated_file_matrix($identifier); + } + + /** + * Construct the filename matrix with user info + * + * This method will generate a matrix using the entity's creation time and + * unique guid. This is intended only to determine a user's data directory. + * + * @param int $guid + * @return str + */ + protected function user_file_matrix($guid) { + // lookup the entity + $user = get_entity($guid); + if ($user->type != 'user') + { + // only to be used for user directories + return FALSE; + } + + if (!$user->time_created) { + // fall back to deprecated method + return $this->deprecated_file_matrix($user->username); + } + + $time_created = date('Y/m/d', $user->time_created); + return "$time_created/$user->guid/"; + } + + /** + * Construct the filename matrix using a string + * + * Particularly, this is used with a username to generate the file storage + * location. + * + * @deprecated for user directories: use user_file_matrix() instead. + * + * @param str $filename + * @return str + */ + protected function deprecated_file_matrix($filename) { + // throw a warning for using deprecated method + $error = 'Deprecated use of ElggDiskFilestore::make_file_matrix. '; + $error .= 'Username passed instead of guid.'; + elgg_log($error, WARNING); + + $user = new ElggUser($filename); + return $this->user_file_matrix($user->guid); + } + + public function getParameters() { + return array("dir_root" => $this->dir_root); + } + + public function setParameters(array $parameters) { + if (isset($parameters['dir_root'])) { + $this->dir_root = $parameters['dir_root']; + return true; + } + + return false; + } +} diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php new file mode 100644 index 000000000..f0d58d1bd --- /dev/null +++ b/engine/classes/ElggEntity.php @@ -0,0 +1,1210 @@ + + * @package Elgg + * @subpackage Core + */ +abstract class ElggEntity implements + Notable, // Calendar interface + Locatable, // Geocoding interface + Exportable, // Allow export of data + Importable, // Allow import of data + Loggable, // Can events related to this object class be logged + Iterator, // Override foreach behaviour + ArrayAccess // Override for array access +{ + /** + * The main attributes of an entity. + * Blank entries for all database fields should be created by the constructor. + * Subclasses should add to this in their constructors. + * Any field not appearing in this will be viewed as a + */ + protected $attributes; + + /** + * If set, overrides the value of getURL() + */ + protected $url_override; + + /** + * Icon override, overrides the value of getIcon(). + */ + protected $icon_override; + + /** + * Temporary cache for metadata, permitting meta data access before a guid has obtained. + */ + protected $temp_metadata; + + /** + * Temporary cache for annotations, permitting meta data access before a guid has obtained. + */ + protected $temp_annotations; + + + /** + * Volatile data structure for this object, allows for storage of data + * in-memory that isn't sync'd back to the metadata table. + */ + protected $volatile; + + /** + * Initialise the attributes array. + * This is vital to distinguish between metadata and base parameters. + * + * Place your base parameters here. + * + * @return void + */ + protected function initialise_attributes() { + initialise_entity_cache(); + + // Create attributes array if not already created + if (!is_array($this->attributes)) { + $this->attributes = array(); + } + if (!is_array($this->temp_metadata)) { + $this->temp_metadata = array(); + } + if (!is_array($this->temp_annotations)) { + $this->temp_annotations = array(); + } + if (!is_array($this->volatile)) { + $this->volatile = array(); + } + + $this->attributes['guid'] = ""; + $this->attributes['type'] = ""; + $this->attributes['subtype'] = ""; + + $this->attributes['owner_guid'] = get_loggedin_userid(); + $this->attributes['container_guid'] = get_loggedin_userid(); + + $this->attributes['site_guid'] = 0; + $this->attributes['access_id'] = ACCESS_PRIVATE; + $this->attributes['time_created'] = ""; + $this->attributes['time_updated'] = ""; + $this->attributes['last_action'] = ''; + $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->attributes['tables_split'] = 1; + $this->attributes['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 over 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. + */ + public function __clone() { + + $orig_entity = get_entity($this->guid); + if (!$orig_entity) { + elgg_log("Failed to clone entity with GUID $this->guid", "ERROR"); + return; + } + + $metadata_array = get_metadata_for_entity($this->guid); + + $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); + } + } + } + + /** + * Return the value of a given key. + * If $name is a key field (as defined in $this->attributes) that value is returned, otherwise it will + * then look to see if the value is in this object's metadata. + * + * Q: Why are we not using __get overload here? + * A: Because overload operators cause problems during subclassing, so we put the code here and + * create overloads in subclasses. + * + * subtype is returned as an id rather than the subtype string. Use getSubtype() + * to get the subtype string. + * + * @param string $name + * @return mixed Returns the value of a given value, or null. + */ + public function get($name) { + // See if its in our base attribute + if (isset($this->attributes[$name])) { + return $this->attributes[$name]; + } + + // No, so see if its in the meta data for this entity + $meta = $this->getMetaData($name); + + // getMetaData returns NULL if $name is not found + return $meta; + } + + /** + * Set the value of a given key, replacing it if necessary. + * If $name is a base attribute (as defined in $this->attributes) that value is set, otherwise it will + * set the appropriate item of metadata. + * + * Note: It is important that your class populates $this->attributes with keys for all base attributes, anything + * not in their gets set as METADATA. + * + * Q: Why are we not using __set overload here? + * A: Because overload operators cause problems during subclassing, so we put the code here and + * create overloads in subclasses. + * + * @param string $name + * @param mixed $value + */ + public function set($name, $value) { + if (array_key_exists($name, $this->attributes)) { + // Certain properties should not be manually changed! + switch ($name) { + case 'guid': + case 'time_created': + case 'time_updated': + case 'last_action': + return FALSE; + break; + default: + $this->attributes[$name] = $value; + break; + } + } else { + return $this->setMetaData($name, $value); + } + + return TRUE; + } + + /** + * Get a given piece of metadata. + * + * @param string $name + */ + public function getMetaData($name) { + if ((int) ($this->guid) > 0) { + $md = get_metadata_byname($this->getGUID(), $name); + } else { + if (isset($this->temp_metadata[$name])) { + return $this->temp_metadata[$name]; + } + } + + if ($md && !is_array($md)) { + return $md->value; + } else if ($md && is_array($md)) { + return metadata_array_to_values($md); + } + + return null; + } + + /** + * Class member get overloading + * + * @param string $name + * @return mixed + */ + function __get($name) { + return $this->get($name); + } + + /** + * Class member set overloading + * + * @param string $name + * @param mixed $value + * @return mixed + */ + function __set($name, $value) { + return $this->set($name, $value); + } + + /** + * Supporting isset. + * + * @param string $name The name of the attribute or metadata. + * @return bool + */ + function __isset($name) { + return $this->$name !== NULL; + } + + /** + * Supporting unsetting of magic attributes. + * + * @param string $name The name of the attribute or metadata. + */ + function __unset($name) { + if (array_key_exists($name, $this->attributes)) { + $this->attributes[$name] = ""; + } + else { + $this->clearMetaData($name); + } + } + + /** + * Set a piece of metadata. + * + * @param string $name Name of the metadata + * @param mixed $value Value of the metadata + * @param string $value_type Types supported: integer and string. Will auto-identify if not set + * @param bool $multiple (does not support associative arrays) + * @return bool + */ + public function setMetaData($name, $value, $value_type = "", $multiple = false) { + 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; + } + } + } + + 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; + } + + return true; + } + } + } + + /** + * Clear metadata. + */ + public function clearMetaData($name = "") { + if (empty($name)) { + return clear_metadata($this->getGUID()); + } else { + return remove_metadata($this->getGUID(),$name); + } + } + + + /** + * Get a piece of volatile (non-persisted) data on this entity + */ + 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 + */ + public function setVolatileData($name, $value) { + if (!is_array($this->volatile)) { + $this->volatile = array(); + } + + $this->volatile[$name] = $value; + } + + + /** + * Remove all entities associated with this entity + * + * @return true + */ + public function clearRelationships() { + remove_entity_relationships($this->getGUID()); + remove_entity_relationships($this->getGUID(),"",true); + return true; + } + + /** + * Add a relationship. + * + * @param int $guid Relationship to link to. + * @param string $relationship The type of relationship. + * @return bool + */ + public function addRelationship($guid, $relationship) { + return add_entity_relationship($this->getGUID(), $relationship, $guid); + } + + /** + * Remove a relationship + * + * @param int $guid + * @param str $relationship + * @return bool + */ + public function removeRelationship($guid, $relationship) { + return remove_entity_relationship($this->getGUID(), $relationship, $guid); + } + + /** + * Adds a private setting to this entity. + * + * @param $name + * @param $value + * @return unknown_type + */ + function setPrivateSetting($name, $value) { + return set_private_setting($this->getGUID(), $name, $value); + } + + /** + * Gets private setting for this entity + * + * @param $name + * @return unknown_type + */ + function getPrivateSetting($name) { + return get_private_setting($this->getGUID(), $name); + } + + /** + * Removes private setting for this entity. + * + * @param $name + * @return unknown_type + */ + function removePrivateSetting($name) { + return remove_private_setting($this->getGUID(), $name); + } + + /** + * Adds an annotation to an entity. By default, the type is detected automatically; however, + * it can also be set. Note that by default, annotations are private. + * + * @param string $name + * @param mixed $value + * @param int $access_id + * @param int $owner_id + * @param string $vartype + */ + function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_id = 0, $vartype = "") { + if ((int) $this->guid > 0) { + return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_id, $access_id); + } else { + $this->temp_annotations[$name] = $value; + } + return true; + } + + /** + * Get the annotations for an entity. + * + * @param string $name + * @param int $limit + * @param int $offset + * @param string $order + */ + function getAnnotations($name, $limit = 50, $offset = 0, $order="asc") { + if ((int) ($this->guid) > 0) { + return get_annotations($this->getGUID(), "", "", $name, "", 0, $limit, $offset, $order); + } else { + return $this->temp_annotations[$name]; + } + } + + /** + * Remove all annotations or all annotations for this entity. + * + * @param string $name + */ + function clearAnnotations($name = "") { + return clear_annotations($this->getGUID(), $name); + } + + /** + * Return the annotations for the entity. + * + * @param string $name The type of annotation. + */ + function countAnnotations($name = "") { + return count_annotations($this->getGUID(), "", "", $name); + } + + /** + * Get the average of an integer type annotation. + * + * @param string $name + */ + function getAnnotationsAvg($name) { + return get_annotations_avg($this->getGUID(), "", "", $name); + } + + /** + * Get the sum of integer type annotations of a given name. + * + * @param string $name + */ + function getAnnotationsSum($name) { + return get_annotations_sum($this->getGUID(), "", "", $name); + } + + /** + * Get the minimum of integer type annotations of given name. + * + * @param string $name + */ + function getAnnotationsMin($name) { + return get_annotations_min($this->getGUID(), "", "", $name); + } + + /** + * Get the maximum of integer type annotations of a given name. + * + * @param string $name + */ + function getAnnotationsMax($name) { + return get_annotations_max($this->getGUID(), "", "", $name); + } + + /** + * Gets an array of entities from a specific relationship type + * + * @param string $relationship Relationship type (eg "friends") + * @param true|false $inverse Is this an inverse relationship? + * @param int $limit Number of elements to return + * @param int $offset Indexing offset + * @return array|false An array of entities or false on failure + */ + function getEntitiesFromRelationship($relationship, $inverse = false, $limit = 50, $offset = 0) { + return elgg_get_entities_from_relationship(array( + 'relationship' => $relationship, + 'relationship_guid' => $this->getGUID(), + 'inverse_relationship' => $inverse, + 'limit' => $limit, + 'offset' => $offset + )); + } + + /** + * Gets the number of of entities from a specific relationship type + * + * @param string $relationship Relationship type (eg "friends") + * @param bool $inverse_relationship + * @return int|false The number of entities or false on failure + */ + 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 + )); + } + + /** + * Determines whether or not the specified user (by default the current one) can edit the entity + * + * @param int $user_guid The user GUID, optionally (defaults to the currently logged in user) + * @return true|false + */ + function canEdit($user_guid = 0) { + return can_edit_entity($this->getGUID(), $user_guid); + } + + /** + * Determines whether or not the specified user (by default the current one) can edit metadata on the entity + * + * @param ElggMetadata $metadata The piece of metadata to specifically check + * @param int $user_guid The user GUID, optionally (defaults to the currently logged in user) + * @return true|false + */ + function canEditMetadata($metadata = null, $user_guid = 0) { + return can_edit_entity_metadata($this->getGUID(), $user_guid, $metadata); + } + + /** + * Returns whether the given user (or current user) has the ability to write to this container. + * + * @param int $user_guid The user. + * @return bool + */ + public function canWriteToContainer($user_guid = 0) { + return can_write_to_container($user_guid, $this->getGUID()); + } + + /** + * Obtain this entity's access ID + * + * @return int The access ID + */ + public function getAccessID() { + return $this->get('access_id'); + } + + /** + * Obtain this entity's GUID + * + * @return int GUID + */ + public function getGUID() { + return $this->get('guid'); + } + + /** + * Get the owner of this entity + * + * @return int The owner GUID + */ + public function getOwner() { + return $this->get('owner_guid'); + } + + /** + * Returns the actual entity of the user who owns this entity, if any + * + * @return ElggEntity The owning user + */ + public function getOwnerEntity() { + return get_entity($this->get('owner_guid')); + } + + /** + * Gets the type of entity this is + * + * @return string Entity type + */ + public function getType() { + return $this->get('type'); + } + + /** + * Returns the subtype of this entity + * + * @return string The entity subtype + */ + public function getSubtype() { + // If this object hasn't been saved, then return the subtype string. + if (!((int) $this->guid > 0)) { + return $this->get('subtype'); + } + + return get_subtype_from_id($this->get('subtype')); + } + + /** + * Gets the UNIX epoch time that this entity was created + * + * @return int UNIX epoch time + */ + public function getTimeCreated() { + return $this->get('time_created'); + } + + /** + * Gets the UNIX epoch time that this entity was last updated + * + * @return int UNIX epoch time + */ + public function getTimeUpdated() { + return $this->get('time_updated'); + } + + /** + * Gets the display URL for this entity + * + * @return string The URL + */ + public function getURL() { + if (!empty($this->url_override)) { + return $this->url_override; + } + return get_entity_url($this->getGUID()); + } + + /** + * Overrides the URL returned by getURL + * + * @param string $url The new item URL + * @return string The URL + */ + public function setURL($url) { + $this->url_override = $url; + return $url; + } + + /** + * Return a url for the entity's icon, trying multiple alternatives. + * + * @param string $size Either 'large','medium','small' or 'tiny' + * @return string The url or false if no url could be worked out. + */ + public function getIcon($size = 'medium') { + if (isset($this->icon_override[$size])) { + return $this->icon_override[$size]; + } + return get_entity_icon_url($this, $size); + } + + /** + * Set an icon override for an icon and size. + * + * @param string $url The url of the icon. + * @param string $size The size its for. + * @return bool + */ + public function setIcon($url, $size = 'medium') { + $url = sanitise_string($url); + $size = sanitise_string($size); + + if (!$this->icon_override) { + $this->icon_override = array(); + } + $this->icon_override[$size] = $url; + + return true; + } + + /** + * Tests to see whether the object has been fully loaded. + * + * @return bool + */ + public function isFullyLoaded() { + return ! ($this->attributes['tables_loaded'] < $this->attributes['tables_split']); + } + + /** + * Save generic attributes to the entities table. + */ + public function save() { + $guid = (int) $this->guid; + if ($guid > 0) { + cache_entity($this); + + return update_entity( + $this->get('guid'), + $this->get('owner_guid'), + $this->get('access_id'), + $this->get('container_guid') + ); + } else { + // Create a new entity (nb: using attribute array directly 'cos set function does something special!) + $this->attributes['guid'] = create_entity($this->attributes['type'], $this->attributes['subtype'], $this->attributes['owner_guid'], $this->attributes['access_id'], $this->attributes['site_guid'], $this->attributes['container_guid']); + if (!$this->attributes['guid']) { + throw new IOException(elgg_echo('IOException:BaseEntitySaveFailed')); + } + + // Save any unsaved metadata + // @todo How to capture extra information (access id etc) + if (sizeof($this->temp_metadata) > 0) { + foreach($this->temp_metadata as $name => $value) { + $this->$name = $value; + unset($this->temp_metadata[$name]); + } + } + + // Save any unsaved annotations metadata. + // @todo How to capture extra information (access id etc) + if (sizeof($this->temp_annotations) > 0) { + foreach($this->temp_annotations as $name => $value) { + $this->annotate($name, $value); + unset($this->temp_annotations[$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); + } + + return $this->attributes['guid']; + } + } + + /** + * Load the basic entity information and populate base attributes array. + * + * @param int $guid + */ + protected function load($guid) { + $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->attributes['tables_loaded']++; + } + + // Cache object handle + if ($this->attributes['guid']) { + cache_entity($this); + } + + return true; + } + + return false; + } + + /** + * Disable this entity. + * + * @param string $reason Optional reason + * @param bool $recursive Recursively disable all contained entities? + */ + public function disable($reason = "", $recursive = true) { + return disable_entity($this->get('guid'), $reason, $recursive); + } + + /** + * Re-enable this entity. + */ + public function enable() { + return enable_entity($this->get('guid')); + } + + /** + * Is this entity enabled? + * + * @return boolean + */ + public function isEnabled() { + if ($this->enabled == 'yes') { + return true; + } + + return false; + } + + /** + * Delete this entity. + */ + public function delete() { + return delete_entity($this->get('guid')); + } + + // LOCATABLE INTERFACE ///////////////////////////////////////////////////////////// + + /** Interface to set the location */ + public function setLocation($location) { + $location = sanitise_string($location); + + $this->location = $location; + + return true; + } + + /** + * Set latitude and longitude tags for a given entity. + * + * @param float $lat + * @param float $long + */ + public function setLatLong($lat, $long) { + $lat = sanitise_string($lat); + $long = sanitise_string($long); + + $this->set('geo:lat', $lat); + $this->set('geo:long', $long); + + return true; + } + + /** + * Get the contents of the ->geo:lat field. + * + */ + public function getLatitude() { + return $this->get('geo:lat'); + } + + /** + * Get the contents of the ->geo:lat field. + * + */ + public function getLongitude() { + return $this->get('geo:long'); + } + + /** + * Get the ->location metadata. + * + */ + public function getLocation() { + return $this->get('location'); + } + + // NOTABLE INTERFACE /////////////////////////////////////////////////////////////// + + /** + * Calendar functionality. + * This function sets the time of an object on a calendar listing. + * + * @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. + */ + public function setCalendarTimeAndDuration($hour = NULL, $minute = NULL, $second = NULL, $day = NULL, $month = NULL, $year = NULL, $duration = NULL) { + $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; + } + + /** + * Return the start timestamp. + */ + public function getCalendarStartTime() { + return (int)$this->calendar_start; + } + + /** + * Return the end timestamp. + */ + public function getCalendarEndTime() { + return (int)$this->calendar_end; + } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + 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) + */ + public function export() { + $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, true); + elgg_set_viewtype(); + + $tmp[] = new ODDMetaData($uuid . "volatile/renderedentity/", $uuid, 'renderedentity', $view , 'volatile'); + + return $tmp; + } + + // IMPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Import data from an parsed xml data array. + * + * @param array $data + * @param int $version + */ + public function import(ODD $data) { + if (!($data instanceof ODDEntity)) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedODDClass')); + } + + // Set type and subtype + $this->attributes['type'] = $data->getAttribute('class'); + $this->attributes['subtype'] = $data->getAttribute('subclass'); + + // Set owner + $this->attributes['owner_guid'] = get_loggedin_userid(); // 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(); + } + + /** + * Return the class name of the object. + */ + public function getClassName() { + return get_class($this); + } + + /** + * For a given ID, return the object associated with it. + * This is used by the river functionality primarily. + * This is useful for checking access permissions etc on objects. + */ + public function getObjectFromID($id) { + return get_entity($id); + } + + /** + * Return the GUID of the owner of this object. + */ + public function getObjectOwnerGUID() { + return $this->owner_guid; + } + + /** + * Returns tags for this entity. + * + * @param array $tag_names Optionally restrict by tag metadata names. + * @return array + */ + public function getTags($tag_names = NULL) { + global $CONFIG; + + 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; + } + + // ITERATOR INTERFACE ////////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be displayed using foreach as a normal array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + private $valid = FALSE; + + function rewind() { + $this->valid = (FALSE !== reset($this->attributes)); + } + + function current() { + return current($this->attributes); + } + + function key() { + return key($this->attributes); + } + + function next() { + $this->valid = (FALSE !== next($this->attributes)); + } + + function valid() { + return $this->valid; + } + + // ARRAY ACCESS INTERFACE ////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be accessed like an associative array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + function offsetSet($key, $value) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = $value; + } + } + + function offsetGet($key) { + if ( array_key_exists($key, $this->attributes) ) { + return $this->attributes[$key]; + } + } + + function offsetUnset($key) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = ""; // Full unsetting is dangerious for our objects + } + } + + function offsetExists($offset) { + return array_key_exists($offset, $this->attributes); + } +} \ No newline at end of file diff --git a/engine/classes/ElggExtender.php b/engine/classes/ElggExtender.php new file mode 100644 index 000000000..ec7a21f35 --- /dev/null +++ b/engine/classes/ElggExtender.php @@ -0,0 +1,252 @@ +attributes[$name])) { + // Sanitise value if necessary + if ($name=='value') { + switch ($this->attributes['value_type']) { + case 'integer' : + return (int)$this->attributes['value']; + + //case 'tag' : + //case 'file' : + case 'text' : + return ($this->attributes['value']); + + default : + throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $this->attributes['value_type'])); + } + } + + return $this->attributes[$name]; + } + return null; + } + + /** + * Set an attribute + * + * @param string $name + * @param mixed $value + * @param string $value_type + * @return boolean + */ + protected function set($name, $value, $value_type = "") { + $this->attributes[$name] = $value; + if ($name == 'value') { + $this->attributes['value_type'] = detect_extender_valuetype($value, $value_type); + } + + return true; + } + + /** + * Return the owner of this annotation. + * + * @return mixed + */ + public function getOwner() { + return $this->owner_guid; + } + + /** + * Return the owner entity + * + * @return mixed + * @since 1.7.0 + */ + public function getOwnerEntity() { + return get_user($this->owner_guid); + } + + /** + * Returns the entity this is attached to + * + * @return ElggEntity The enttiy + */ + public function getEntity() { + return get_entity($this->entity_guid); + } + + /** + * Save this data to the appropriate database table. + */ + abstract public function save(); + + /** + * Delete this data. + */ + abstract public function delete(); + + /** + * Determines whether or not the specified user can edit this + * + * @param int $user_guid The GUID of the user (defaults to currently logged in user) + * @return true|false + */ + public function canEdit($user_guid = 0) { + return can_edit_extender($this->id,$this->type,$user_guid); + } + + /** + * Return a url for this extender. + * + * @return string + */ + public abstract function getURL(); + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array( + 'id', + 'entity_guid', + 'name', + 'value', + 'value_type', + 'owner_guid', + 'type', + ); + } + + /** + * Export this object + * + * @return array + */ + public function export() { + $uuid = get_uuid_from_object($this); + + $meta = new ODDMetadata($uuid, guid_to_uuid($this->entity_guid), $this->attributes['name'], $this->attributes['value'], $this->attributes['type'], guid_to_uuid($this->owner_guid)); + $meta->setAttribute('published', date("r", $this->time_created)); + + return $meta; + } + + // 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->id; + } + + /** + * Return the class name of the object. + */ + public function getClassName() { + return get_class($this); + } + + /** + * Return the GUID of the owner of this object. + */ + public function getObjectOwnerGUID() { + return $this->owner_guid; + } + + /** + * Return a type of the object - eg. object, group, user, relationship, metadata, annotation etc + */ + public function getType() { + return $this->type; + } + + /** + * Return a subtype. For metadata & annotations this is the 'name' and + * for relationship this is the relationship type. + */ + public function getSubtype() { + return $this->name; + } + + + // ITERATOR INTERFACE ////////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be displayed using foreach as a normal array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + private $valid = FALSE; + + function rewind() { + $this->valid = (FALSE !== reset($this->attributes)); + } + + function current() { + return current($this->attributes); + } + + function key() { + return key($this->attributes); + } + + function next() { + $this->valid = (FALSE !== next($this->attributes)); + } + + function valid() { + return $this->valid; + } + + // ARRAY ACCESS INTERFACE ////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be accessed like an associative array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + function offsetSet($key, $value) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = $value; + } + } + + function offsetGet($key) { + if ( array_key_exists($key, $this->attributes) ) { + return $this->attributes[$key]; + } + } + + function offsetUnset($key) { + if ( array_key_exists($key, $this->attributes) ) { + // Full unsetting is dangerious for our objects + $this->attributes[$key] = ""; + } + } + + function offsetExists($offset) { + return array_key_exists($offset, $this->attributes); + } +} diff --git a/engine/classes/ElggFile.php b/engine/classes/ElggFile.php new file mode 100644 index 000000000..68ed2f2f2 --- /dev/null +++ b/engine/classes/ElggFile.php @@ -0,0 +1,318 @@ +attributes['subtype'] = "file"; + } + + public function __construct($guid = null) { + parent::__construct($guid); + + // Set default filestore + $this->filestore = $this->getFilestore(); + } + + /** + * Set the filename of this file. + * + * @param string $name The filename. + */ + public function setFilename($name) { + $this->filename = $name; + } + + /** + * Return the filename. + */ + public function getFilename() { + return $this->filename; + } + + /** + * Return the filename of this file as it is/will be stored on the filestore, which may be different + * to the filename. + */ + public function getFilenameOnFilestore() { + return $this->filestore->getFilenameOnFilestore($this); + } + + /* + * Return the size of the filestore associated with this file + * + */ + public function getFilestoreSize($prefix='',$container_guid=0) { + if (!$container_guid) { + $container_guid = $this->container_guid; + } + $fs = $this->getFilestore(); + return $fs->getSize($prefix,$container_guid); + } + + /** + * Get the mime type of the file. + */ + public function getMimeType() { + if ($this->mimetype) { + return $this->mimetype; + } + + // @todo Guess mimetype if not here + } + + /** + * Set the mime type of the file. + * + * @param $mimetype The mimetype + */ + public function setMimeType($mimetype) { + return $this->mimetype = $mimetype; + } + + /** + * Set the optional file description. + * + * @param string $description The description. + */ + public function setDescription($description) { + $this->description = $description; + } + + /** + * Open the file with the given mode + * + * @param string $mode Either read/write/append + */ + public function open($mode) { + if (!$this->getFilename()) { + throw new IOException(elgg_echo('IOException:MissingFileName')); + } + + // See if file has already been saved + // seek on datastore, parameters and name? + + // Sanity check + if ( + ($mode!="read") && + ($mode!="write") && + ($mode!="append") + ) { + throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:UnrecognisedFileMode'), $mode)); + } + + // Get the filestore + $fs = $this->getFilestore(); + + // Ensure that we save the file details to object store + //$this->save(); + + // Open the file handle + $this->handle = $fs->open($this, $mode); + + return $this->handle; + } + + /** + * Write some data. + * + * @param string $data The data + */ + public function write($data) { + $fs = $this->getFilestore(); + + return $fs->write($this->handle, $data); + } + + /** + * Read some data. + * + * @param int $length Amount to read. + * @param int $offset The offset to start from. + */ + public function read($length, $offset = 0) { + $fs = $this->getFilestore(); + + return $fs->read($this->handle, $length, $offset); + } + + /** + * Gets the full contents of this file. + * + * @return mixed The file contents. + */ + public function grabFile() { + $fs = $this->getFilestore(); + return $fs->grabFile($this); + } + + /** + * Close the file and commit changes + */ + public function close() { + $fs = $this->getFilestore(); + + if ($fs->close($this->handle)) { + $this->handle = NULL; + + return true; + } + + return false; + } + + /** + * Delete this file. + */ + public function delete() { + $fs = $this->getFilestore(); + if ($fs->delete($this)) { + return parent::delete(); + } + } + + /** + * Seek a position in the file. + * + * @param int $position + */ + public function seek($position) { + $fs = $this->getFilestore(); + + return $fs->seek($this->handle, $position); + } + + /** + * Return the current position of the file. + * + * @return int The file position + */ + public function tell() { + $fs = $this->getFilestore(); + + return $fs->tell($this->handle); + } + + /** + * Return the size of the file in bytes. + */ + public function size() { + return $this->filestore->getFileSize($this); + } + + /** + * Return a boolean value whether the file handle is at the end of the file + */ + public function eof() { + $fs = $this->getFilestore(); + + return $fs->eof($this->handle); + } + + public function exists() { + $fs = $this->getFilestore(); + + return $fs->exists($this); + } + + /** + * Set a filestore. + * + * @param ElggFilestore $filestore The file store. + */ + public function setFilestore(ElggFilestore $filestore) { + $this->filestore = $filestore; + } + + /** + * Return a filestore suitable for saving this file. + * This filestore is either a pre-registered filestore, a filestore loaded from metatags saved + * along side this file, or the system default. + */ + protected function getFilestore() { + // Short circuit if already set. + if ($this->filestore) { + return $this->filestore; + } + + // If filestore meta set then retrieve filestore + // @todo Better way of doing this? + $metas = get_metadata_for_entity($this->guid); + $parameters = array(); + if (is_array($metas)) { + foreach ($metas as $meta) { + if (strpos($meta->name, "filestore::")!==false) { + // Filestore parameter tag + $comp = explode("::", $meta->name); + $name = $comp[1]; + + $parameters[$name] = $meta->value; + } + } + } + + if (isset($parameters['filestore'])) { + if (!class_exists($parameters['filestore'])) { + $msg = sprintf(elgg_echo('ClassNotFoundException:NotFoundNotSavedWithFile'), + $parameters['filestore'], + $this->guid); + throw new ClassNotFoundException($msg); + } + + // Create new filestore object + $this->filestore = new $parameters['filestore'](); + + $this->filestore->setParameters($parameters); + } else { + // @todo - should we log error if filestore not set + } + + + // if still nothing then set filestore to default + if (!$this->filestore) { + $this->filestore = get_default_filestore(); + } + + return $this->filestore; + } + + public function save() { + if (!parent::save()) { + return false; + } + + // Save datastore metadata + $params = $this->filestore->getParameters(); + foreach ($params as $k => $v) { + $this->setMetaData("filestore::$k", $v); + } + + // Now make a note of the filestore class + $this->setMetaData("filestore::filestore", get_class($this->filestore)); + + return true; + } +} diff --git a/engine/classes/ElggFileCache.php b/engine/classes/ElggFileCache.php new file mode 100644 index 000000000..b8989a935 --- /dev/null +++ b/engine/classes/ElggFileCache.php @@ -0,0 +1,164 @@ + + * @package Elgg + * @subpackage API + */ +class ElggFileCache extends ElggCache { + /** + * Set the Elgg cache. + * + * @param string $cache_path The cache path. + * @param int $max_age Maximum age in seconds, 0 if no limit. + * @param int $max_size Maximum size of cache in seconds, 0 if no limit. + */ + function __construct($cache_path, $max_age = 0, $max_size = 0) { + $this->set_variable("cache_path", $cache_path); + $this->set_variable("max_age", $max_age); + $this->set_variable("max_size", $max_size); + + if ($cache_path=="") { + throw new ConfigurationException(elgg_echo('ConfigurationException:NoCachePath')); + } + } + + /** + * Create and return a handle to a file. + * + * @param string $filename + * @param string $rw + */ + protected function create_file($filename, $rw = "rb") { + // Create a filename matrix + $matrix = ""; + $depth = strlen($filename); + if ($depth > 5) { + $depth = 5; + } + + // Create full path + $path = $this->get_variable("cache_path") . $matrix; + if (!is_dir($path)) { + mkdir($path, 0700, true); + } + + // Open the file + if ((!file_exists($path . $filename)) && ($rw=="rb")) { + return false; + } + + return fopen($path . $filename, $rw); + } + + /** + * Create a sanitised filename for the file. + * + * @param string $filename + */ + protected function sanitise_filename($filename) { + // @todo : Writeme + + return $filename; + } + + /** + * Save a key + * + * @param string $key + * @param string $data + * @return boolean + */ + public function save($key, $data) { + $f = $this->create_file($this->sanitise_filename($key), "wb"); + if ($f) { + $result = fwrite($f, $data); + fclose($f); + + return $result; + } + + return false; + } + + /** + * Load a key + * + * @param string $key + * @param int $offset + * @param int $limit + * @return string + */ + public function load($key, $offset = 0, $limit = null) { + $f = $this->create_file($this->sanitise_filename($key)); + if ($f) { + //fseek($f, $offset); + if (!$limit) { + $limit = -1; + } + $data = stream_get_contents($f, $limit, $offset); + + fclose($f); + + return $data; + } + + return false; + } + + /** + * Invalidate a given key. + * + * @param string $key + * @return bool + */ + public function delete($key) { + $dir = $this->get_variable("cache_path"); + + if (file_exists($dir.$key)) { + return unlink($dir.$key); + } + return TRUE; + } + + public function clear() { + // @todo writeme + } + + public function __destruct() { + // @todo Check size and age, clean up accordingly + $size = 0; + $dir = $this->get_variable("cache_path"); + + // Short circuit if both size and age are unlimited + if (($this->get_variable("max_age")==0) && ($this->get_variable("max_size")==0)) { + return; + } + + $exclude = array(".",".."); + + $files = scandir($dir); + if (!$files) { + throw new IOException(sprintf(elgg_echo('IOException:NotDirectory'), $dir)); + } + + // Perform cleanup + foreach ($files as $f) { + if (!in_array($f, $exclude)) { + $stat = stat($dir.$f); + + // Add size + $size .= $stat['size']; + + // Is this older than my maximum date? + if (($this->get_variable("max_age")>0) && (time() - $stat['mtime'] > $this->get_variable("max_age"))) { + unlink($dir.$f); + } + + // @todo Size + } + } + } +} \ No newline at end of file diff --git a/engine/classes/ElggFilestore.php b/engine/classes/ElggFilestore.php new file mode 100644 index 000000000..3311842a9 --- /dev/null +++ b/engine/classes/ElggFilestore.php @@ -0,0 +1,115 @@ +getParameters(). + */ + abstract public function setParameters(array $parameters); + + /** + * Get the contents of the whole file. + * + * @param mixed $file The file handle. + * @return mixed The file contents. + */ + abstract public function grabFile(ElggFile $file); + + /** + * Return whether a file physically exists or not. + * + * @param ElggFile $file + */ + abstract public function exists(ElggFile $file); +} \ No newline at end of file diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php new file mode 100644 index 000000000..9713ca39e --- /dev/null +++ b/engine/classes/ElggGroup.php @@ -0,0 +1,299 @@ +attributes['type'] = "group"; + $this->attributes['name'] = ""; + $this->attributes['description'] = ""; + $this->attributes['tables_split'] = 2; + } + + /** + * Construct a new user entity, optionally from a given id value. + * + * @param mixed $guid If an int, load that GUID. + * If a db row then will attempt to load the rest of the data. + * @throws Exception if there was a problem creating the user. + */ + function __construct($guid = null) { + $this->initialise_attributes(); + + if (!empty($guid)) { + // Is $guid is a DB row - either a entity row, or a user table row. + if ($guid instanceof stdClass) { + // Load the rest + if (!$this->load($guid->guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid)); + } + } + // Is $guid is an ElggGroup? Use a copy constructor + else if ($guid instanceof ElggGroup) { + elgg_deprecated_notice('This type of usage of the ElggGroup constructor was deprecated. Please use the clone method.', 1.7); + + foreach ($guid->attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + // Is this is an ElggEntity but not an ElggGroup = ERROR! + else if ($guid instanceof ElggEntity) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggGroup')); + } + // We assume if we have got this far, $guid is an int + else if (is_numeric($guid)) { + if (!$this->load($guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid)); + } + } + + else { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue')); + } + } + } + + /** + * Add an ElggObject to this group. + * + * @param ElggObject $object The object. + * @return bool + */ + public function addObjectToGroup(ElggObject $object) { + return add_object_to_group($this->getGUID(), $object->getGUID()); + } + + /** + * Remove an object from the containing group. + * + * @param int $guid The guid of the object. + * @return bool + */ + public function removeObjectFromGroup($guid) { + return remove_object_from_group($this->getGUID(), $guid); + } + + public function get($name) { + if ($name == 'username') { + return 'group:' . $this->getGUID(); + } + return parent::get($name); + } + +/** + * Start friendable compatibility block: + * + * public function addFriend($friend_guid); + public function removeFriend($friend_guid); + public function isFriend(); + public function isFriendsWith($user_guid); + public function isFriendOf($user_guid); + public function getFriends($subtype = "", $limit = 10, $offset = 0); + public function getFriendsOf($subtype = "", $limit = 10, $offset = 0); + public function getObjects($subtype="", $limit = 10, $offset = 0); + public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0); + public function countObjects($subtype = ""); + */ + + /** + * For compatibility with Friendable + */ + public function addFriend($friend_guid) { + return $this->join(get_entity($friend_guid)); + } + + /** + * For compatibility with Friendable + */ + public function removeFriend($friend_guid) { + return $this->leave(get_entity($friend_guid)); + } + + /** + * For compatibility with Friendable + */ + public function isFriend() { + return $this->isMember(); + } + + /** + * For compatibility with Friendable + */ + public function isFriendsWith($user_guid) { + return $this->isMember($user_guid); + } + + /** + * For compatibility with Friendable + */ + public function isFriendOf($user_guid) { + return $this->isMember($user_guid); + } + + /** + * For compatibility with Friendable + */ + public function getFriends($subtype = "", $limit = 10, $offset = 0) { + return get_group_members($this->getGUID(), $limit, $offset); + } + + /** + * For compatibility with Friendable + */ + public function getFriendsOf($subtype = "", $limit = 10, $offset = 0) { + return get_group_members($this->getGUID(), $limit, $offset); + } + + /** + * Get objects contained in this group. + * + * @param string $subtype + * @param int $limit + * @param int $offset + * @return mixed + */ + public function getObjects($subtype="", $limit = 10, $offset = 0) { + return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", $limit, $offset, false); + } + + /** + * For compatibility with Friendable + */ + public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0) { + return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", $limit, $offset, false); + } + + /** + * For compatibility with Friendable + */ + public function countObjects($subtype = "") { + return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", 10, 0, true); + } + +/** + * End friendable compatibility block + */ + + /** + * Get a list of group members. + * + * @param int $limit + * @param int $offset + * @return mixed + */ + public function getMembers($limit = 10, $offset = 0, $count = false) { + return get_group_members($this->getGUID(), $limit, $offset, 0 , $count); + } + + /** + * Returns whether the current group is public membership or not. + * @return bool + */ + public function isPublicMembership() { + if ($this->membership == ACCESS_PUBLIC) { + return true; + } + + return false; + } + + /** + * Return whether a given user is a member of this group or not. + * + * @param ElggUser $user The user + * @return bool + */ + public function isMember($user = 0) { + if (!($user instanceof ElggUser)) { + $user = get_loggedin_user(); + } + if (!($user instanceof ElggUser)) { + return false; + } + return is_group_member($this->getGUID(), $user->getGUID()); + } + + /** + * Join an elgg user to this group. + * + * @param ElggUser $user + * @return bool + */ + public function join(ElggUser $user) { + return join_group($this->getGUID(), $user->getGUID()); + } + + /** + * Remove a user from the group. + * + * @param ElggUser $user + */ + public function leave(ElggUser $user) { + return leave_group($this->getGUID(), $user->getGUID()); + } + + /** + * Override the load function. + * This function will ensure that all data is loaded (were possible), so + * if only part of the ElggGroup is loaded, it'll load the rest. + * + * @param int $guid + */ + protected function load($guid) { + // Test to see if we have the generic stuff + if (!parent::load($guid)) { + return false; + } + + // Check the type + if ($this->attributes['type']!='group') { + throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class())); + } + + // Load missing data + $row = get_group_entity_as_row($guid); + if (($row) && (!$this->isFullyLoaded())) { + // If $row isn't a cached copy then increment the counter + $this->attributes['tables_loaded'] ++; + } + + // Now put these into the attributes array as core values + $objarray = (array) $row; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + + return true; + } + + /** + * Override the save function. + */ + public function save() { + // Save generic stuff + if (!parent::save()) { + return false; + } + + // Now save specific stuff + return create_group_entity($this->get('guid'), $this->get('name'), $this->get('description')); + } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array_merge(parent::getExportableValues(), array( + 'name', + 'description', + )); + } +} \ No newline at end of file diff --git a/engine/classes/ElggHMACCache.php b/engine/classes/ElggHMACCache.php new file mode 100644 index 000000000..8c50d7dfb --- /dev/null +++ b/engine/classes/ElggHMACCache.php @@ -0,0 +1,94 @@ + + * @package Elgg + * @subpackage API + */ +class ElggHMACCache extends ElggCache { + /** + * Set the Elgg cache. + * + * @param int $max_age Maximum age in seconds, 0 if no limit. + */ + function __construct($max_age = 0) { + $this->set_variable("max_age", $max_age); + } + + /** + * Save a key + * + * @param string $key + * @param string $data + * @return boolean + */ + public function save($key, $data) { + global $CONFIG; + + $key = sanitise_string($key); + $time = time(); + + return insert_data("INSERT into {$CONFIG->dbprefix}hmac_cache (hmac, ts) VALUES ('$key', '$time')"); + } + + /** + * Load a key + * + * @param string $key + * @param int $offset + * @param int $limit + * @return string + */ + public function load($key, $offset = 0, $limit = null) { + global $CONFIG; + + $key = sanitise_string($key); + + $row = get_data_row("SELECT * from {$CONFIG->dbprefix}hmac_cache where hmac='$key'"); + if ($row) { + return $row->hmac; + } + + return false; + } + + /** + * Invalidate a given key. + * + * @param string $key + * @return bool + */ + public function delete($key) { + global $CONFIG; + + $key = sanitise_string($key); + + return delete_data("DELETE from {$CONFIG->dbprefix}hmac_cache where hmac='$key'"); + } + + /** + * Clear out all the contents of the cache. + * + * Not currently implemented in this cache type. + */ + public function clear() { + return true; + } + + /** + * Clean out old stuff. + * + */ + public function __destruct() { + global $CONFIG; + + $time = time(); + $age = (int)$this->get_variable("max_age"); + + $expires = $time-$age; + + delete_data("DELETE from {$CONFIG->dbprefix}hmac_cache where ts<$expires"); + } +} \ No newline at end of file diff --git a/engine/classes/ElggMemcache.php b/engine/classes/ElggMemcache.php new file mode 100644 index 000000000..5e898c26a --- /dev/null +++ b/engine/classes/ElggMemcache.php @@ -0,0 +1,151 @@ + + */ +class ElggMemcache extends ElggSharedMemoryCache { + /** + * Minimum version of memcached needed to run + * + */ + private static $MINSERVERVERSION = '1.1.12'; + + /** + * Memcache object + */ + private $memcache; + + /** + * Expiry of saved items (default timeout after a day to prevent anything getting too stale) + */ + private $expires = 86400; + + /** + * The version of memcache running + */ + private $version = 0; + + /** + * Connect to memcache. + * + * @param string $cache_id The namespace for this cache to write to - note, namespaces of the same name are shared! + */ + function __construct($namespace = 'default') { + global $CONFIG; + + $this->setNamespace($namespace); + + // Do we have memcache? + if (!class_exists('Memcache')) { + throw new ConfigurationException(elgg_echo('memcache:notinstalled')); + } + + // Create memcache object + $this->memcache = new Memcache; + + // Now add servers + if (!$CONFIG->memcache_servers) { + throw new ConfigurationException(elgg_echo('memcache:noservers')); + } + + if (is_callable($this->memcache, 'addServer')) { + foreach ($CONFIG->memcache_servers as $server) { + if (is_array($server)) { + $this->memcache->addServer( + $server[0], + isset($server[1]) ? $server[1] : 11211, + isset($server[2]) ? $server[2] : true, + isset($server[3]) ? $server[3] : null, + isset($server[4]) ? $server[4] : 1, + isset($server[5]) ? $server[5] : 15, + isset($server[6]) ? $server[6] : true + ); + + } else { + $this->memcache->addServer($server, 11211); + } + } + } else { + elgg_log(elgg_echo('memcache:noaddserver'), 'ERROR'); + + $server = $CONFIG->memcache_servers[0]; + if (is_array($server)) { + $this->memcache->connect($server[0], $server[1]); + } else { + $this->memcache->addServer($server, 11211); + } + } + + // Get version + $this->version = $this->memcache->getversion(); + if (version_compare($this->version, ElggMemcache::$MINSERVERVERSION, '<')) { + throw new ConfigurationException(sprintf(elgg_echo('memcache:versiontoolow'), ElggMemcache::$MINSERVERVERSION, $this->version)); + } + + // Set some defaults + if (isset($CONFIG->memcache_expires)) { + $this->expires = $CONFIG->memcache_expires; + } + } + + /** + * Set the default expiry. + * + * @param int $expires The lifetime as a unix timestamp or time from now. Defaults forever. + */ + public function setDefaultExpiry($expires = 0) { + $this->expires = $expires; + } + + /** + * Combine a key with the namespace. + * Memcache can only accept <250 char key. If the given key is too long it is shortened. + * + * @param string $key The key + * @return string The new key. + */ + private function make_memcache_key($key) { + $prefix = $this->getNamespace() . ":"; + + if (strlen($prefix.$key)> 250) { + $key = md5($key); + } + + return $prefix.$key; + } + + public function save($key, $data) { + $key = $this->make_memcache_key($key); + + $result = $this->memcache->set($key, $data, null, $this->expires); + if (!$result) { + elgg_log("MEMCACHE: FAILED TO SAVE $key", 'ERROR'); + } + + return $result; + } + + public function load($key, $offset = 0, $limit = null) { + $key = $this->make_memcache_key($key); + + $result = $this->memcache->get($key); + if (!$result) { + elgg_log("MEMCACHE: FAILED TO LOAD $key", 'ERROR'); + } + + return $result; + } + + public function delete($key) { + $key = $this->make_memcache_key($key); + + return $this->memcache->delete($key, 0); + } + + public function clear() { + // DISABLE clearing for now - you must use delete on a specific key. + return true; + + // @todo Namespaces as in #532 + } +} diff --git a/engine/classes/ElggMetadata.php b/engine/classes/ElggMetadata.php new file mode 100644 index 000000000..631b73c8f --- /dev/null +++ b/engine/classes/ElggMetadata.php @@ -0,0 +1,114 @@ + + * @package Elgg + * @subpackage Core + */ +class ElggMetadata extends ElggExtender { + /** + * Construct a new site object, optionally from a given id value or row. + * + * @param mixed $id + */ + function __construct($id = null) { + $this->attributes = array(); + + if (!empty($id)) { + // Create from db row + if ($id instanceof stdClass) { + $metadata = $id; + } else { + $metadata = get_metadata($id); + } + + if ($metadata) { + $objarray = (array) $metadata; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + $this->attributes['type'] = "metadata"; + } + } + } + + /** + * Class member get overloading + * + * @param string $name + * @return mixed + */ + function __get($name) { + return $this->get($name); + } + + /** + * Class member set overloading + * + * @param string $name + * @param mixed $value + * @return mixed + */ + function __set($name, $value) { + return $this->set($name, $value); + } + + /** + * Determines whether or not the user can edit this piece of metadata + * + * @return true|false Depending on permissions + */ + function canEdit() { + if ($entity = get_entity($this->get('entity_guid'))) { + return $entity->canEditMetadata($this); + } + return false; + } + + /** + * Save matadata object + * + * @return int the metadata object id + */ + function save() { + if ($this->id > 0) { + return update_metadata($this->id, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id); + } else { + $this->id = create_metadata($this->entity_guid, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id); + if (!$this->id) { + throw new IOException(sprintf(elgg_echo('IOException:UnableToSaveNew'), get_class())); + } + return $this->id; + } + } + + /** + * Delete a given metadata. + */ + function delete() { + return delete_metadata($this->id); + } + + /** + * Get a url for this item of metadata. + * + * @return string + */ + public function getURL() { + return get_metadata_url($this->id); + } + + // SYSTEM LOG INTERFACE //////////////////////////////////////////////////////////// + + /** + * For a given ID, return the object associated with it. + * This is used by the river functionality primarily. + * This is useful for checking access permissions etc on objects. + */ + public function getObjectFromID($id) { + return get_metadata($id); + } +} \ No newline at end of file diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php new file mode 100644 index 000000000..af67ef3f6 --- /dev/null +++ b/engine/classes/ElggObject.php @@ -0,0 +1,199 @@ +attributes['type'] = "object"; + $this->attributes['title'] = ""; + $this->attributes['description'] = ""; + $this->attributes['tables_split'] = 2; + } + + /** + * Construct a new object entity, optionally from a given id value. + * + * @param mixed $guid If an int, load that GUID. + * If a db row then will attempt to load the rest of the data. + * @throws Exception if there was a problem creating the object. + */ + function __construct($guid = null) { + $this->initialise_attributes(); + + if (!empty($guid)) { + // Is $guid is a DB row - either a entity row, or a object table row. + if ($guid instanceof stdClass) { + // Load the rest + if (!$this->load($guid->guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid)); + } + } + + // Is $guid is an ElggObject? Use a copy constructor + else if ($guid instanceof ElggObject) { + elgg_deprecated_notice('This type of usage of the ElggObject constructor was deprecated. Please use the clone method.', 1.7); + + foreach ($guid->attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + + // Is this is an ElggEntity but not an ElggObject = ERROR! + else if ($guid instanceof ElggEntity) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggObject')); + } + + // We assume if we have got this far, $guid is an int + else if (is_numeric($guid)) { + if (!$this->load($guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid)); + } + } + + else { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue')); + } + } + } + + /** + * Override the load function. + * This function will ensure that all data is loaded (were possible), so + * if only part of the ElggObject is loaded, it'll load the rest. + * + * @param int $guid + * @return true|false + */ + protected function load($guid) { + // Test to see if we have the generic stuff + if (!parent::load($guid)) { + return false; + } + + // Check the type + if ($this->attributes['type']!='object') { + throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class())); + } + + // Load missing data + $row = get_object_entity_as_row($guid); + if (($row) && (!$this->isFullyLoaded())) { + // If $row isn't a cached copy then increment the counter + $this->attributes['tables_loaded'] ++; + } + + // Now put these into the attributes array as core values + $objarray = (array) $row; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + + return true; + } + + /** + * Override the save function. + * @return true|false + */ + public function save() { + // Save generic stuff + if (!parent::save()) { + return false; + } + + // Now save specific stuff + return create_object_entity($this->get('guid'), $this->get('title'), $this->get('description'), $this->get('container_guid')); + } + + /** + * Get sites that this object is a member of + * + * @param string $subtype Optionally, the subtype of result we want to limit to + * @param int $limit The number of results to return + * @param int $offset Any indexing offset + */ + function getSites($subtype="", $limit = 10, $offset = 0) { + return get_site_objects($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Add this object to a particular site + * + * @param int $site_guid The guid of the site to add it to + * @return true|false + */ + function addToSite($site_guid) { + return add_site_object($this->getGUID(), $site_guid); + } + + /** + * Set the container for this object. + * + * @param int $container_guid The ID of the container. + * @return bool + */ + function setContainer($container_guid) { + $container_guid = (int)$container_guid; + + return $this->set('container_guid', $container_guid); + } + + /** + * Return the container GUID of this object. + * + * @return int + */ + function getContainer() { + return $this->get('container_guid'); + } + + /** + * As getContainer(), but returns the whole entity. + * + * @return mixed ElggGroup object or false. + */ + function getContainerEntity() { + $result = get_entity($this->getContainer()); + + if (($result) && ($result instanceof ElggGroup)) { + return $result; + } + + return false; + } + + /** + * Get the collections associated with a object. + * + * @param string $subtype Optionally, the subtype of result we want to limit to + * @param int $limit The number of results to return + * @param int $offset Any indexing offset + * @return unknown + */ + //public function getCollections($subtype="", $limit = 10, $offset = 0) { get_object_collections($this->getGUID(), $subtype, $limit, $offset); } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array_merge(parent::getExportableValues(), array( + 'title', + 'description', + )); + } +} \ No newline at end of file diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php new file mode 100644 index 000000000..921665f4d --- /dev/null +++ b/engine/classes/ElggPlugin.php @@ -0,0 +1,56 @@ +attributes['subtype'] = "plugin"; + } + + public function __construct($guid = null) { + parent::__construct($guid); + } + + /** + * Override entity get and sets in order to save data to private data store. + */ + public function get($name) { + // See if its in our base attribute + if (isset($this->attributes[$name])) { + return $this->attributes[$name]; + } + + // No, so see if its in the private data store. + // get_private_setting() returns false if it doesn't exist + $meta = get_private_setting($this->guid, $name); + + if ($meta === false) { + // Can't find it, so return null + return NULL; + } + + return $meta; + } + + /** + * Override entity get and sets in order to save data to private data store. + */ + public function set($name, $value) { + if (array_key_exists($name, $this->attributes)) { + // Check that we're not trying to change the guid! + if ((array_key_exists('guid', $this->attributes)) && ($name=='guid')) { + return false; + } + + $this->attributes[$name] = $value; + } else { + return set_private_setting($this->guid, $name, $value); + } + + return true; + } +} \ No newline at end of file diff --git a/engine/classes/ElggRelationship.php b/engine/classes/ElggRelationship.php new file mode 100644 index 000000000..4d14941a9 --- /dev/null +++ b/engine/classes/ElggRelationship.php @@ -0,0 +1,287 @@ +attributes = array(); + + if (!empty($id)) { + if ($id instanceof stdClass) { + $relationship = $id; // Create from db row + } else { + $relationship = get_relationship($id); + } + + if ($relationship) { + $objarray = (array) $relationship; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + } + } + } + + /** + * Class member get overloading + * + * @param string $name + * @return mixed + */ + function __get($name) { + if (isset($this->attributes[$name])) { + return $this->attributes[$name]; + } + + return null; + } + + /** + * Class member set overloading + * + * @param string $name + * @param mixed $value + * @return mixed + */ + function __set($name, $value) { + $this->attributes[$name] = $value; + return true; + } + + /** + * Save the relationship + * + * @return int the relationship id + */ + public function save() { + if ($this->id > 0) { + delete_relationship($this->id); + } + + $this->id = add_entity_relationship($this->guid_one, $this->relationship, $this->guid_two); + if (!$this->id) { + throw new IOException(sprintf(elgg_echo('IOException:UnableToSaveNew'), get_class())); + } + + return $this->id; + } + + /** + * Delete a given relationship. + */ + public function delete() { + return delete_relationship($this->id); + } + + /** + * Get a URL for this relationship. + * + * @return string + */ + public function getURL() { + return get_relationship_url($this->id); + } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array( + 'id', + 'guid_one', + 'relationship', + 'guid_two' + ); + } + + /** + * Export this relationship + * + * @return array + */ + public function export() { + $uuid = get_uuid_from_object($this); + $relationship = new ODDRelationship( + guid_to_uuid($this->guid_one), + $this->relationship, + guid_to_uuid($this->guid_two) + ); + + $relationship->setAttribute('uuid', $uuid); + + return $relationship; + } + + // IMPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Import a relationship + * + * @param array $data + * @param int $version + * @return ElggRelationship + * @throws ImportException + */ + public function import(ODD $data) { + if (!($element instanceof ODDRelationship)) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedODDClass')); + } + + $uuid_one = $data->getAttribute('uuid1'); + $uuid_two = $data->getAttribute('uuid2'); + + // See if this entity has already been imported, if so then we need to link to it + $entity1 = get_entity_from_uuid($uuid_one); + $entity2 = get_entity_from_uuid($uuid_two); + if (($entity1) && ($entity2)) { + // Set the item ID + $this->attributes['guid_one'] = $entity1->getGUID(); + $this->attributes['guid_two'] = $entity2->getGUID(); + + // Map verb to relationship + //$verb = $data->getAttribute('verb'); + //$relationship = get_relationship_from_verb($verb); + $relationship = $data->getAttribute('type'); + + if ($relationship) { + $this->attributes['relationship'] = $relationship; + // save + $result = $this->save(); + if (!$result) { + throw new ImportException(sprintf(elgg_echo('ImportException:ProblemSaving'), get_class())); + } + + return $this; + } + } + } + + // 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->id; + } + + /** + * Return the class name of the object. + */ + public function getClassName() { + return get_class($this); + } + + /** + * For a given ID, return the object associated with it. + * This is used by the river functionality primarily. + * This is useful for checking access permissions etc on objects. + */ + public function getObjectFromID($id) { + return get_relationship($id); + } + + /** + * Return the GUID of the owner of this object. + */ + public function getObjectOwnerGUID() { + return $this->owner_guid; + } + + /** + * Return a type of the object - eg. object, group, user, relationship, metadata, annotation etc + */ + public function getType() { + return 'relationship'; + } + + /** + * Return a subtype. For metadata & annotations this is the 'name' and for relationship this is the relationship type. + */ + public function getSubtype() { + return $this->relationship; + } + + // ITERATOR INTERFACE ////////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be displayed using foreach as a normal array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + private $valid = FALSE; + + function rewind() { + $this->valid = (FALSE !== reset($this->attributes)); + } + + function current() { + return current($this->attributes); + } + + function key() { + return key($this->attributes); + } + + function next() { + $this->valid = (FALSE !== next($this->attributes)); + } + + function valid() { + return $this->valid; + } + + // ARRAY ACCESS INTERFACE ////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be accessed like an associative array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + function offsetSet($key, $value) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = $value; + } + } + + function offsetGet($key) { + if ( array_key_exists($key, $this->attributes) ) { + return $this->attributes[$key]; + } + } + + function offsetUnset($key) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = ""; // Full unsetting is dangerious for our objects + } + } + + function offsetExists($offset) { + return array_key_exists($offset, $this->attributes); + } +} \ No newline at end of file diff --git a/engine/classes/ElggSession.php b/engine/classes/ElggSession.php new file mode 100644 index 000000000..874502579 --- /dev/null +++ b/engine/classes/ElggSession.php @@ -0,0 +1,95 @@ +offsetExists($key); + } + + /** Set a value, go straight to session. */ + function offsetSet($key, $value) { + $_SESSION[$key] = $value; + } + + /** + * Get a variable from either the session, or if its not in the session attempt to get it from + * an api call. + */ + function offsetGet($key) { + if (!ElggSession::$__localcache) { + ElggSession::$__localcache = array(); + } + + if (isset($_SESSION[$key])) { + return $_SESSION[$key]; + } + + if (isset(ElggSession::$__localcache[$key])) { + return ElggSession::$__localcache[$key]; + } + + $value = NULL; + $value = trigger_plugin_hook('session:get', $key, NULL, $value); + + ElggSession::$__localcache[$key] = $value; + + return ElggSession::$__localcache[$key]; + } + + /** + * Unset a value from the cache and the session. + */ + function offsetUnset($key) { + unset(ElggSession::$__localcache[$key]); + unset($_SESSION[$key]); + } + + /** + * Return whether the value is set in either the session or the cache. + */ + function offsetExists($offset) { + if (isset(ElggSession::$__localcache[$offset])) { + return true; + } + + if (isset($_SESSION[$offset])) { + return true; + } + + if ($this->offsetGet($offset)){ + return true; + } + } + + + // Alias functions + function get($key) { + return $this->offsetGet($key); + } + + function set($key, $value) { + return $this->offsetSet($key, $value); + } + + function del($key) { + return $this->offsetUnset($key); + } +} \ No newline at end of file diff --git a/engine/classes/ElggSharedMemoryCache.php b/engine/classes/ElggSharedMemoryCache.php new file mode 100644 index 000000000..cae78943e --- /dev/null +++ b/engine/classes/ElggSharedMemoryCache.php @@ -0,0 +1,34 @@ +namespace = $namespace; + } + + /** + * Get the namespace currently defined. + * + * @return string + */ + public function getNamespace() { + return $this->namespace; + } +} \ No newline at end of file diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php new file mode 100644 index 000000000..77e26372e --- /dev/null +++ b/engine/classes/ElggSite.php @@ -0,0 +1,299 @@ + + * @package Elgg + * @subpackage Core + */ +class ElggSite extends ElggEntity { + /** + * Initialise the attributes array. + * This is vital to distinguish between metadata and base parameters. + * + * Place your base parameters here. + */ + protected function initialise_attributes() { + parent::initialise_attributes(); + + $this->attributes['type'] = "site"; + $this->attributes['name'] = ""; + $this->attributes['description'] = ""; + $this->attributes['url'] = ""; + $this->attributes['tables_split'] = 2; + } + + /** + * Construct a new site object, optionally from a given id value. + * + * @param mixed $guid If an int, load that GUID. + * If a db row then will attempt to load the rest of the data. + * @throws Exception if there was a problem creating the site. + */ + function __construct($guid = null) { + $this->initialise_attributes(); + + if (!empty($guid)) { + // Is $guid is a DB row - either a entity row, or a site table row. + if ($guid instanceof stdClass) { + // Load the rest + if (!$this->load($guid->guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid)); + } + } + + // Is $guid is an ElggSite? Use a copy constructor + else if ($guid instanceof ElggSite) { + elgg_deprecated_notice('This type of usage of the ElggSite constructor was deprecated. Please use the clone method.', 1.7); + + foreach ($guid->attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + + // Is this is an ElggEntity but not an ElggSite = ERROR! + else if ($guid instanceof ElggEntity) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggSite')); + } + + // See if this is a URL + else if (strpos($guid, "http") !== false) { + $guid = get_site_by_url($guid); + foreach ($guid->attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + + // We assume if we have got this far, $guid is an int + else if (is_numeric($guid)) { + if (!$this->load($guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid)); + } + } + + else { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue')); + } + } + } + + /** + * Override the load function. + * This function will ensure that all data is loaded (were possible), so + * if only part of the ElggSite is loaded, it'll load the rest. + * + * @param int $guid + */ + protected function load($guid) { + // Test to see if we have the generic stuff + if (!parent::load($guid)) { + return false; + } + + // Check the type + if ($this->attributes['type']!='site') { + throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class())); + } + + // Load missing data + $row = get_site_entity_as_row($guid); + if (($row) && (!$this->isFullyLoaded())) { + // If $row isn't a cached copy then increment the counter + $this->attributes['tables_loaded'] ++; + } + + // Now put these into the attributes array as core values + $objarray = (array) $row; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + + return true; + } + + /** + * Override the save function. + */ + public function save() { + // Save generic stuff + if (!parent::save()) { + return false; + } + + // Now save specific stuff + return create_site_entity($this->get('guid'), $this->get('name'), $this->get('description'), $this->get('url')); + } + + /** + * Delete this site. + */ + public function delete() { + global $CONFIG; + if ($CONFIG->site->getGUID() == $this->guid) { + throw new SecurityException('SecurityException:deletedisablecurrentsite'); + } + + return parent::delete(); + } + + /** + * Disable override to add safety rail. + * + * @param unknown_type $reason + */ + public function disable($reason = "") { + global $CONFIG; + + if ($CONFIG->site->getGUID() == $this->guid) { + throw new SecurityException('SecurityException:deletedisablecurrentsite'); + } + + return parent::disable($reason); + } + + /** + * Return a list of users using this site. + * + * @param int $limit + * @param int $offset + * @return array of ElggUsers + */ + public function getMembers($limit = 10, $offset = 0) { + get_site_members($this->getGUID(), $limit, $offset); + } + + /** + * Add a user to the site. + * + * @param int $user_guid + */ + public function addUser($user_guid) { + return add_site_user($this->getGUID(), $user_guid); + } + + /** + * Remove a site user. + * + * @param int $user_guid + */ + public function removeUser($user_guid) { + return remove_site_user($this->getGUID(), $user_guid); + } + + /** + * Get an array of member ElggObjects. + * + * @param string $subtype + * @param int $limit + * @param int $offset + */ + public function getObjects($subtype="", $limit = 10, $offset = 0) { + get_site_objects($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Add an object to the site. + * + * @param int $user_id + */ + public function addObject($object_guid) { + return add_site_object($this->getGUID(), $object_guid); + } + + /** + * Remove a site user. + * + * @param int $user_id + */ + public function removeObject($object_guid) { + return remove_site_object($this->getGUID(), $object_guid); + } + + /** + * Get the collections associated with a site. + * + * @param string $type + * @param int $limit + * @param int $offset + * @return unknown + */ + public function getCollections($subtype="", $limit = 10, $offset = 0) { + get_site_collections($this->getGUID(), $subtype, $limit, $offset); + } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array_merge(parent::getExportableValues(), array( + 'name', + 'description', + 'url', + )); + } + + public function check_walled_garden() { + global $CONFIG; + + if ($CONFIG->walled_garden && !isloggedin()) { + // hook into the index system call at the highest priority + register_plugin_hook('index', 'system', 'elgg_walled_garden_index', 1); + + if (!$this->is_public_page()) { + register_error(elgg_echo('loggedinrequired')); + forward(); + } + } + } + + public function is_public_page($url='') { + global $CONFIG; + + if (empty($url)) { + $url = current_page_url(); + + // do not check against URL queries + if ($pos = strpos($url, '?')) { + $url = substr($url, 0, $pos); + } + } + + // always allow index page + if ($url == $CONFIG->url) { + return TRUE; + } + + // default public pages + $defaults = array( + 'action/login', + 'pg/register', + 'action/register', + 'account/forgotten_password\.php', + 'action/user/requestnewpassword', + 'pg/resetpassword', + 'upgrade\.php', + 'xml-rpc\.php', + 'mt/mt-xmlrpc\.cgi', + '_css/css\.css', + '_css/js\.php', + ); + + // include a hook for plugin authors to include public pages + $plugins = trigger_plugin_hook('public_pages', 'walled_garden', NULL, array()); + + // lookup admin-specific public pages + + // allow public pages + foreach (array_merge($defaults, $plugins) as $public) { + $pattern = "`^{$CONFIG->url}$public/*$`i"; + if (preg_match($pattern, $url)) { + return TRUE; + } + } + + // non-public page + return FALSE; + } +} diff --git a/engine/classes/ElggStaticVariableCache.php b/engine/classes/ElggStaticVariableCache.php new file mode 100644 index 000000000..0038862bd --- /dev/null +++ b/engine/classes/ElggStaticVariableCache.php @@ -0,0 +1,66 @@ + + * @package Elgg + * @subpackage API + */ +class ElggStaticVariableCache extends ElggSharedMemoryCache { + /** + * The cache. + * + * @var unknown_type + */ + private static $__cache; + + /** + * Create the variable cache. + * + * This function creates a variable cache in a static variable in memory, optionally with a given namespace (to avoid overlap). + * + * @param string $namespace The namespace for this cache to write to - note, namespaces of the same name are shared! + */ + function __construct($namespace = 'default') { + $this->setNamespace($namespace); + $this->clear(); + } + + public function save($key, $data) { + $namespace = $this->getNamespace(); + + ElggStaticVariableCache::$__cache[$namespace][$key] = $data; + + return true; + } + + public function load($key, $offset = 0, $limit = null) { + $namespace = $this->getNamespace(); + + if (isset(ElggStaticVariableCache::$__cache[$namespace][$key])) { + return ElggStaticVariableCache::$__cache[$namespace][$key]; + } + + return false; + } + + public function delete($key) { + $namespace = $this->getNamespace(); + + unset(ElggStaticVariableCache::$__cache[$namespace][$key]); + + return true; + } + + public function clear() { + $namespace = $this->getNamespace(); + + if (!isset(ElggStaticVariableCache::$__cache)) { + ElggStaticVariableCache::$__cache = array(); + } + + ElggStaticVariableCache::$__cache[$namespace] = array(); + } +} \ No newline at end of file diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php new file mode 100644 index 000000000..001da19ed --- /dev/null +++ b/engine/classes/ElggUser.php @@ -0,0 +1,427 @@ +attributes['type'] = "user"; + $this->attributes['name'] = ""; + $this->attributes['username'] = ""; + $this->attributes['password'] = ""; + $this->attributes['salt'] = ""; + $this->attributes['email'] = ""; + $this->attributes['language'] = ""; + $this->attributes['code'] = ""; + $this->attributes['banned'] = "no"; + $this->attributes['admin'] = 'no'; + $this->attributes['tables_split'] = 2; + } + + /** + * Construct a new user entity, optionally from a given id value. + * + * @param mixed $guid If an int, load that GUID. + * If a db row then will attempt to load the rest of the data. + * @throws Exception if there was a problem creating the user. + */ + function __construct($guid = null) { + $this->initialise_attributes(); + + if (!empty($guid)) { + // Is $guid is a DB row - either a entity row, or a user table row. + if ($guid instanceof stdClass) { + // Load the rest + if (!$this->load($guid->guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid)); + } + } + + // See if this is a username + else if (is_string($guid)) { + $guid = get_user_by_username($guid); + foreach ($guid->attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + + // Is $guid is an ElggUser? Use a copy constructor + else if ($guid instanceof ElggUser) { + elgg_deprecated_notice('This type of usage of the ElggUser constructor was deprecated. Please use the clone method.', 1.7); + + foreach ($guid->attributes as $key => $value) { + $this->attributes[$key] = $value; + } + } + + // Is this is an ElggEntity but not an ElggUser = ERROR! + else if ($guid instanceof ElggEntity) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggUser')); + } + + // We assume if we have got this far, $guid is an int + else if (is_numeric($guid)) { + if (!$this->load($guid)) { + throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid)); + } + } + + else { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue')); + } + } + } + + /** + * Override the load function. + * This function will ensure that all data is loaded (were possible), so + * if only part of the ElggUser is loaded, it'll load the rest. + * + * @param int $guid + * @return true|false + */ + protected function load($guid) { + // Test to see if we have the generic stuff + if (!parent::load($guid)) { + return false; + } + + // Check the type + if ($this->attributes['type']!='user') { + throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class())); + } + + // Load missing data + $row = get_user_entity_as_row($guid); + if (($row) && (!$this->isFullyLoaded())) { + // If $row isn't a cached copy then increment the counter + $this->attributes['tables_loaded'] ++; + } + + // Now put these into the attributes array as core values + $objarray = (array) $row; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + + return true; + } + + /** + * Saves this user to the database. + * @return true|false + */ + public function save() { + // Save generic stuff + if (!parent::save()) { + return false; + } + + // Now save specific stuff + return create_user_entity($this->get('guid'), $this->get('name'), $this->get('username'), $this->get('password'), $this->get('salt'), $this->get('email'), $this->get('language'), $this->get('code')); + } + + /** + * User specific override of the entity delete method. + * + * @return bool + */ + public function delete() { + global $USERNAME_TO_GUID_MAP_CACHE, $CODE_TO_GUID_MAP_CACHE; + + // clear cache + if (isset($USERNAME_TO_GUID_MAP_CACHE[$this->username])) { + unset($USERNAME_TO_GUID_MAP_CACHE[$this->username]); + } + if (isset($CODE_TO_GUID_MAP_CACHE[$this->code])) { + unset($CODE_TO_GUID_MAP_CACHE[$this->code]); + } + + // Delete owned data + clear_annotations_by_owner($this->guid); + clear_metadata_by_owner($this->guid); + clear_user_files($this); + + // Delete entity + return parent::delete(); + } + + /** + * Ban this user. + * + * @param string $reason Optional reason + */ + public function ban($reason = "") { + return ban_user($this->guid, $reason); + } + + /** + * Unban this user. + */ + public function unban() { + return unban_user($this->guid); + } + + /** + * Is this user banned or not? + * + * @return bool + */ + public function isBanned() { + return $this->banned == 'yes'; + } + + /** + * Is this user admin? + * + * @return bool + */ + public function isAdmin() { + + // for backward compatibility we need to pull this directly + // from the attributes instead of using the magic methods. + // this can be removed in 1.9 + // return $this->admin == 'yes'; + return $this->attributes['admin'] == 'yes'; + } + + /** + * Make the user an admin + * + * @return bool + */ + public function makeAdmin() { + if (make_user_admin($this->guid)) { + $this->attributes['admin'] = 'yes'; + return TRUE; + } + return FALSE; + } + + /** + * Remove the admin flag for user + * + * @return bool + */ + public function removeAdmin() { + if (remove_user_admin($this->guid)) { + $this->attributes['admin'] = 'no'; + return TRUE; + } + return FALSE; + } + + /** + * Get sites that this user is a member of + * + * @param string $subtype Optionally, the subtype of result we want to limit to + * @param int $limit The number of results to return + * @param int $offset Any indexing offset + */ + function getSites($subtype="", $limit = 10, $offset = 0) { + // return get_site_users($this->getGUID(), $subtype, $limit, $offset); + return get_user_sites($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Add this user to a particular site + * + * @param int $site_guid The guid of the site to add it to + * @return true|false + */ + function addToSite($site_guid) { + // return add_site_user($this->getGUID(), $site_guid); + return add_site_user($site_guid, $this->getGUID()); + } + + /** + * Remove this user from a particular site + * + * @param int $site_guid The guid of the site to remove it from + * @return true|false + */ + function removeFromSite($site_guid) { + //return remove_site_user($this->getGUID(), $site_guid); + return remove_site_user($site_guid, $this->getGUID()); + } + + /** + * Adds a user to this user's friends list + * + * @param int $friend_guid The GUID of the user to add + * @return true|false Depending on success + */ + function addFriend($friend_guid) { + return user_add_friend($this->getGUID(), $friend_guid); + } + + /** + * Removes a user from this user's friends list + * + * @param int $friend_guid The GUID of the user to remove + * @return true|false Depending on success + */ + function removeFriend($friend_guid) { + return user_remove_friend($this->getGUID(), $friend_guid); + } + + /** + * Determines whether or not this user is a friend of the currently logged in user + * + * @return true|false + */ + function isFriend() { + return user_is_friend(get_loggedin_userid(), $this->getGUID()); + } + + /** + * Determines whether this user is friends with another user + * + * @param int $user_guid The GUID of the user to check is on this user's friends list + * @return true|false + */ + function isFriendsWith($user_guid) { + return user_is_friend($this->getGUID(), $user_guid); + } + + /** + * Determines whether or not this user is on another user's friends list + * + * @param int $user_guid The GUID of the user to check against + * @return true|false + */ + function isFriendOf($user_guid) { + return user_is_friend($user_guid, $this->getGUID()); + } + + /** + * Retrieves a list of this user's friends + * + * @param string $subtype Optionally, the subtype of user to filter to (leave blank for all) + * @param int $limit The number of users to retrieve + * @param int $offset Indexing offset, if any + * @return array|false Array of ElggUsers, or false, depending on success + */ + function getFriends($subtype = "", $limit = 10, $offset = 0) { + return get_user_friends($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Retrieves a list of people who have made this user a friend + * + * @param string $subtype Optionally, the subtype of user to filter to (leave blank for all) + * @param int $limit The number of users to retrieve + * @param int $offset Indexing offset, if any + * @return array|false Array of ElggUsers, or false, depending on success + */ + function getFriendsOf($subtype = "", $limit = 10, $offset = 0) { + return get_user_friends_of($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Get an array of ElggObjects owned by this user. + * + * @param string $subtype The subtype of the objects, if any + * @param int $limit Number of results to return + * @param int $offset Any indexing offset + */ + public function getObjects($subtype="", $limit = 10, $offset = 0) { + return get_user_objects($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Get an array of ElggObjects owned by this user's friends. + * + * @param string $subtype The subtype of the objects, if any + * @param int $limit Number of results to return + * @param int $offset Any indexing offset + */ + public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0) { + return get_user_friends_objects($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * Counts the number of ElggObjects owned by this user + * + * @param string $subtype The subtypes of the objects, if any + * @return int The number of ElggObjects + */ + public function countObjects($subtype = "") { + return count_user_objects($this->getGUID(), $subtype); + } + + /** + * Get the collections associated with a user. + * + * @param string $subtype Optionally, the subtype of result we want to limit to + * @param int $limit The number of results to return + * @param int $offset Any indexing offset + * @return unknown + */ + public function getCollections($subtype="", $limit = 10, $offset = 0) { + return get_user_collections($this->getGUID(), $subtype, $limit, $offset); + } + + /** + * If a user's owner is blank, return its own GUID as the owner + * + * @return int User GUID + */ + function getOwner() { + if ($this->owner_guid == 0) { + return $this->getGUID(); + } + + return $this->owner_guid; + } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array_merge(parent::getExportableValues(), array( + 'name', + 'username', + 'language', + )); + } + + // backward compatibility with admin flag + // remove for 1.9 + public function __set($name, $value) { + if ($name == 'admin' || $name == 'siteadmin') { + elgg_deprecated_notice('The admin/siteadmin metadata are not longer used. Use ElggUser->makeAdmin() and ElggUser->removeAdmin().', '1.7.1'); + + if ($value == 'yes' || $value == '1') { + $this->makeAdmin(); + } else { + $this->removeAdmin(); + } + } + return parent::__set($name, $value); + } + + public function __get($name) { + if ($name == 'admin' || $name == 'siteadmin') { + elgg_deprecated_notice('The admin/siteadmin metadata are not longer used. Use ElggUser->isAdmin().', '1.7.1'); + return $this->isAdmin(); + } + + return parent::__get($name); + } +} diff --git a/engine/classes/ElggWidget.php b/engine/classes/ElggWidget.php new file mode 100644 index 000000000..dbca3c369 --- /dev/null +++ b/engine/classes/ElggWidget.php @@ -0,0 +1,53 @@ +attributes['subtype'] = "widget"; + } + + public function __construct($guid = null) { + parent::__construct($guid); + } + + /** + * Override entity get and sets in order to save data to private data store. + */ + public function get($name) { + // See if its in our base attribute + if (isset($this->attributes[$name])) { + return $this->attributes[$name]; + } + + // No, so see if its in the private data store. + $meta = get_private_setting($this->guid, $name); + if ($meta) { + return $meta; + } + + // Can't find it, so return null + return null; + } + + /** + * Override entity get and sets in order to save data to private data store. + */ + public function set($name, $value) { + if (array_key_exists($name, $this->attributes)) { + // Check that we're not trying to change the guid! + if ((array_key_exists('guid', $this->attributes)) && ($name=='guid')) { + return false; + } + + $this->attributes[$name] = $value; + } else { + return set_private_setting($this->guid, $name, $value); + } + + return true; + } +} \ No newline at end of file diff --git a/engine/classes/ErrorResult.php b/engine/classes/ErrorResult.php new file mode 100644 index 000000000..5fc6c88b6 --- /dev/null +++ b/engine/classes/ErrorResult.php @@ -0,0 +1,44 @@ + + * @package Elgg + * @subpackage Core + */ +class ErrorResult extends GenericResult { + // Fail with no specific code + public static $RESULT_FAIL = -1 ; + + public static $RESULT_FAIL_APIKEY_DISABLED = -30; + public static $RESULT_FAIL_APIKEY_INACTIVE = -31; + public static $RESULT_FAIL_APIKEY_INVALID = -32; + + // Invalid, expired or missing auth token + public static $RESULT_FAIL_AUTHTOKEN = -20; + + public function ErrorResult($message, $code = "", Exception $exception = NULL) { + if ($code == "") { + $code = ErrorResult::$RESULT_FAIL; + } + + if ($exception!=NULL) { + $this->setResult($exception->__toString()); + } + + $this->setStatusCode($code, $message); + } + + /** + * Get a new instance of the ErrorResult. + * + * @param string $message + * @param int $code + * @param Exception $exception Optional exception for generating a stack trace. + */ + public static function getInstance($message, $code = "", Exception $exception = NULL) { + // Return a new error object. + return new ErrorResult($message, $code, $exception); + } +} \ No newline at end of file diff --git a/engine/classes/ExportException.php b/engine/classes/ExportException.php new file mode 100644 index 000000000..dc5c686b7 --- /dev/null +++ b/engine/classes/ExportException.php @@ -0,0 +1,9 @@ + + * @package Elgg + * @subpackage Core + */ +abstract class GenericResult { + /** + * The status of the result. + * @var int + */ + private $status_code; + + /** + * Message returned along with the status which is almost always an error message. + * This must be human readable, understandable and localised. + * @var string + */ + private $message; + + /** + * Result store. + * Attach result specific informaton here. + * + * @var mixed. Should probably be an object of some sort. + */ + private $result; + + /** + * Set a status code and optional message. + * + * @param int $status The status code. + * @param string $message The message. + */ + protected function setStatusCode($status, $message = "") { + $this->status_code = $status; + $this->message = $message; + } + + /** + * Set the result. + * + * @param mixed $result + */ + protected function setResult($result) { + $this->result = $result; + } + + protected function getStatusCode() { + return $this->status_code; + } + + protected function getStatusMessage() { + return $this->message; + } + + protected function getResult() { + return $this->result; + } + + /** + * Serialise to a standard class. + * + * DEVNOTE: The API is only interested in data, we can not easily serialise + * custom classes without the need for 1) the other side being PHP, 2) you need to have the class + * definition installed, 3) its the right version! + * + * Therefore, I'm not bothering. + * + * Override this to include any more specific information, however api results should be attached to the + * class using setResult(). + * + * if $CONFIG->debug is set then additional information about the runtime environment and authentication will be + * returned. + * + * @return stdClass Object containing the serialised result. + */ + public function export() { + global $ERRORS, $CONFIG, $_PAM_HANDLERS_MSG; + + $result = new stdClass; + + $result->status = $this->getStatusCode(); + if ($this->getStatusMessage()!="") { + $result->message = $this->getStatusMessage(); + } + + $resultdata = $this->getResult(); + if (isset($resultdata)) { + $result->result = $resultdata; + } + + if (isset($CONFIG->debug)) { + if (count($ERRORS)) { + $result->runtime_errors = $ERRORS; + } + + if (count($_PAM_HANDLERS_MSG)) { + $result->pam = $_PAM_HANDLERS_MSG; + } + } + + return $result; + } +} \ No newline at end of file diff --git a/engine/classes/ImportException.php b/engine/classes/ImportException.php new file mode 100644 index 000000000..fd86fc23c --- /dev/null +++ b/engine/classes/ImportException.php @@ -0,0 +1,8 @@ +geo:lat field. + * + */ + public function getLatitude(); + + /** + * Get the contents of the ->geo:lat field. + * + */ + public function getLongitude(); + + /** + * Get the ->location metadata. + * + */ + public function getLocation(); +} \ No newline at end of file diff --git a/engine/classes/Loggable.php b/engine/classes/Loggable.php new file mode 100644 index 000000000..e12641410 --- /dev/null +++ b/engine/classes/Loggable.php @@ -0,0 +1,49 @@ +body = ""; + } + + public function getAttributes() { + return $this->attributes; + } + + public function setAttribute($key, $value) { + $this->attributes[$key] = $value; + } + + public function getAttribute($key) { + if (isset($this->attributes[$key])) { + return $this->attributes[$key]; + } + + return NULL; + } + + public function setBody($value) { + $this->body = $value; + } + + public function getBody() { + return $this->body; + } + + /** + * Set the published time. + * + * @param int $time Unix timestamp + */ + public function setPublished($time) { + $this->attributes['published'] = date("r", $time); + } + + /** + * Return the published time as a unix timestamp. + * + * @return int or false on failure. + */ + public function getPublishedAsTime() { + return strtotime($this->attributes['published']); + } + + /** + * For serialisation, implement to return a string name of the tag eg "header" or "metadata". + * @return string + */ + abstract protected function getTagName(); + + /** + * Magic function to generate valid ODD XML for this item. + */ + public function __toString() { + // Construct attributes + $attr = ""; + foreach ($this->attributes as $k => $v) { + $attr .= ($v!="") ? "$k=\"$v\" " : ""; + } + + $body = $this->getBody(); + $tag = $this->getTagName(); + + $end = "/>"; + if ($body!="") { + $end = ">"; + } + + return "<{$tag} $attr" . $end . "\n"; + } +} diff --git a/engine/classes/ODDDocument.php b/engine/classes/ODDDocument.php new file mode 100644 index 000000000..0c8731a75 --- /dev/null +++ b/engine/classes/ODDDocument.php @@ -0,0 +1,129 @@ +elements = $elements; + } else { + $this->addElement($elements); + } + } else { + $this->elements = array(); + } + } + + /** + * Return the version of ODD being used. + * + * @return string + */ + public function getVersion() { + return $this->ODDSupportedVersion; + } + + public function getNumElements() { + return count($this->elements); + } + + public function addElement(ODD $element) { + if (!is_array($this->elements)) { + $this->elements = array(); + $this->elements[] = $element; + } + } + + public function addElements(array $elements) { + foreach ($elements as $element) { + $this->addElement($element); + } + } + + public function getElements() { + return $this->elements; + } + + /** + * Set an optional wrapper factory to optionally embed the ODD document in another format. + */ + public function setWrapperFactory(ODDWrapperFactory $factory) { + $this->wrapperfactory = $factory; + } + + /** + * Magic function to generate valid ODD XML for this item. + */ + public function __toString() { + $xml = ""; + + if ($this->wrapperfactory) { + // A wrapper has been provided + $wrapper = $this->wrapperfactory->getElementWrapper($this); // Get the wrapper for this element + + $xml = $wrapper->wrap($this); // Wrap this element (and subelements) + } else { + // Output begin tag + $generated = date("r"); + $xml .= "ODDSupportedVersion}\" generated=\"$generated\">\n"; + + // Get XML for elements + foreach ($this->elements as $element) { + $xml .= "$element"; + } + + // Output end tag + $xml .= "\n"; + } + + return $xml; + } + + // ITERATOR INTERFACE ////////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be displayed using foreach as a normal array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + private $valid = FALSE; + + function rewind() { + $this->valid = (FALSE !== reset($this->elements)); + } + + function current() { + return current($this->elements); + } + + function key() { + return key($this->elements); + } + + function next() { + $this->valid = (FALSE !== next($this->elements)); + } + + function valid() { + return $this->valid; + } +} diff --git a/engine/classes/ODDEntity.php b/engine/classes/ODDEntity.php new file mode 100644 index 000000000..30da5f37f --- /dev/null +++ b/engine/classes/ODDEntity.php @@ -0,0 +1,60 @@ +setAttribute('uuid', $uuid); + $this->setAttribute('class', $class); + $this->setAttribute('subclass', $subclass); + } + + protected function getTagName() { return "entity"; } +} + +/** + * ODD Metadata class. + * @package Elgg + * @subpackage Core + * @author Curverider Ltd + */ +class ODDMetaData extends ODD { + function __construct($uuid, $entity_uuid, $name, $value, $type = "", $owner_uuid = "") { + parent::__construct(); + + $this->setAttribute('uuid', $uuid); + $this->setAttribute('entity_uuid', $entity_uuid); + $this->setAttribute('name', $name); + $this->setAttribute('type', $type); + $this->setAttribute('owner_uuid', $owner_uuid); + $this->setBody($value); + } + + protected function getTagName() { + return "metadata"; + } +} + +/** + * ODD Relationship class. + * @package Elgg + * @subpackage Core + * @author Curverider Ltd + */ +class ODDRelationship extends ODD { + function __construct($uuid1, $type, $uuid2) { + parent::__construct(); + + $this->setAttribute('uuid1', $uuid1); + $this->setAttribute('type', $type); + $this->setAttribute('uuid2', $uuid2); + } + + protected function getTagName() { return "relationship"; } +} \ No newline at end of file diff --git a/engine/classes/SuccessResult.php b/engine/classes/SuccessResult.php new file mode 100644 index 000000000..db5769d58 --- /dev/null +++ b/engine/classes/SuccessResult.php @@ -0,0 +1,22 @@ + + * @package Elgg + * @subpackage Core + */ +class SuccessResult extends GenericResult { + public static $RESULT_SUCCESS = 0; // Do not change this from 0 + + public function SuccessResult($result) { + $this->setResult($result); + $this->setStatusCode(SuccessResult::$RESULT_SUCCESS); + } + + public static function getInstance($result) { + // Return a new error object. + return new SuccessResult($result); + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCArrayParameter.php b/engine/classes/XMLRPCArrayParameter.php new file mode 100644 index 000000000..600f5d9a7 --- /dev/null +++ b/engine/classes/XMLRPCArrayParameter.php @@ -0,0 +1,48 @@ +addField($v); + } + } + + /** + * Add a field to the container. + * + * @param XMLRPCParameter $value The value. + */ + public function addField(XMLRPCParameter $value) + { + if (!is_array($this->value)) + $this->value = array(); + + $this->value[] = $value; + } + + function __toString() + { + $params = ""; + foreach ($this->value as $value) + { + $params .= "$value"; + } + + return "$params"; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCBase64Parameter.php b/engine/classes/XMLRPCBase64Parameter.php new file mode 100644 index 000000000..b32e7f3da --- /dev/null +++ b/engine/classes/XMLRPCBase64Parameter.php @@ -0,0 +1,24 @@ +value = base64_encode($blob); + } + + function __toString() + { + return "{$value}"; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCBoolParameter.php b/engine/classes/XMLRPCBoolParameter.php new file mode 100644 index 000000000..c2714ceff --- /dev/null +++ b/engine/classes/XMLRPCBoolParameter.php @@ -0,0 +1,20 @@ +value = (bool)$value; + } + + function __toString() + { + $code = ($this->value) ? "1" : "0"; + return "{$code}"; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCCall.php b/engine/classes/XMLRPCCall.php new file mode 100644 index 000000000..09e8e6d6d --- /dev/null +++ b/engine/classes/XMLRPCCall.php @@ -0,0 +1,60 @@ +parse($xml); + } + + /** + * Return the method name associated with the call. + * + * @return string + */ + public function getMethodName() { return $this->methodname; } + + /** + * Return the parameters. + * Returns a nested array of XmlElement. + * + * @see XmlElement + * @return array + */ + public function getParameters() { return $this->params; } + + /** + * Parse the xml into its components according to spec. + * This first version is a little primitive. + * + * @param string $xml + */ + private function parse($xml) + { + $xml = xml_to_object($xml); + + // sanity check + if ((isset($xml->name)) && (strcasecmp($xml->name, "methodCall")!=0)) + throw new CallException(elgg_echo('CallException:NotRPCCall')); + + // method name + $this->methodname = $xml->children[0]->content; + + // parameters + $this->params = $xml->children[1]->children; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCDateParameter.php b/engine/classes/XMLRPCDateParameter.php new file mode 100644 index 000000000..47ba88c0f --- /dev/null +++ b/engine/classes/XMLRPCDateParameter.php @@ -0,0 +1,27 @@ +value = $timestamp; + if (!$timestamp) + $this->value = time(); + } + + function __toString() + { + $value = date('c', $this->value); + return "{$value}"; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCDoubleParameter.php b/engine/classes/XMLRPCDoubleParameter.php new file mode 100644 index 000000000..64cbdff91 --- /dev/null +++ b/engine/classes/XMLRPCDoubleParameter.php @@ -0,0 +1,19 @@ +value = (float)$value; + } + + function __toString() + { + return "{$this->value}"; + } +} diff --git a/engine/classes/XMLRPCErrorResponse.php b/engine/classes/XMLRPCErrorResponse.php new file mode 100644 index 000000000..4dfcfafea --- /dev/null +++ b/engine/classes/XMLRPCErrorResponse.php @@ -0,0 +1,34 @@ +addParameter( + new XMLRPCStructParameter( + array ( + 'faultCode' => new XMLRPCIntParameter($code), + 'faultString' => new XMLRPCStringParameter($message) + ) + ) + ); + } + + /** + * Output to XML. + */ + public function __toString() + { + return "{$this->parameters[0]}"; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCIntParameter.php b/engine/classes/XMLRPCIntParameter.php new file mode 100644 index 000000000..2305a66a7 --- /dev/null +++ b/engine/classes/XMLRPCIntParameter.php @@ -0,0 +1,19 @@ +value = (int)$value; + } + + function __toString() + { + return "{$this->value}"; + } +} diff --git a/engine/classes/XMLRPCParameter.php b/engine/classes/XMLRPCParameter.php new file mode 100644 index 000000000..f9e04a073 --- /dev/null +++ b/engine/classes/XMLRPCParameter.php @@ -0,0 +1,12 @@ +parameters)) + $this->parameters = array(); + + $this->parameters[] = $param; + } + + public function addInt($value) { $this->addParameter(new XMLRPCIntParameter($value)); } + public function addString($value) { $this->addParameter(new XMLRPCStringParameter($value)); } + public function addDouble($value) { $this->addParameter(new XMLRPCDoubleParameter($value)); } + public function addBoolean($value) { $this->addParameter(new XMLRPCBoolParameter($value)); } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCStringParameter.php b/engine/classes/XMLRPCStringParameter.php new file mode 100644 index 000000000..bf9097747 --- /dev/null +++ b/engine/classes/XMLRPCStringParameter.php @@ -0,0 +1,20 @@ +value = $value; + } + + function __toString() + { + $value = htmlentities($this->value); + return "{$value}"; + } +} diff --git a/engine/classes/XMLRPCStructParameter.php b/engine/classes/XMLRPCStructParameter.php new file mode 100644 index 000000000..326a82804 --- /dev/null +++ b/engine/classes/XMLRPCStructParameter.php @@ -0,0 +1,49 @@ + $v) + $this->addField($k, $v); + } + } + + /** + * Add a field to the container. + * + * @param string $name The name of the field. + * @param XMLRPCParameter $value The value. + */ + public function addField($name, XMLRPCParameter $value) + { + if (!is_array($this->value)) + $this->value = array(); + + $this->value[$name] = $value; + } + + function __toString() + { + $params = ""; + foreach ($this->value as $k => $v) + { + $params .= "$k$v"; + } + + return "$params"; + } +} \ No newline at end of file diff --git a/engine/classes/XMLRPCSuccessResponse.php b/engine/classes/XMLRPCSuccessResponse.php new file mode 100644 index 000000000..cffa64439 --- /dev/null +++ b/engine/classes/XMLRPCSuccessResponse.php @@ -0,0 +1,19 @@ +parameters as $param) + $params .= "$param\n"; + + return "$params"; + } +} \ No newline at end of file diff --git a/engine/classes/XmlElement.php b/engine/classes/XmlElement.php new file mode 100644 index 000000000..17e3151a8 --- /dev/null +++ b/engine/classes/XmlElement.php @@ -0,0 +1,19 @@ +