You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
8.4 KiB
277 lines
8.4 KiB
<?php |
|
|
|
// $Id$ |
|
|
|
abstract class XMLDatastream { |
|
|
|
static $XMLNS = 'http://www.islandora.ca'; |
|
static $errors = NULL; |
|
|
|
protected $xml = NULL; |
|
private $valid = NULL; |
|
|
|
protected $forceSchema = FALSE; // if set, the datastream will be validated against the specified schema in self::$SCHEMA_URI instead of |
|
// reading the schema URI from the datastream. |
|
|
|
public $pid; |
|
public $dsid; |
|
|
|
|
|
/** |
|
* Parses an PID from an identifier. |
|
* @param string $identifier |
|
* @return string $pid |
|
*/ |
|
public static function getPidFromIdentifier($identifier) { |
|
return substr($identifier, 0, strpos($identifier, "/")); |
|
} |
|
|
|
|
|
/** |
|
* validPid |
|
* Validates a fedora PID based on the regexp provided in the fedora |
|
* 3.3 documentation. |
|
* http://www.fedora-commons.org/confluence/display/FCR30/Fedora+Identifiers |
|
* |
|
* @param String $pid |
|
* @return boolean $valid |
|
*/ |
|
public static function validPid($pid) { |
|
$valid = FALSE; |
|
if (strlen(trim($pid)) <= 64 && preg_match('/^([A-Za-z0-9]|-|\.)+:(([A-Za-z0-9])|-|\.|~|_|(%[0-9A-F]{2}))+$/', trim($pid))) { |
|
$valid = TRUE; |
|
} |
|
|
|
return $valid; |
|
} |
|
|
|
/** |
|
* validDsid |
|
* Validates a fedora Dsid based on the the allowed XML standard NCName. |
|
* The regexp is a "regular" subset of names allowed, it excludes some extended hex characters that are |
|
* technically permitted. |
|
* http://www.fedora-commons.org/confluence/display/FCR30/Fedora+Identifiers |
|
* |
|
* @param String $pid |
|
* @return boolean $valid |
|
*/ |
|
public static function validDsid($dsid) { |
|
$valid = FALSE; |
|
if (strlen(trim($dsid)) <= 64 && preg_match('/^[a-zA-Z0-9\_\-\.]+$/', trim($dsid))) { |
|
$valid = TRUE; |
|
} |
|
|
|
return $valid; |
|
} |
|
|
|
|
|
|
|
/** |
|
* Parses the DSID from an identifier. |
|
* TODO: combine this method with getPidFromIdentifier? |
|
* @param string $identifier |
|
* @return string $dsid |
|
*/ |
|
public static function getDSIDFromIdentifier($identifier) { |
|
$temp = strstr($identifier, "/"); |
|
return substr($temp, 1); |
|
} |
|
|
|
|
|
/** |
|
* Constructs an XMLDatastream object from the XML file specified. |
|
* Returns FALSE on failure. |
|
* |
|
* @param string $filename |
|
* @return XMLDatastream $cm |
|
*/ |
|
public static function loadFromFile($filename) { |
|
return new self(file_get_contents($filename)); |
|
} |
|
|
|
|
|
/** |
|
* Constructor |
|
* NOTE: Use the static constructor methods whenever possible. |
|
* |
|
* @param string $xmlStr |
|
* @param string $pid |
|
* @param string $dsid |
|
* @return XMLDatastream $cm |
|
*/ |
|
public function __construct($xmlStr, $pid = NULL, $dsid = NULL) { |
|
libxml_use_internal_errors(true); |
|
$this->pid=$pid; |
|
$this->dsid=$dsid; |
|
|
|
if ($xmlStr !== NULL) { |
|
$this->xml = (is_object($xmlStr) && get_class($xmlStr) == DOMDocument)?$xmlStr : DOMDocument::loadXML($xmlStr); |
|
} |
|
} |
|
|
|
|
|
/** |
|
* Gets the identifier for this XMLDatastream |
|
* Returns FALSE on failure. |
|
* |
|
* NOTE: not available if constructed directly from file. |
|
* |
|
* @return string identifier |
|
*/ |
|
public function getIdentifier() { |
|
return ($this->pid != NULL && $this->dsid != NULL) ? $this->pid . '/'. $this->dsid : FALSE; |
|
} |
|
|
|
|
|
/** |
|
* Dumps the XMLDatastream as an XML String |
|
* |
|
* |
|
* @return string xml |
|
*/ |
|
public function dumpXml() { |
|
if ($this->xml == NULL) { |
|
$this->fetchXml(); |
|
} |
|
return $this->xml->saveXml(); |
|
} |
|
|
|
|
|
/** |
|
* Validates the XMLDatastream against the schema location |
|
* defined by the xmlns:schemaLocation attribute of the root |
|
* element. If the xmlns:schemaLocation attribute does not exist, |
|
* then it is assumed to be the old schema and it attempts to convert |
|
* using the convertFromOldSchema method. |
|
* |
|
* TODO: Maybe change it so that it always validates against a known |
|
* schema. This makes more sense because this class assumes the structure |
|
* to be known after it has been validated. |
|
* |
|
* @return boolean $valid |
|
*/ |
|
public function validate() { |
|
if ($this->valid === NULL) { |
|
$ret = TRUE; |
|
if ($this->xml == NULL) { |
|
$this->fetchXml(); |
|
} |
|
// figure out if we're dealing with a new or old schema |
|
$rootEl = $this->xml->firstChild; |
|
if (!$rootEl->hasAttributes() || $rootEl->attributes->getNamedItem('schemaLocation') === NULL ) { |
|
//$tmpname = substr($this->pid, strpos($this->pid, ':') + 1); |
|
$tmpname = user_password(10); |
|
$this->convertFromOldSchema(); |
|
drupal_add_js("fedora_repository_print_new_schema_$tmpname = function(tagID) { |
|
var target = document.getElementById(tagID); |
|
var content = target.innerHTML; |
|
var text = '<html><head><title>Title' + |
|
'</title><body>' + content +'</body></html>'; |
|
printerWindow = window.open('', '', 'toolbar=no,location=no,' + 'status=no,menu=no,scrollbars=yes,width=650,height=400'); |
|
printerWindow.document.open(); |
|
printerWindow.document.write(text); |
|
} ", 'inline'); |
|
|
|
drupal_set_message('<span id="new_schema_'. $tmpname .'" style="display: none;">'. htmlentities($this->xml->saveXML()) .'</span>Warning: XMLDatastream performed conversion of \''. $this->getIdentifier() .'\' from old schema. Please update the datastream. The new datastream contents are <a href="javascript:fedora_repository_print_new_schema_'. $tmpname .'(\'new_schema_'. $tmpname .'\')">here.</a> '); |
|
$rootEl = $this->xml->firstChild; |
|
} |
|
|
|
$schemaLocation = NULL; |
|
if ($this->forceSchema) { |
|
// hack because you cant easily get the static property value from |
|
// a subclass. |
|
$vars = get_class_vars(get_class($this)); |
|
$schemaLocation = $vars['SCHEMA_URI']; |
|
|
|
} |
|
elseif ($rootEl->attributes->getNamedItem('schemaLocation') !== NULL) { |
|
//figure out where the schema is located and validate. |
|
list(, $schemaLocation) = preg_split('/\s+/', $rootEl->attributes->getNamedItem('schemaLocation')->nodeValue); |
|
} |
|
$schemaLocation = NULL; |
|
return TRUE; |
|
if ($schemaLocation !== NULL) { |
|
if (!$this->xml->schemaValidate($schemaLocation)) { |
|
$ret = FALSE; |
|
$errors=libxml_get_errors(); |
|
foreach ($errors as $err) { |
|
self::$errors[] = 'XML Error: Line '. $err->line .': '. $err->message; |
|
} |
|
} |
|
else { |
|
$this->name=$rootEl->attributes->getNamedItem('name')->nodeValue; |
|
} |
|
} |
|
else { |
|
$ret = FALSE; |
|
self::$errors[] = 'Unable to load schema.'; |
|
} |
|
|
|
$this->valid = $ret; |
|
} |
|
|
|
return $this->valid; |
|
} |
|
|
|
|
|
/** |
|
* Saves the current XML datastream back to fedora. The XML must validate. |
|
* |
|
* @return boolean $success |
|
*/ |
|
public function saveToFedora() { |
|
module_load_include('inc', 'Fedora_Repository', 'api/fedora_item'); |
|
if ($this->validate()) { |
|
$item = new Fedora_Item($this->pid); |
|
$item->modify_datastream_by_value($this->dumpXml(), $this->dsid, $this->name, 'application/xml'); |
|
return TRUE; |
|
} |
|
return FALSE; |
|
} |
|
|
|
/** |
|
* Purges veersions of the datastream newer than and including the start_date. If |
|
* End date is specified, it can be used to purge a range of versions instead. Date should be in |
|
* DATE_RFC822 format |
|
* |
|
* @param string $start_date |
|
* @param string $end_date |
|
* @return boolean $valid |
|
*/ |
|
public function purgeVersions($start_date, $end_date = NULL) { |
|
module_load_include('inc', 'fedora_repository', 'api/fedora_item'); |
|
$fedora_item = new Fedora_Item($this->pid); |
|
return $fedora_item->purge_datastream( $this->dsid, $start_date, $end_date); |
|
} |
|
|
|
/** |
|
* Gets the history of the datastream from fedora. |
|
* Returns false on failure. |
|
* |
|
* @return string[] $ret |
|
*/ |
|
public function getHistory() { |
|
module_load_include('inc', 'fedora_repository', 'api/fedora_item'); |
|
$fedora_item = new Fedora_Item($this->pid); |
|
$history = $fedora_item->get_datastream_history($this->dsid); |
|
|
|
$ret = FALSE; |
|
if ($history !== FALSE) { |
|
$ret = array(); |
|
foreach ($history as $version) { |
|
if ($version->versionID !== NULL) $ret[] = array('versionID' => $version->versionID, 'createDate' => $version->createDate); |
|
} |
|
} |
|
return $ret; |
|
} |
|
|
|
/** |
|
* Attempts to convert from the old XML schema to the new by |
|
* traversing the XML DOM and building a new DOM. When done |
|
* $this->xml is replaced by the newly created DOM.. |
|
* |
|
* @return void |
|
*/ |
|
abstract protected function convertFromOldSchema(); |
|
|
|
}
|
|
|