diff options
-rw-r--r-- | engine/lib/annotations.php | 4 | ||||
-rw-r--r-- | engine/lib/entities.php | 64 | ||||
-rw-r--r-- | engine/lib/export.php | 423 | ||||
-rw-r--r-- | engine/lib/extender.php | 2 | ||||
-rw-r--r-- | engine/lib/metadata.php | 4 | ||||
-rw-r--r-- | engine/lib/relationships.php | 6 |
6 files changed, 295 insertions, 208 deletions
diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index 68c9bfc22..4983dcacf 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -427,7 +427,7 @@ function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $params) { // Sanity check values - if ((!is_array($params)) && (!isset($params['guid']))) +/* if ((!is_array($params)) && (!isset($params['guid']))) throw new InvalidParameterException("GUID has not been specified during export, this should never happen."); if (!is_array($returnvalue)) @@ -442,7 +442,7 @@ { foreach ($result as $r) $returnvalue[] = $r; - } + }*/ return $returnvalue; } diff --git a/engine/lib/entities.php b/engine/lib/entities.php index 788a559d8..ab682fb2f 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -379,12 +379,49 @@ */ public function export() { - $tmp = new stdClass; - $tmp->attributes = $this->attributes; - $tmp->attributes['uuid'] = guid_to_uuid($this->getGUID()); - $tmp->attributes['owner_uuid'] = guid_to_uuid($this->owner_guid); - $tmp->attributes['subtype'] = get_subtype_from_id($tmp->attributes['subtype']); - return $tmp; + global $CONFIG; + + $tmp = array(); + + // Generate uuid + $uuid = guid_to_uuid($this->getGUID()); + + // Create entity + $tmp[] = new ODDEntity( + $uuid, + $this->attributes['type'], + get_subtype_from_id($tmp->attributes['subtype']) + ); + + // Now add its attributes + foreach ($this->attributes as $k => $v) + { + switch ($k) + { + case 'guid' : break; // Dont use guid + case 'subtype' : break; // Hide subtype + case 'type' : break; // Don't use type + case 'access_id' : break; // Don't use access - if can export then its public for you, then importer decides what access to give this object. + + case 'owner_guid' : // Convert owner guid to uuid + $k = 'owner_uuid'; + $v = guid_to_uuid($v); + $tmp[] = new ODDMetadata($uuid . "attr/$k/", $uuid, $k, $v, "attribute"); + break; + + case 'time_created' : // Convert to RFC 822 + case 'time_updated' : // Convert to RFC 822 + $v = date('r', $v); + $tmp[] = new ODDMetadata($uuid . "attr/$k/", $uuid, $k, $v, "attribute"); + break; + + default : + $tmp[] = new ODDMetadata($uuid . "attr/$k/", $uuid, $k, $v, "attribute"); + } + } + + + return $tmp; } // IMPORTABLE INTERFACE //////////////////////////////////////////////////////////// @@ -395,7 +432,7 @@ * @param array $data * @param int $version */ - public function import(array $data, $version = 1) + public function import(ODD $data) { if ($version == 1) { @@ -772,10 +809,17 @@ // Get the entity $entity = get_entity($guid); + if (!($entity instanceof ElggEntity)) + throw new InvalidClassException("GUID:$guid is not an ElggEntity"); + + $export = $entity->export(); + + if (is_array($export)) + foreach ($export as $e) + $returnvalue[] = $e; + else + $returnvalue[] = $export; - if ($entity instanceof ElggEntity) - $returnvalue[] = $entity; // Add object to list of things to serialise - actual serialisation done later - return $returnvalue; } diff --git a/engine/lib/export.php b/engine/lib/export.php index 586f5609d..c8b7fa3ca 100644 --- a/engine/lib/export.php +++ b/engine/lib/export.php @@ -20,7 +20,8 @@ interface Exportable { /** - * This must take the contents of the object and return it as a stdClass. + * This must take the contents of the object and convert it to exportable class(es). + * @return object or array of object. */ public function export(); } @@ -35,154 +36,191 @@ * Accepts an array of data to import, this data is parsed from the XML produced by export. * The function should return the constructed object data, or NULL. * - * @param array $data - * @param int $version Support different internal serialisation formats, should be "1" + * @param ODD $data * @return mixed The newly imported object. * @throws ImportException if there was a critical error importing data. */ - public function import(array $data, $version = 1); + public function import(ODD $data); } - + /** - * Export a GUID. - * - * This function exports a GUID and all information related to it in an XML format. - * - * This function makes use of the "serialise" plugin hook, which is passed an array to which plugins - * should add data to be serialised to. + * Export exception * - * @see ElggEntity for an example of its usage. - * @param int $guid The GUID. - * @return xml + * @package Elgg + * @subpackage Exceptions + * */ - function export($guid) + class ExportException extends DataFormatException {} + + /** + * Import exception + * + * @package Elgg + * @subpackage Exceptions + */ + class ImportException extends DataFormatException {} + + /** + * Open Data Definition (ODD) superclass. + * @package Elgg + * @subpackage Core + * @author Marcus Povey + */ + abstract class ODD { - global $CONFIG; + /** + * ODD Version + * + * @var string + */ + private $ODDSupportedVersion = "1.0"; - $guid = (int)$guid; + /** + * Attributes. + */ + private $attributes = array(); - // Initialise the array - $to_be_serialised = array(); + /** + * Optional body. + */ + private $body; - // Trigger a hook to - $to_be_serialised = trigger_plugin_hook("export", "all", array("guid" => $guid), $to_be_serialised); + /** + * Construct an ODD document with initial values. + */ + public function __construct() + { + $this->body = ""; + $this->setAttribute('generated', date("r")); + } - // Sanity check - if ((!is_array($to_be_serialised)) || (count($to_be_serialised)==0)) throw new ExportException("No such entity GUID:$guid"); + protected function setAttribute($key, $value) { $this->attributes[$key] = $value; } + protected function getAttribute($key) + { + if (isset($this->attributes[$key])) + return $this->attributes[$key]; + + return NULL; + } + protected function setBody($value) { $this->body = $value; } + protected function getBody() { return $this->body; } - // Now serialise the result to XML - $wrapper = new stdClass; - - // Construct header - $wrapper->header = new stdClass; - $wrapper->header->date = date("r"); - $wrapper->header->timestamp = time(); - $wrapper->header->domain = $CONFIG->wwwroot; - $wrapper->header->exported_by = guid_to_uuid($_SESSION['id']); - - // Construct data - $wrapper->data = $to_be_serialised; - - return serialise_object_to_xml($wrapper, "elggexport"); + /** + * Return the version of ODD being used. + * + * @return real + */ + public function getVersion() { return $this->ODDSupportedVersion; } + + /** + * 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 = ">$body</$tag>"; + + return "<$tag $attr" . $end . "\n"; + } } - /** - * XML 2 Array function. - * Taken from http://www.bytemycode.com/snippets/snippet/445/ - * @license UNKNOWN - Please contact if you are the original author of this code. - * @author UNKNOWN + * ODD Header class. + * @package Elgg + * @subpackage Core + * @author Marcus Povey */ - function __xml2array($xml) + class ODDHeader extends ODD { - $xmlary = array(); - - $reels = '/<(\w+)\s*([^\/>]*)\s*(?:\/>|>(.*)<\/\s*\\1\s*>)/s'; - $reattrs = '/(\w+)=(?:"|\')([^"\']*)(:?"|\')/'; - - preg_match_all($reels, $xml, $elements); - - foreach ($elements[1] as $ie => $xx) { - $xmlary[$ie]["name"] = $elements[1][$ie]; - - if ($attributes = trim($elements[2][$ie])) { - preg_match_all($reattrs, $attributes, $att); - foreach ($att[1] as $ia => $xx) - $xmlary[$ie]["attributes"][$att[1][$ia]] = $att[2][$ia]; - } - - $cdend = strpos($elements[3][$ie], "<"); - if ($cdend > 0) { - $xmlary[$ie]["text"] = substr($elements[3][$ie], 0, $cdend - 1); - } - - if (preg_match($reels, $elements[3][$ie])) - $xmlary[$ie]["elements"] = __xml2array($elements[3][$ie]); - else if ($elements[3][$ie]) { - $xmlary[$ie]["text"] = $elements[3][$ie]; - } - } - - return $xmlary; + + function __construct($extension = "SN1.0") + { + parent::__construct(); + + $this->setAttribute('version', $this->getVersion()); + $this->setAttribute('extension', $extension); + } + + protected function getTagName() { return "header"; } } - - $IMPORTED_DATA = array(); - $IMPORTED_OBJECT_COUNTER = 0; /** - * This function processes an element, passing elements to the plugin stack to see if someone will - * process it. - * If nobody processes the top level element, the sub level elements are processed. + * ODD Entity class. + * @package Elgg + * @subpackage Core + * @author Marcus Povey */ - function __process_element(array $dom) + class ODDEntity extends ODD { - global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER; - - foreach ($dom as $element) + function __construct($uuid, $class, $subclass = "") { - // See if anyone handles this element, return true if it is. - $handled = trigger_plugin_hook("import", "all", array("name" => $element['name'], "element" => $element), $to_be_serialised); - - // If not, then see if any of its sub elements are handled - if (!$handled) - { - if (isset($element['elements'])) - __process_element($element['elements']); - } - else - { - $IMPORTED_OBJECT_COUNTER ++; // Increment validation counter - $IMPORTED_DATA[] = $handled; // Return the constructed object - } + parent::__construct(); + + $this->setAttribute('uuid', $uuid); + $this->setAttribute('class', $class); + $this->setAttribute('subclass', $subclass); } + + protected function getTagName() { return "entity"; } } /** - * Import an XML serialisation of an object. - * This will make a best attempt at importing a given xml doc. - * - * @param string $xml - * @return array An array of imported objects (these have already been saved). - * @throws Exception if there was a problem importing the data. + * ODD Metadata class. + * @package Elgg + * @subpackage Core + * @author Marcus Povey */ - function import($xml) + class ODDMetaData extends ODD { - global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER; - - $IMPORTED_DATA = array(); - $IMPORTED_OBJECT_COUNTER = 0; - $IMPORTED_GUID_MAP = array(); - - $dom = __xml2array($xml); - - __process_element($dom); + function __construct($uuid, $entity_uuid, $name, $value, $type = "") + { + parent::__construct(); + + $this->setAttribute('uuid', $uuid); + $this->setAttribute('entity_uuid', $entity_uuid); + $this->setAttribute('name', $name); + $this->setAttribute('type', $type); + $this->setBody($value); + } - if ($IMPORTED_OBJECT_COUNTER!= count($IMPORTED_DATA)) - throw new ImportException("Not all elements were imported."); + protected function getTagName() { return "metadata"; } + } + + /** + * ODD Relationship class. + * @package Elgg + * @subpackage Core + * @author Marcus Povey + */ + class ODDRelationship extends ODD + { + function __construct($uuid1, $verb, $uuid2) + { + parent::__construct(); + + $this->setAttribute('uuid1', $uuid); + $this->setAttribute('verb', $uuid); + $this->setAttribute('uuid2', $uuid); + } - return $IMPORTED_DATA; + protected function getTagName() { return "relationship"; } } - + /** * Generate a UUID from a given GUID. * @@ -192,7 +230,7 @@ { global $CONFIG; - return "UUID:".md5($CONFIG->wwwroot) . ":$guid"; + return $CONFIG->wwwroot . "odd/$guid/"; } /** @@ -204,15 +242,12 @@ { global $CONFIG; - $domain = md5($CONFIG->wwwroot); - $tmp = explode(":",$uuid); - - if (strcmp($tmp[1], $domain) == 0) + if (strpos($uuid, $CONFIG->wwwroot) === 0) return true; return false; } - + /** * This function attempts to retrieve a previously imported entity via its UUID. * @@ -245,97 +280,105 @@ } /** - * This function serialises an object recursively into an XML representation. - * The function attempts to call $data->export() which expects a stdClass in return, otherwise it will attempt to - * get the object variables using get_object_vars (which will only return public variables!) - * @param $data object The object to serialise. - * @param $n int Level, only used for recursion. - * @return string The serialised XML output. + * Export a GUID. + * + * This function exports a GUID and all information related to it in an XML format. + * + * This function makes use of the "serialise" plugin hook, which is passed an array to which plugins + * should add data to be serialised to. + * + * @see ElggEntity for an example of its usage. + * @param int $guid The GUID. + * @return xml */ - function serialise_object_to_xml($data, $name = "", $n = 0) + function export($guid) { - $classname = ($name=="" ? get_class($data) : $name); + $guid = (int)$guid; - $vars = method_exists($data, "export") ? get_object_vars($data->export()) : get_object_vars($data); + // Initialise the array + $to_be_serialised = array(); - $output = ""; + // Set header + $to_be_serialised[] = new ODDHeader(); - if (($n==0) || ( is_object($data) && !($data instanceof stdClass))) $output = "<$classname>"; - - foreach ($vars as $key => $value) - { - $output .= "<$key type=\"".gettype($value)."\">"; - - if (is_object($value)) - $output .= serialise_object_to_xml($value, $key, $n+1); - else if (is_array($value)) - $output .= serialise_array_to_xml($value, $n+1); - else - $output .= htmlentities($value); - - $output .= "</$key>\n"; - } + // Trigger a hook to + $to_be_serialised = trigger_plugin_hook("export", "all", array("guid" => $guid), $to_be_serialised); + + // Sanity check + if ((!is_array($to_be_serialised)) || (count($to_be_serialised)==0)) throw new ExportException("No such entity GUID:$guid"); + + $output = "<odd>\n"; - if (($n==0) || ( is_object($data) && !($data instanceof stdClass))) $output .= "</$classname>\n"; + foreach ($to_be_serialised as $odd) + $output .= "$odd"; + + $output .= "</odd>\n"; return $output; } + + + + + + $IMPORTED_DATA = array(); + $IMPORTED_OBJECT_COUNTER = 0; + /** - * Serialise an array. - * - * @param array $data - * @param int $n Used for recursion - * @return string + * This function processes an element, passing elements to the plugin stack to see if someone will + * process it. + * If nobody processes the top level element, the sub level elements are processed. */ - function serialise_array_to_xml(array $data, $n = 0) +/* function __process_element(array $dom) { - $output = ""; - - if ($n==0) $output = "<array>\n"; + global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER; - foreach ($data as $key => $value) + foreach ($dom as $element) { - $item = "array_item"; - - if (is_numeric($key)) - $output .= "<$item name=\"$key\" type=\"".gettype($value)."\">"; - else + // See if anyone handles this element, return true if it is. + $handled = trigger_plugin_hook("import", "all", array("name" => $element['name'], "element" => $element), $to_be_serialised); + + // If not, then see if any of its sub elements are handled + if (!$handled) { - $item = $key; - $output .= "<$item type=\"".gettype($value)."\">"; + if (isset($element['elements'])) + __process_element($element['elements']); } - - if (is_object($value)) - $output .= serialise_object_to_xml($value, "", $n+1); - else if (is_array($value)) - $output .= serialise_array_to_xml($value, $n+1); else - $output .= htmlentities($value); - - $output .= "</$item>\n"; + { + $IMPORTED_OBJECT_COUNTER ++; // Increment validation counter + $IMPORTED_DATA[] = $handled; // Return the constructed object + } } - - if ($n==0) $output = "</array>\n"; - - return $output; } /** - * Export exception - * - * @package Elgg - * @subpackage Exceptions - * - */ - class ExportException extends Exception {} - - /** - * Import exception + * Import an XML serialisation of an object. + * This will make a best attempt at importing a given xml doc. * - * @package Elgg - * @subpackage Exceptions + * @param string $xml + * @return array An array of imported objects (these have already been saved). + * @throws Exception if there was a problem importing the data. */ - class ImportException extends Exception {} +/* function import($xml) + { + global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER; + + $IMPORTED_DATA = array(); + $IMPORTED_OBJECT_COUNTER = 0; + $IMPORTED_GUID_MAP = array(); + + $dom = __xml2array($xml); + + __process_element($dom); + + if ($IMPORTED_OBJECT_COUNTER!= count($IMPORTED_DATA)) + throw new ImportException("Not all elements were imported."); + + return $IMPORTED_DATA; + } + + */ ?>
\ No newline at end of file diff --git a/engine/lib/extender.php b/engine/lib/extender.php index 5a5d29e08..e22de5109 100644 --- a/engine/lib/extender.php +++ b/engine/lib/extender.php @@ -122,7 +122,7 @@ * @return ElggExtender * @throws ImportException */ - public function import(array $data, $version = 1) + public function import(ODD $data) { if ($version == 1) { diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index 76c953c85..50bcf2c53 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -361,7 +361,7 @@ */ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) { - // Sanity check values + /* // Sanity check values if ((!is_array($params)) && (!isset($params['guid']))) throw new InvalidParameterException("GUID has not been specified during export, this should never happen."); @@ -378,7 +378,7 @@ foreach ($result as $r) $returnvalue[] = $r; } - + */ return $returnvalue; } diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php index 52418e500..5af01044a 100644 --- a/engine/lib/relationships.php +++ b/engine/lib/relationships.php @@ -126,7 +126,7 @@ * @return ElggRelationship * @throws ImportException */ - public function import(array $data, $version = 1) + public function import(ODD $data) { if ($version == 1) { @@ -363,7 +363,7 @@ { global $CONFIG; - // Sanity check values +/* // Sanity check values if ((!is_array($params)) && (!isset($params['guid']))) throw new InvalidParameterException("GUID has not been specified during export, this should never happen."); @@ -379,7 +379,7 @@ foreach ($result as $r) $returnvalue[] = $r; } - +*/ return $returnvalue; } |