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.
1568 lines
53 KiB
1568 lines
53 KiB
<?php |
|
/** |
|
* @file |
|
* Fedora Item |
|
*/ |
|
|
|
define('RELS_EXT_URI', 'info:fedora/fedora-system:def/relations-external#'); |
|
define("FEDORA_MODEL_URI", 'info:fedora/fedora-system:def/model#'); |
|
define("ISLANDORA_PAGE_URI", 'info:islandora/islandora-system:def/pageinfo#'); |
|
define("ISLANDORA_RELS_EXT_URI", 'http://islandora.ca/ontology/relsext#'); |
|
define("ISLANDORA_RELS_INT_URI", "http://islandora.ca/ontology/relsint#"); |
|
|
|
define("RELS_TYPE_URI", 0); |
|
define("RELS_TYPE_PLAIN_LITERAL", 1); |
|
define("RELS_TYPE_STRING", 2); |
|
define("RELS_TYPE_INT", 3); |
|
define("RELS_TYPE_DATETIME", 4); |
|
|
|
/** |
|
* Fedora Item Class |
|
*/ |
|
class Fedora_Item { |
|
|
|
// The $pid of the fedora object represented by an instance of this class. |
|
public $pid = NULL; |
|
public $objectProfile = NULL; |
|
public $ownerId = NULL; |
|
|
|
// A SimpleXML object to store a list of this item's datastreams. |
|
private $datastreams_list = NULL; |
|
public $datastreams = NULL; |
|
private static $connection_helper = NULL; |
|
private static $instantiated_pids = array(); |
|
private static $SoapManagedFunctions = array( |
|
'ingest', |
|
'addDataStream', |
|
'addRelationship', |
|
'export', |
|
'getDatastream', |
|
'getDatastreamHistory', |
|
'getNextPID', |
|
'getRelationships', |
|
'modifyDatastreamByValue', |
|
'modifyDatastreamByReference', |
|
'purgeDatastream', |
|
'purgeObject', |
|
'modifyObject', |
|
'setDatastreamState', |
|
); |
|
|
|
/** |
|
* Create an object to represent an item in the Fedora repository. |
|
* Throws a SOAPException if the PID is not in the repository. |
|
* |
|
* @param string $pid |
|
* The Fedora PID to create an object for. |
|
* |
|
* @return Fedora_Item |
|
*/ |
|
function __construct($pid) { |
|
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL); |
|
module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); |
|
module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); |
|
|
|
$this->pid = $pid; |
|
if (isset(Fedora_Item::$instantiated_pids[$pid])) { |
|
$this->objectProfile = & Fedora_Item::$instantiated_pids[$pid]->objectProfile; |
|
$this->datastreams = & Fedora_Item::$instantiated_pids[$pid]->datastreams; |
|
$this->datastreams_list = & Fedora_Item::$instantiated_pids[$pid]->datastreams_list; |
|
$this->ownerId = & Fedora_Item::$instantiated_pids[$pid]->ownerId; |
|
} |
|
else { |
|
if (empty(self::$connection_helper)) { |
|
self::$connection_helper = new ConnectionHelper(); |
|
} |
|
|
|
$raw_objprofile = $this->soap_call('getObjectProfile', array('pid' => $this->pid, 'asOfDateTime' => ""), TRUE); |
|
|
|
if (!empty($raw_objprofile)) { |
|
$this->objectProfile = $raw_objprofile->objectProfile; |
|
$this->datastreams = $this->get_datastreams_list_as_array(); |
|
$this->ownerId = & Fedora_Item::getOwnerId($pid); |
|
} |
|
else { |
|
$this->objectProfile = ''; |
|
$this->datastreams = array(); |
|
$this->ownerId = NULL; |
|
} |
|
Fedora_Item::$instantiated_pids[$pid] = &$this; |
|
} |
|
} |
|
|
|
/** |
|
* Forget this Object, do manually when memory constraints apply. |
|
* |
|
* Removes this object from the static list of $instantiated_pids |
|
*/ |
|
function forget() { |
|
unset(Fedora_Item::$instantiated_pids[$this->pid]); |
|
} |
|
|
|
/** |
|
* Exists |
|
* |
|
* @return type |
|
*/ |
|
function exists() { |
|
return (!empty($this->objectProfile)); |
|
} |
|
|
|
/** |
|
* Add datastream from file |
|
* |
|
* @param type $datastream_file |
|
* @param type $datastream_id |
|
* @param type $datastream_label |
|
* @param type $datastream_mimetype |
|
* @param type $controlGroup |
|
* @param type $logMessage |
|
* |
|
* @return type |
|
*/ |
|
function add_datastream_from_file($datastream_file, $datastream_id, $datastream_label = NULL, $datastream_mimetype = '', $controlGroup = 'M', $logMessage = NULL) { |
|
module_load_include('inc', 'fedora_repository', 'MimeClass'); |
|
if (!is_file($datastream_file)) { |
|
drupal_set_message(t('The datastream file %datastream_file could not found! (or is not a regular file...)', array('%datastream_file' => $datastream_file)), 'warning'); |
|
return; |
|
} |
|
elseif (!is_readable($datastream_file)) { |
|
drupal_set_message(t('The datastream file %datastream_file could not be read! (likely due to permissions...)', array('%datastream_file' => $datastream_file)), 'warning'); |
|
return; |
|
} |
|
|
|
if (empty($datastream_mimetype)) { |
|
// Get mime type from the file extension. |
|
$mimetype_helper = new MimeClass(); |
|
$datastream_mimetype = $mimetype_helper->getType($datastream_file); |
|
} |
|
$original_path = $datastream_file; |
|
// Temporarily move file to a web-accessible location. |
|
file_copy($datastream_file, file_directory_path()); |
|
$datastream_url = drupal_urlencode($datastream_file); |
|
$url = file_create_url($datastream_url); |
|
|
|
// Add_datastream_from_url forces a re-sync of the datastream list. |
|
$return_value = $this->add_datastream_from_url($url, $datastream_id, $datastream_label, $datastream_mimetype, $controlGroup, $logMessage); |
|
|
|
if ($original_path != $datastream_file) { |
|
file_delete($datastream_file); |
|
} |
|
return $return_value; |
|
} |
|
|
|
/** |
|
* Add datastream from url |
|
* |
|
* @param type $datastream_url |
|
* @param type $datastream_id |
|
* @param type $datastream_label |
|
* @param type $datastream_mimetype |
|
* @param type $controlGroup |
|
* @param type $logMessage |
|
* |
|
* @return type |
|
*/ |
|
function add_datastream_from_url($datastream_url, $datastream_id, $datastream_label = NULL, $datastream_mimetype = '', $controlGroup = 'M', $logMessage = NULL) { |
|
global $base_url; |
|
|
|
if (empty($datastream_label)) { |
|
$datastream_label = $datastream_id; |
|
} |
|
|
|
// Fedora has some problems getting files from HTTPS connections sometimes, so if we are getting a file |
|
// from the local drupal, we try to pass a HTTP url instead of a HTTPS one. |
|
if (stripos($datastream_url, 'https://') !== FALSE && stripos($datastream_url, $base_url) !== FALSE) { |
|
$datastream_url = str_ireplace('https://', 'http://', $datastream_url); |
|
} |
|
|
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $datastream_id, |
|
'altIDs' => NULL, |
|
'dsLabel' => truncate_utf8($datastream_label, 255, TRUE, TRUE), |
|
'versionable' => TRUE, |
|
'MIMEType' => $datastream_mimetype, |
|
'formatURI' => NULL, |
|
'dsLocation' => $datastream_url, |
|
'controlGroup' => $controlGroup, |
|
'dsState' => 'A', |
|
'checksumType' => 'DISABLED', |
|
'checksum' => 'none', |
|
'logMessage' => ($logMessage != NULL) ? $logMessage : 'Ingested object ' . $datastream_id, |
|
); |
|
|
|
$soap_result = $this->soap_call('addDataStream', $params); |
|
// Make sure to refresh the datastream list after adding so this item stays in sync with the repository. |
|
$this->datastreams = $this->get_datastreams_list_as_array(); |
|
return $soap_result; |
|
} |
|
|
|
/** |
|
* Add datastream from string |
|
* |
|
* @param type $str |
|
* @param type $datastream_id |
|
* @param type $datastream_label |
|
* @param type $datastream_mimetype |
|
* @param type $controlGroup |
|
* @param type $logMessage |
|
* |
|
* @return type |
|
*/ |
|
function add_datastream_from_string($str, $datastream_id, $datastream_label = NULL, $datastream_mimetype = 'text/xml', $controlGroup = 'M', $logMessage = NULL) { |
|
$dir = file_directory_temp(); |
|
$tmpfilename = tempnam($dir, 'fedoratmp'); |
|
$tmpfile = fopen($tmpfilename, 'w'); |
|
fwrite($tmpfile, $str, strlen($str)); |
|
fclose($tmpfile); |
|
// Add_datastream_from_file forces a re-sync of the datastream list. |
|
$returnvalue = $this->add_datastream_from_file($tmpfilename, $datastream_id, $datastream_label, $datastream_mimetype, $controlGroup, $logMessage); |
|
unlink($tmpfilename); |
|
return $returnvalue; |
|
} |
|
|
|
/** |
|
* Wrapper to add new or modify existing datastream |
|
* |
|
* @global url $base_url |
|
* |
|
* @param url $external_url |
|
* @param string $dsid |
|
* @param string $label |
|
* @param string $mime_type |
|
* @param string $controlGroup |
|
* @param boolean $force |
|
* @param string $logMessage |
|
* @param boolean $quiet |
|
*/ |
|
function add_or_modify_by_reference($external_url, $dsid, $label, $mime_type, $controlGroup = 'M', $force = FALSE, $logMessage = 'Modified by Islandora API', $quiet=FALSE) { |
|
global $base_url; |
|
if (array_key_exists($dsid, $this->datastreams)) { |
|
$this->modify_datastream_by_reference($external_url, $dsid, $label, $mime_type, $force, $logMessage, $quiet); |
|
} |
|
else { |
|
$file_location = str_replace("$base_url/", '', $external_url); |
|
$this->add_datastream_from_file($file_location, $dsid, $label, $mime_type, $controlGroup = 'M', $logMessage = NULL); |
|
} |
|
} |
|
|
|
/** |
|
* |
|
* @param unknown_type $el |
|
* @param unknown_type $object |
|
* @param unknown_type $type |
|
*/ |
|
protected function buildRelsStatement(&$el, $object, $type) { |
|
if ($type > 0) { |
|
$el->appendChild($el->ownerDocument->createTextNode($object)); |
|
if ($type == RELS_TYPE_STRING) { |
|
$el->setAttribute('rdf:datatype', 'http://www.w3.org/2001/XMLSchema#string'); |
|
} |
|
elseif ($type == RELS_TYPE_INT) { |
|
$el->setAttribute('rdf:datatype', 'http://www.w3.org/2001/XMLSchema#int'); |
|
} |
|
elseif ($type == RELS_TYPE_DATETIME) { |
|
$el->setAttribute('rdf:datatype', 'http://www.w3.org/2001/XMLSchema#dateTime'); |
|
} |
|
else { |
|
// Plain literal. |
|
} |
|
} |
|
else { |
|
$el->setAttribute('rdf:resource', $object); |
|
} |
|
} |
|
|
|
/** |
|
* Add a relationship string to this object's RELS-EXT. |
|
* |
|
* does not support rels-int yet. |
|
* |
|
* @param string $relationship |
|
* The predicate/relationship tag to add |
|
* @param string $object |
|
* The object to be related to. |
|
* @param string $namespaceURI |
|
* The predicate namespace. |
|
* @param int $literal_value |
|
* Used to type the value. |
|
* - 0: URI |
|
* - 1: plain literal |
|
* - 2: string (explicitly typed) |
|
* - 3: integer |
|
* - 4: dateTime |
|
* |
|
* @return ??? |
|
* Value returned from SOAP call for modify_datastream. |
|
*/ |
|
function add_relationship($relationship, $object, $namespaceURI = RELS_EXT_URI, $literal_value = RELS_TYPE_URI) { |
|
static $relsextxml = NULL; |
|
if ($relsextxml === NULL) { |
|
// Avoid new instantiations in long-running processes. |
|
$relsextxml = new DOMDocument(); |
|
} |
|
|
|
$ds_list = $this->datastreams; |
|
|
|
$f_prefix = 'info:fedora/'; |
|
if (!array_key_exists('RELS-EXT', $ds_list)) { |
|
$rdf_string = <<<RDF |
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"> |
|
<rdf:Description rdf:about="$f_prefix{$this->pid}"> |
|
</rdf:Description> |
|
</rdf:RDF> |
|
RDF; |
|
$this->add_datastream_from_string($rdf_string, 'RELS-EXT', 'Fedora object-to-object relationship metadata', 'application/rdf+xml', 'X'); |
|
} |
|
|
|
$relsext = $this->get_datastream_dissemination('RELS-EXT'); |
|
|
|
if ($literal_value == RELS_TYPE_URI && strpos($object, $f_prefix) !== 0) { |
|
$object = $f_prefix . $object; |
|
} |
|
|
|
$relsextxml->loadXML($relsext); |
|
$description = $relsextxml->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'Description'); |
|
if ($description->length == 0) { |
|
// XXX: This really shouldn't be done; lower case d doesn't fit the schema. Warn users to fix the data and generators, pending deprecation. |
|
$description = $relsextxml->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'description'); |
|
if ($description->length > 0) { |
|
drupal_set_message(t('RDF with lower case "d" in "description" encountered. Should be uppercase! PID: %pid', array('%pid' => $this->pid)), 'warning'); |
|
} |
|
} |
|
$description = $description->item(0); |
|
|
|
// Create the new relationship node. |
|
$newrel = $relsextxml->createElementNS($namespaceURI, $relationship); |
|
|
|
$this->buildRelsStatement($newrel, $object, $literal_value); |
|
|
|
$description->appendChild($newrel); |
|
|
|
return $this->modify_datastream($relsextxml->saveXML(), 'RELS-EXT', "Fedora Object-to-Object Relationship Metadata", 'application/rdf+xml'); |
|
} |
|
|
|
/** |
|
* Extension of add_relationship, which acts on RELS-INT. |
|
* |
|
* @param $dsid |
|
* A string containing either the base dsid (EXAMPLE) |
|
* or URI to the datastream (info:fedora/pid/EXAMPLE) |
|
*/ |
|
function add_dsid_relationship($dsid, $relationship, $object, $namespaceURI = RELS_EXT_URI, $literal_value = RELS_TYPE_URI) { |
|
static $relsxml = NULL; |
|
if ($relsxml === NULL) { |
|
// Avoid new instantiations in long-running processes. |
|
$relsxml = new DOMDocument(); |
|
} |
|
|
|
$f_prefix = 'info:fedora/'; |
|
if (!array_key_exists('RELS-INT', $this->datastreams)) { |
|
$rdf_string = <<<RDF |
|
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"/> |
|
RDF; |
|
$this->add_datastream_from_string($rdf_string, 'RELS-INT', 'Fedora datastream relationship metadata', 'application/rdf+xml', 'X'); |
|
} |
|
|
|
$rels_text = $this->get_datastream_dissemination('RELS-INT'); |
|
|
|
if ($literal_value == RELS_TYPE_URI && strpos($object, $f_prefix) !== 0) { |
|
$object = $f_prefix . $object; |
|
} |
|
if (strpos($dsid, $f_prefix) !== 0) { |
|
$dsid = $f_prefix . $this->pid . '/' . $dsid; |
|
} |
|
|
|
$relsxml->loadXML($rels_text); |
|
$descs = $relsxml->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'Description'); |
|
$description = NULL; |
|
foreach ($descs as $desc) { |
|
if ($desc->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'about') == $dsid) { |
|
$description = $desc; |
|
break; |
|
} |
|
} |
|
|
|
// Create the description element if we didn't find it... |
|
if ($description === NULL) { |
|
$description = $relsxml->createElementNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:Description'); |
|
$description->setAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'rdf:about', $dsid); |
|
$relsxml->documentElement->appendChild($description); |
|
} |
|
|
|
// Create the new relationship node. |
|
$newrel = $relsxml->createElementNS($namespaceURI, $relationship); |
|
|
|
$this->buildRelsStatement($newrel, $object, $literal_value); |
|
|
|
$description->appendChild($newrel); |
|
|
|
return $this->modify_datastream($relsxml->saveXML(), 'RELS-INT', "Fedora Datastream Relationship Metadata", 'application/rdf+xml'); |
|
} |
|
|
|
/** |
|
* Purge/delete relationships string from this object's RELS-EXT. |
|
* |
|
* does not support rels-int yet. |
|
* |
|
* @param string $relationship |
|
* The predicate/relationship tag to delete |
|
* @param string $object |
|
* The object to be related to. (NULL/value for which empty() |
|
* evaluates to true will remove all relations of the given type, |
|
* ignoring $literal_value) |
|
* @param string $namespaceURI |
|
* The predicate namespace. |
|
* @param int $literal_value |
|
* Same as add_relationship. NOTE: dateTime implemented. |
|
* @return boolean |
|
* Whether or not this operation has produced any changes in the RELS-EXT |
|
*/ |
|
function purge_relationships($relationship, $object, $namespaceURI = RELS_EXT_URI, $literal_value = FALSE) { |
|
$relsext = trim($this->get_datastream_dissemination('RELS-EXT')); |
|
|
|
$relsextxml = new DOMDocument(); |
|
$modified = FALSE; |
|
|
|
if ($relsext && $relsextxml->loadXML($relsext)) { |
|
$rels = $relsextxml->getElementsByTagNameNS($namespaceURI, $relationship); |
|
if (!empty($rels)) { |
|
// Iterate backwards so if we delete something our pointer doesn't get out of sync. |
|
for ($i = $rels->length; $i > 0; $i--) { |
|
$rel = $rels->item($i - 1); |
|
// Foreach ($rels as $rel) { // moving forward like this caused iteration errors when something was deleted. |
|
if ( |
|
// If either no object is specified, or the object matches (in either the literal or URI case), remove this node from it's parent, and mark as changed. |
|
empty($object) || |
|
(($literal_value == RELS_TYPE_URI) && $rel->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource') == $object) || |
|
(($literal_value == RELS_TYPE_PLAIN_LITERAL) && $rel->textContent == $object) || |
|
(($literal_value == RELS_TYPE_STRING) && $rel->getAttribute('rdf:datatype') == 'http://www.w3.org/2001/XMLSchema#string' && $rel->textContent == $object) || |
|
(($literal_value == RELS_TYPE_INT) && $rel->getAttribute('rdf:datatype') == 'http://www.w3.org/2001/XMLSchema#int' && intval($rel->textContent) == $object)) { |
|
$rel->parentNode->removeChild($rel); |
|
$modified = TRUE; |
|
} |
|
} |
|
} |
|
|
|
// Save changes. |
|
if ($modified) { |
|
$this->modify_datastream($relsextxml->saveXML(), 'RELS-EXT', "Fedora Object-to-Object Relationship Metadata", 'text/xml'); |
|
} |
|
} |
|
// Return whether or not we've introduced any changes. |
|
return $modified; |
|
} |
|
|
|
/** |
|
* Extension of purge_relationships, which acts on RELS-INT. |
|
* |
|
* @param string $dsid |
|
* A string containing either the base dsid (EXAMPLE) |
|
* or URI to the datastream (info:fedora/pid/EXAMPLE) |
|
*/ |
|
function purge_dsid_relationships($dsid, $relationship, $object, $namespaceURI = RELS_EXT_URI, $literal_value = FALSE) { |
|
$f_prefix = 'info:fedora/'; |
|
if (strpos($dsid, $f_prefix) !== 0) { |
|
$dsid = $f_prefix . $this->pid . '/' . $dsid; |
|
} |
|
|
|
$relsxml = new DOMDocument(); |
|
$relsint = trim($this->get_datastream_dissemination('RELS-INT')); |
|
$modified = FALSE; |
|
if ($relsint && $relsxml->loadXML($relsint)) { |
|
|
|
|
|
$descs = $relsxml->getElementsByTagNameNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'Description'); |
|
$description = NULL; |
|
foreach ($descs as $desc) { |
|
if ($dsid === NULL || $desc->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'about') == $dsid) { |
|
$rels = $desc->getElementsByTagNameNS($namespaceURI, $relationship); |
|
if (!empty($rels)) { |
|
// Iterate backwards so if we delete something our pointer doesn't get out of sync. |
|
for ($i = $rels->length; $i>0; $i--) { |
|
$rel = $rels->item($i-1); |
|
// foreach ($rels as $rel) { // moving forward like this caused iteration errors when something was deleted |
|
// If either no object is specified, or the object matches (in either the literal or URI case), remove this node from it's parent, and mark as changed. |
|
if ( |
|
empty($object) || |
|
(($literal_value == RELS_TYPE_URI) && $rel->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource') == $object) || |
|
(($literal_value == RELS_TYPE_PLAIN_LITERAL) && $rel->textContent == $object) || |
|
(($literal_value == RELS_TYPE_STRING) && $rel->getAttribute('rdf:datatype') == 'http://www.w3.org/2001/XMLSchema#string' && $rel->textContent == $object) || |
|
(($literal_value == RELS_TYPE_INT) && $rel->getAttribute('rdf:datatype') == 'http://www.w3.org/2001/XMLSchema#int' && intval($rel->textContent) == $object)) { |
|
$rel->parentNode->removeChild($rel); |
|
$modified = TRUE; |
|
} |
|
} |
|
} |
|
|
|
if ($desc->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'about') == $dsid) { |
|
break; |
|
} |
|
} |
|
} |
|
|
|
// Save changes. |
|
if ($modified) { |
|
$this->modify_datastream($relsxml->saveXML(), 'RELS-INT', "Fedora Datastream Relationship Metadata", 'text/xml'); |
|
} |
|
} |
|
|
|
// Return whether or not we've introduced any changes. |
|
return $modified; |
|
} |
|
|
|
/** |
|
* Removes the given relationship from the item's RELS-EXT and re-saves it. |
|
* |
|
* @deprecated |
|
* Dropped in favour of purge_relationships, which follows the same paradigm as add_relationship. This function tries to figure out the predicate URI based on the prefix/predicate given, which requires specific naming... |
|
* @param string $relationship |
|
* @param string $object |
|
*/ |
|
function purge_relationship($relationship, $object) { |
|
$relsext = $this->get_datastream_dissemination('RELS-EXT'); |
|
$namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; |
|
// Pre-pend a namespace prefix to recognized relationships |
|
|
|
switch ($relationship) { |
|
case 'rel:isMemberOf': |
|
case 'fedora:isMemberOf': |
|
$relationship = "isMemberOf"; |
|
$namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; |
|
break; |
|
case "rel:isMemberOfCollection": |
|
case "fedora:isMemberOfCollection": |
|
$relationship = "isMemberOfCollection"; |
|
$namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; |
|
break; |
|
case "fedora:isPartOf": |
|
$relationship = "isPartOf"; |
|
$namespaceURI = 'info:fedora/fedora-system:def/relations-external#'; |
|
break; |
|
case "rel:hasModel": |
|
case "hasModel": |
|
$relationship = "hasModel"; |
|
$namespaceURI = FEDORA_MODEL_URI; |
|
break; |
|
case "isPageNumber": |
|
$relationship = "isPageNumber"; |
|
$namespaceURI = ISLANDORA_PAGE_URI; |
|
break; |
|
} |
|
|
|
if (!empty($object) && substr($object, 0, 12) != 'info:fedora/') { |
|
$object = "info:fedora/$object"; |
|
} |
|
|
|
$relsextxml = new DomDocument(); |
|
$relsextxml->loadXML($relsext); |
|
$modified = FALSE; |
|
$rels = $relsextxml->getElementsByTagNameNS($namespaceURI, $relationship); |
|
if (!empty($rels)) { |
|
foreach ($rels as $rel) { |
|
if (empty($object) || $rel->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource') == $object) { |
|
$rel->parentNode->removeChild($rel); |
|
$modified = TRUE; |
|
} |
|
} |
|
} |
|
if ($modified) { |
|
$this->modify_datastream($relsextxml->saveXML(), 'RELS-EXT', "Fedora Object-to-Object Relationship Metadata", 'text/xml'); |
|
} |
|
return $modified; |
|
} |
|
|
|
/** |
|
* Export as foxml |
|
* |
|
* @return type |
|
*/ |
|
function export_as_foxml() { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'format' => 'info:fedora/fedora-system:FOXML-1.1', |
|
'context' => 'migrate', |
|
); |
|
$result = self::soap_call('export', $params); |
|
return $result->objectXML; |
|
} |
|
|
|
/** |
|
* Does a search using the "query" format followed by the Fedora REST APi. |
|
* |
|
* @param string $pattern to search for, including wildcards. |
|
* @param string $field The field to search on, e.g. pid, title, cDate. See http://www.fedora-commons.org/confluence/display/FCR30/REST+API#RESTAPI-findObjects for details |
|
* @param int $max_results not used at this time |
|
* |
|
* @return Array of pid => title pairs that match the results |
|
*/ |
|
static function find_objects_by_pattern($pattern = '*', $field = 'pid', $max_results = 100, $resultFields = array()) { |
|
module_load_include('inc', 'fedora_repository', 'api/fedora_utils'); |
|
|
|
$pattern = drupal_urlencode($pattern); |
|
$done = FALSE; |
|
$cursor = 0; |
|
$session_token = ''; |
|
$i = 0; |
|
$results = array(); |
|
while (!$done && $i < 5) { |
|
$i++; |
|
$url = variable_get('fedora_base_url', 'http://localhost:8080/fedora'); |
|
if ($cursor == 0) { |
|
$url .= "/objects?query=$field~$pattern&pid=true&title=TRUE&resultFormat=xml&maxResults=$max_results"; |
|
} |
|
else { |
|
$url .= "/objects?pid=true&title=true&sessionToken=$session_token&resultFormat=xml&maxResults=$max_results"; |
|
} |
|
|
|
if (count($resultFields) > 0) { |
|
$url .= '&' . join('=true&', $resultFields) . '=true'; |
|
} |
|
|
|
$resultxml = do_curl($url); |
|
libxml_use_internal_errors(TRUE); |
|
$resultelements = simplexml_load_string($resultxml); |
|
if ($resultelements === FALSE) { |
|
libxml_clear_errors(); |
|
break; |
|
} |
|
$cursor += count($resultelements->resultList->objectFields); |
|
if (count($resultelements->resultList->objectFields) < $max_results |
|
|| count($resultelements->resultList->objectFields) == 0) { |
|
$done = TRUE; |
|
} |
|
foreach ($resultelements->resultList->objectFields as $obj) { |
|
|
|
$ret = (string) $obj->title; |
|
if (count($resultFields) > 0) { |
|
$ret = array('title' => $ret); |
|
foreach ($resultFields as $field) { |
|
$ret[$field] = (string) $obj->$field; |
|
} |
|
} |
|
$results[(string) $obj->pid] = $ret; |
|
$cursor++; |
|
if ($cursor >= $max_results) { |
|
$done = TRUE; |
|
break; |
|
} |
|
} |
|
$session_token = $resultelements->listSession->token; |
|
$done = !empty($session_token); |
|
} |
|
return $results; |
|
} |
|
|
|
/** |
|
* Get datastream dissemination |
|
* |
|
* @param type $dsid |
|
* @param type $as_of_date_time |
|
* @param type $quiet |
|
* |
|
* @return null |
|
*/ |
|
function get_datastream_dissemination($dsid, $as_of_date_time = "", $quiet=TRUE) { |
|
if (!array_key_exists($dsid, $this->datastreams)) { |
|
return NULL; |
|
} |
|
|
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
'asOfDateTime' => $as_of_date_time, |
|
); |
|
|
|
// Make soap call with quite |
|
$object = self::soap_call('getDataStreamDissemination', $params, $quiet); |
|
if (!empty($object)) { |
|
$content = $object->dissemination->stream; |
|
$content = trim($content); |
|
} |
|
else { |
|
$content = NULL; |
|
} |
|
return $content; |
|
} |
|
|
|
/** |
|
* Get datastream |
|
* |
|
* @param type $dsid |
|
* @param type $as_of_date_time |
|
* |
|
* @return type |
|
*/ |
|
function get_datastream($dsid, $as_of_date_time = '', $quiet = TRUE) { |
|
if (!array_key_exists($dsid, $this->datastreams)) { |
|
return NULL; |
|
} |
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
'asOfDateTime' => $as_of_date_time, |
|
); |
|
$object = self::soap_call('getDatastream', $params, $quiet); |
|
|
|
return $object->datastream; |
|
} |
|
|
|
/** |
|
* Get datastream history |
|
* |
|
* @param type $dsid |
|
* |
|
* @return type |
|
*/ |
|
function get_datastream_history($dsid) { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
); |
|
$object = self::soap_call('getDatastreamHistory', $params); |
|
$ret = FALSE; |
|
if (!empty($object)) { |
|
$ret = $object->datastream; |
|
} |
|
|
|
return $ret; |
|
} |
|
|
|
/** |
|
* Get dissemination |
|
* |
|
* @param type $service_definition_pid |
|
* @param type $method_name |
|
* @param type $parameters |
|
* @param type $as_of_date_time |
|
* |
|
* @return string |
|
*/ |
|
function get_dissemination($service_definition_pid, $method_name, $parameters = array(), $as_of_date_time = NULL) { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'serviceDefinitionPid' => $service_definition_pid, |
|
'methodName' => $method_name, |
|
'parameters' => $parameters, |
|
'asOfDateTime' => $as_of_date_time, |
|
); |
|
$object = self::soap_call('getDissemination', $params); |
|
if (!empty($object)) { |
|
$content = $object->dissemination->stream; |
|
$content = trim($content); |
|
} |
|
else { |
|
$content = ""; |
|
} |
|
return $content; |
|
} |
|
|
|
/** |
|
* Retrieves and returns a SimpleXML list of this item's datastreams, |
|
* and stores them as an instance variable for caching purposes. |
|
* |
|
* @return SimpleXMLElement |
|
*/ |
|
function get_datastreams_list_as_SimpleXML() { |
|
//if ( empty( $this->datastreams_list ) ) { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'asOfDateTime' => "", |
|
); |
|
|
|
$this->datastreams_list = $this->soap_call('listDataStreams', $params); |
|
//} |
|
return $this->datastreams_list; |
|
} |
|
|
|
/** |
|
* DatastreamControlGroup controlGroup - String restricted to the values of "X", "M", "R", or "E" (InlineXML,Managed Content,Redirect, or External Referenced). |
|
* String ID - The datastream ID (64 characters max). |
|
* String versionID - The ID of the most recent datastream version |
|
* String[] altIDs - Alternative IDs for the datastream, if any. |
|
* String label - The Label of the datastream. |
|
* boolean versionable - Whether the datastream is versionable. |
|
* String MIMEType - The mime-type for the datastream, if set. |
|
* String formatURI - The format uri for the datastream, if set. |
|
* String createDate - The date the first version of the datastream was created. |
|
* long size - The size of the datastream in Fedora. Only valid for inline XML metadata and managed content datastreams. |
|
* String state - The state of the datastream. Will be "A" (active), "I" (inactive) or "D" (deleted). |
|
* String location - If the datastream is an external reference or redirect, the url to the contents. TODO: Managed? |
|
* String checksumType - The algorithm used to compute the checksum. One of "DEFAULT", "DISABLED", "MD5", "SHA-1", "SHA-256", "SHA-385", "SHA-512". |
|
* String checksum - The value of the checksum represented as a hexadecimal string. |
|
|
|
* |
|
* @param string $dsid |
|
* |
|
* @return datastream object |
|
* get the mimetype size etc. in one shot. instead of iterating throught the datastream list for what we need |
|
*/ |
|
function get_datastream_info($dsid, $as_of_date_time = '') { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
'asOfDateTime' => $as_of_date_time, |
|
); |
|
|
|
return $this->soap_call('getDatastream', $params); |
|
} |
|
|
|
/** |
|
* Returns an associative array of this object's datastreams. |
|
* Results look like this: |
|
* |
|
* 'DC' => |
|
* array |
|
* 'label' => string 'Dublin Core Record for this object' (length=34) |
|
* 'MIMEType' => string 'text/xml' (length=8) |
|
* 'RELS-EXT' => |
|
* array |
|
* 'label' => string 'RDF Statements about this object' (length=32) |
|
* 'MIMEType' => string 'application/rdf+xml' (length=19) |
|
* |
|
* @return array |
|
*/ |
|
function get_datastreams_list_as_array() { |
|
$this->get_datastreams_list_as_SimpleXML(); |
|
$ds_list = array(); |
|
if ($this->datastreams_list != FALSE) { |
|
|
|
// This is a really annoying edge case: if there is only one |
|
// datastream, instead of returning it as an array, only |
|
// the single item will be returned directly. We have to |
|
// check for this. |
|
$xml_list = $this->datastreams_list->datastreamDef; |
|
if (!is_array($this->datastreams_list->datastreamDef)) { |
|
$xml_list = array($xml_list); |
|
} |
|
|
|
foreach ($xml_list as $ds) { |
|
if (!is_object($ds)) { |
|
print_r($ds); |
|
} |
|
$ds_list[$ds->ID]['label'] = $ds->label; |
|
$ds_list[$ds->ID]['MIMEType'] = $ds->MIMEType; |
|
$ds_list[$ds->ID]['URL'] = $this->url() . '/' . $ds->ID . '/' . drupal_urlencode($ds->label); |
|
} |
|
} |
|
|
|
return $ds_list; |
|
} |
|
|
|
/** |
|
* Returns a MIME type string for the given Datastream ID. |
|
* |
|
* @param string $dsid |
|
* @return string |
|
*/ |
|
function get_mimetype_of_datastream($dsid) { |
|
$this->get_datastreams_list_as_SimpleXML(); |
|
|
|
$mimetype = ''; |
|
foreach ($datastream_list as $datastream) { |
|
foreach ($datastream as $datastreamValue) { |
|
if ($datastreamValue->ID == $dsid) { |
|
return $datastreamValue->MIMEType; |
|
} |
|
} |
|
} |
|
|
|
return ''; |
|
} |
|
|
|
/** |
|
* Currently the Fedora API call getRelationships is reporting an uncaught |
|
* exception so we will parse the RELS-EXT ourselves and simulate the |
|
* documented behaviour. |
|
* |
|
* @param String $relationship - filter the results to match this string. |
|
*/ |
|
function get_relationships($relationship = NULL) { |
|
$relationships = array(); |
|
try { |
|
$relsext = $this->get_datastream_dissemination('RELS-EXT'); |
|
} catch (exception $e) { |
|
drupal_set_message(t("Error retrieving RELS-EXT of object $pid"), 'error'); |
|
return $relationships; |
|
} |
|
|
|
// Parse the RELS-EXT into an associative array. |
|
$relsextxml = new DOMDocument(); |
|
$relsextxml->loadXML($relsext); |
|
$relsextxml->normalizeDocument(); |
|
$rels = $relsextxml->getElementsByTagNameNS('info:fedora/fedora-system:def/relations-external#', '*'); |
|
foreach ($rels as $child) { |
|
if (empty($relationship) || preg_match("/$relationship/", $child->tagName)) { |
|
$relationships[] = array( |
|
'subject' => $this->pid, |
|
'predicate' => $child->tagName, |
|
'object' => substr($child->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource'), 12), |
|
); |
|
} |
|
} |
|
|
|
return $relationships; |
|
} |
|
|
|
/** |
|
* Retrieves RELS-EXT values from item |
|
* |
|
* @param array $namespaces |
|
* |
|
* @return array |
|
*/ |
|
function get_rdf_relationships($namespaces = null) { |
|
if ($namespaces == NULL) { |
|
$namespaces = array( |
|
RELS_EXT_URI, |
|
FEDORA_MODEL_URI, |
|
ISLANDORA_PAGE_URI, |
|
ISLANDORA_RELS_EXT_URI, |
|
ISLANDORA_RELS_INT_URI, |
|
); |
|
} |
|
if (!is_array($namespaces)) { |
|
$namespaces = array($namespaces); |
|
} |
|
$relationships = array(); |
|
try { |
|
$relsext = $this->get_datastream_dissemination('RELS-EXT'); |
|
} catch (exception $e) { |
|
drupal_set_message(t('Error retrieving RELS-EXT of object %pid.', array('%pid' => $pid)), 'error'); |
|
return $relationships; |
|
} |
|
|
|
// Parse the RELS-EXT into an associative array. |
|
$relsextxml = new DOMDocument(); |
|
$relsextxml->loadXML($relsext); |
|
$relsextxml->normalizeDocument(); |
|
$allTags = array(); |
|
foreach ($namespaces as $namespace) { |
|
$allTags[] = $relsextxml->getElementsByTagNameNS($namespace, '*'); |
|
} |
|
|
|
foreach ($allTags as $tags) { |
|
foreach ($tags as $child) { |
|
$value = preg_replace('/info:fedora\//', '', $child->getAttributeNS('http://www.w3.org/1999/02/22-rdf-syntax-ns#', 'resource')); |
|
if (!$value) { |
|
$value = $child->textContent; |
|
} |
|
$relationships[$child->tagName][] = $value; |
|
} |
|
} |
|
|
|
return $relationships; |
|
} |
|
|
|
function get_models() { |
|
//This is/was formerly just a copy/paste jobbie, without the parameter being passable... |
|
return $this->get_relationships(); |
|
} |
|
|
|
/** |
|
* Creates a RELS-EXT XML stream from the supplied array and saves it to |
|
* the item on the server. |
|
* |
|
* @param <type> $relationships |
|
*/ |
|
function save_relationships($relationships) { |
|
// Verify the array format and that it isn't empty. |
|
if (!empty($relationships)) { |
|
$relsextxml = '<rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:fedora="info:fedora/fedora-system:def/relations-external#" xmlns:fedora-model="info:fedora/fedora-system:def/model#" xmlns:oai_dc="http://www.openarchives.org/OAI/2.0/oai_dc/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#">' |
|
. '<rdf:description rdf:about="' . $this->pid . '">'; |
|
|
|
foreach ($relationships as $rel) { |
|
if (empty($rel['subject']) || empty($rel['predicate']) || empty($rel['object']) || $rel['subject'] != 'info:fedora/' . $this->pid) { |
|
// drupal_set_message should use parameterized variables, not interpolated. |
|
drupal_set_message(t("Error with relationship format: " . $rel['subject'] . " - " . $rel['predicate'] . ' - ' . $rel['object']), "error"); |
|
return FALSE; |
|
} |
|
} |
|
} |
|
|
|
// Do the messy work constructing the RELS-EXT XML. Because addRelationship is broken. |
|
return FALSE; |
|
} |
|
|
|
/** |
|
* Set the object to a deleted state |
|
*/ |
|
function move_to_trash($log_message = 'Flagged deleted using Islandora API.', $quiet = TRUE) { |
|
// Loop through the datastreams and mark them deleted. |
|
foreach ($this->get_datastreams_list_as_array() as $dsid => $info) { |
|
$this->set_datastream_state($dsid, 'D'); |
|
} |
|
|
|
// Create a message to mark the object deleted. |
|
$params = array( |
|
'pid' => $this->pid, |
|
'state' => 'D', |
|
'logMessage' => $log_message, |
|
'label' => $this->objectProfile->objLabel, |
|
'ownerId' => null, |
|
); |
|
|
|
// Send message to mark the object deleted. |
|
return self::soap_call('modifyObject', $params, $quiet); |
|
} |
|
|
|
/** |
|
* Removes this object form the repository. |
|
* @param type $log_message |
|
* @param type $force |
|
* @return type |
|
*/ |
|
function purge($log_message = 'Purged using Islandora API.', $force = FALSE) { |
|
|
|
// Flag the object to be deleted first. |
|
$this->move_to_trash($log_message); |
|
|
|
// Create the delete message. |
|
$params = array( |
|
'pid' => $this->pid, |
|
'logMessage' => $log_message, |
|
'force' => $force, |
|
); |
|
|
|
$this->forget(); |
|
|
|
// Delete the object. |
|
return $this->soap_call('purgeObject', $params); |
|
} |
|
|
|
/** |
|
* Purge datastream |
|
* |
|
* @param type $dsID |
|
* @param type $start_date |
|
* @param type $end_date |
|
* @param type $log_message |
|
* @param type $force |
|
* |
|
* @return type |
|
*/ |
|
function purge_datastream($dsID, $start_date = NULL, $end_date = NULL, $log_message = 'Purged datastream using Islandora API', $force = FALSE) { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsID, |
|
'startDT' => $start_date, |
|
'endDT' => $end_date, |
|
'logMessage' => $log_message, |
|
'force' => $force, |
|
); |
|
$soap_result = $this->soap_call('purgeDatastream', $params); |
|
// Make sure to refresh the datastream list after adding so this item stays in sync with the repository. |
|
$this->datastreams = $this->get_datastreams_list_as_array(); |
|
return $soap_result; |
|
} |
|
|
|
/** |
|
* URL |
|
* @global type $base_url |
|
* |
|
* @return type |
|
*/ |
|
function url() { |
|
return url('fedora/repository/' . $this->pid . (!empty($this->objectProfile) ? '/-/' . drupal_urlencode($this->objectProfile->objLabel) : ''), array( |
|
'absolute' => TRUE, |
|
)); |
|
} |
|
|
|
/** |
|
* Get Next PID in Namespace |
|
* |
|
* @param $pid_namespace string |
|
* |
|
* @return string |
|
*/ |
|
static function get_next_PID_in_namespace($pid_namespace = '', $number_of_pids = 1) { |
|
if (empty($pid_namespace)) { |
|
// Just get the first one in the config settings. |
|
$allowed_namespaces = explode(" ", variable_get('fedora_pids_allowed', 'default: demo: changeme: islandora: ilives: islandora-book: books: newspapers: ')); |
|
$pid_namespace = $allowed_namespaces[0]; |
|
if (!empty($pid_namespace)) { |
|
$pid_namespace = substr($pid_namespace, 0, strpos($pid_namespace, ":")); |
|
} |
|
else { |
|
$pid_namespace = 'default'; |
|
} |
|
} |
|
|
|
$params = array( |
|
'numPIDs' => $number_of_pids, |
|
'pidNamespace' => $pid_namespace, |
|
); |
|
|
|
$result = self::soap_call('getNextPID', $params); |
|
|
|
return $result->pid; |
|
} |
|
|
|
/** |
|
* ingest from FOXML |
|
* |
|
* @param type $foxml |
|
* |
|
* @return Fedora_Item |
|
*/ |
|
static function ingest_from_FOXML(DOMDocument $foxml) { |
|
$params = array( |
|
'objectXML' => $foxml->saveXML(), |
|
'format' => 'info:fedora/fedora-system:FOXML-1.1', |
|
'logMessage' => 'Fedora Object Ingested', |
|
); |
|
$object = self::soap_call('ingest', $params); |
|
return new Fedora_Item($object->objectPID); |
|
} |
|
|
|
/** |
|
* ingest from FOXML file |
|
* |
|
* @param type $foxml_file |
|
* |
|
* @return type |
|
*/ |
|
static function ingest_from_FOXML_file($foxml_file) { |
|
$foxml = new DOMDocument(); |
|
$foxml->load($foxml_file); |
|
return self::ingest_from_FOXML($foxml); |
|
} |
|
|
|
/** |
|
* ingest from FOXML files in directory |
|
* |
|
* @param type $path |
|
*/ |
|
static function ingest_from_FOXML_files_in_directory($path) { |
|
// Open the directory. |
|
$dir_handle = @opendir($path); |
|
// Loop through the files. |
|
while ($file = readdir($dir_handle)) { |
|
if ($file == "." || $file == ".." || strtolower(substr($file, strlen($file) - 4)) != '.xml') { |
|
continue; |
|
} |
|
|
|
try { |
|
self::ingest_from_FOXML_file($path . '/' . $file); |
|
} catch (exception $e) { |
|
|
|
} |
|
} |
|
// Close. |
|
closedir($dir_handle); |
|
} |
|
|
|
/** |
|
* Modify Object |
|
* |
|
* @param $label string |
|
* @param $state string |
|
* @param $ownerId string |
|
* @param $logMessage string |
|
* @param $quiet boolean |
|
* |
|
* @return type |
|
*/ |
|
function modify_object($label = '', $state = NULL, $ownerId = NULL, $logMessage = 'Modified by Islandora API', $quiet=TRUE) { |
|
|
|
$params = array( |
|
'pid' => $this->pid, |
|
// Default to the current owner if none is provided.. |
|
'ownerId' => (($ownerId !== NULL) ? |
|
$ownerId : |
|
$this->ownerId), |
|
'state' => $state, |
|
'label' => $label, |
|
'logMessage' => $logMessage, |
|
); |
|
|
|
return self::soap_call('modifyObject', $params, $quiet); |
|
} |
|
|
|
/** |
|
* Work around function, due to file_create_url not URL encoding stuff. |
|
* |
|
* Parses and reassembles the URL, exploding, rawurlencoding and imploding |
|
* the path components along the way. |
|
* |
|
* @param $url |
|
* A string containing an HTTP(S) URL to attempt. |
|
* |
|
* @return string |
|
* The results of the HTTP request if successful; boolean FALSE otherwise. |
|
*/ |
|
protected static function try_http_get_content($url) { |
|
// Can throw a warning prior to 5.3.3. |
|
$parsed_url = @parse_url($url); |
|
$supported_schemes = array( |
|
'http', |
|
'https', |
|
); |
|
|
|
$content = FALSE; |
|
|
|
if ($parsed_url && array_key_exists('scheme', $parsed_url) && in_array($parsed_url['scheme'], $supported_schemes)) { |
|
$components = explode('/', $parsed_url['path']); |
|
$components = array_map('rawurlencode', $components); |
|
$fixed_url = url( |
|
t( |
|
'!scheme://!user:!pass@!host:!port/!path', |
|
array( |
|
'!scheme' => $parsed_url['scheme'], |
|
'!user' => rawurlencode($parsed_url['user']), |
|
'!pass' => rawurlencode($parsed_url['pass']), |
|
'!host' => $parsed_url['host'], |
|
'!port' => $parsed_url['port'], |
|
'!path' => implode('/', $components), |
|
) |
|
), |
|
array( |
|
'query' => $parsed_url['query'], |
|
'fragment' => $parsed_url['fragment'], |
|
) |
|
); |
|
$result = drupal_http_request($fixed_url); |
|
|
|
if ((int) ($result->code / 100) === 2) { |
|
$content = $result->data; |
|
} |
|
else { |
|
watchdog('fedora_repository', 'Failed making HTTP request to @URL. Info: @info', array( |
|
'@URL' => $fixed_url, |
|
'@info' => print_r($result, TRUE), |
|
), 'warning'); |
|
} |
|
} |
|
|
|
return $content; |
|
} |
|
|
|
/** |
|
* Wrap modify by value and reference |
|
* |
|
* Wrap modify by value and reference, so that the proper one gets called |
|
* in the correct instance. (value if inline XML, reference otherwise) |
|
* |
|
* First tries to treat the passed in value as a filename, tries using as contents second. |
|
* Coerces the data into what is required, and passes it on to the relevant function. |
|
* |
|
* @param string $filename_or_content |
|
* Either a filename to add, or an string of content. |
|
* @param string $dsid |
|
* The DSID to update |
|
* @param string $label |
|
* A label to withwhich to update the datastream |
|
* @param string $mime_type |
|
* Mimetype for the data being pushed into the datastream |
|
* @param boolean $force |
|
* Dunno, refer to underlying functions/SOAP interface. We just pass it like a chump. |
|
* @param string $logMessage |
|
* A message for the audit log. |
|
* @param boolean $quiet |
|
* Error suppression? Refer to soap_call for usage |
|
* (just passed along here). |
|
*/ |
|
function modify_datastream($filename_or_content, $dsid, $label, $mime_type, $force = FALSE, $logMessage='Modified by Islandora API', $quiet=FALSE) { |
|
$toReturn = NULL; |
|
|
|
// Determine if it's inline xml; if it is, modify by value. |
|
if ($this->get_datastream($dsid)->controlGroup === 'X') { |
|
$content = '<null/>'; |
|
if (is_file($filename_or_content) && is_readable($filename_or_content)) { |
|
$content = file_get_contents($filename_or_content); |
|
} |
|
else { |
|
// XXX: Get the contents to deal with fopen not being allowed for remote access |
|
//in some OSs |
|
$temp_content = self::try_http_get_content($filename_or_content); |
|
if ($temp_content !== FALSE) { |
|
$content = $temp_content; |
|
} |
|
else { |
|
$content = $filename_or_content; |
|
} |
|
} |
|
|
|
$toReturn = $this->modify_datastream_by_value($content, $dsid, $label, $mime_type, $force, $logMessage); |
|
} |
|
// Otherwise, write to web-accessible temp file and modify by reference. |
|
else { |
|
$file = ''; |
|
$created_temp = FALSE; |
|
if (is_file($filename_or_content) && is_readable($filename_or_content)) { |
|
$file = $filename_or_content; |
|
$original_path = $file; |
|
// Temporarily move file to a web-accessible location. |
|
file_copy($file, file_directory_path()); |
|
$created_temp = ($original_path != $file); |
|
} |
|
else { |
|
// XXX: Get the contents to deal with fopen not being allowed for remote access |
|
// in some OSs |
|
$temp_content = self::try_http_get_content($filename_or_content); |
|
if ($temp_content !== FALSE) { |
|
$filename_or_content = $temp_content; |
|
} |
|
|
|
// Push contents to a web-accessible file. |
|
$file = file_save_data($filename_or_content, file_create_filename($label, file_directory_path())); |
|
$created_temp = TRUE; |
|
} |
|
|
|
$parts = explode(DIRECTORY_SEPARATOR, $file); |
|
$parts = array_map('rawurlencode', $parts); |
|
$file_url = file_create_url(implode(DIRECTORY_SEPARATOR, $parts)); |
|
|
|
$toReturn = $this->modify_datastream_by_reference($file_url, $dsid, $label, $mime_type, $force, $logMessage); |
|
|
|
if ($created_temp && is_file($file) && is_writable($file)) { |
|
file_delete($file); |
|
} |
|
} |
|
|
|
return $toReturn; |
|
} |
|
|
|
/** |
|
* Modify datastream by reference |
|
* |
|
* @param type $external_url |
|
* @param type $dsid |
|
* @param type $label |
|
* @param type $mime_type |
|
* @param type $force |
|
* @param type $logMessage |
|
* @param type $quiet |
|
* |
|
* @return type |
|
*/ |
|
function modify_datastream_by_reference($external_url, $dsid, $label, $mime_type, $force = FALSE, $logMessage = 'Modified by Islandora API', $quiet=FALSE) { |
|
global $base_url; |
|
|
|
// Fedora has some problems getting files from HTTPS connections sometimes, so if we are getting a file |
|
// from the local drupal, we try to pass a HTTP url instead of a HTTPS one. |
|
if (stripos($external_url, 'https://') !== FALSE && stripos($external_url, $base_url) !== FALSE) { |
|
$external_url = str_ireplace('https://', 'http://', $external_url); |
|
} |
|
|
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
'altIDs' => NULL, |
|
'dsLabel' => $label, |
|
'MIMEType' => $mime_type, |
|
'formatURI' => NULL, |
|
'dsLocation' => $external_url, |
|
'checksumType' => 'DISABLED', |
|
'checksum' => 'none', |
|
'logMessage' => $logMessage, |
|
'force' => $force, |
|
); |
|
return self::soap_call('modifyDatastreamByReference', $params, $quiet); |
|
} |
|
|
|
/** |
|
* Modify datastream by value |
|
* |
|
* @param type $content |
|
* @param type $dsid |
|
* @param type $label |
|
* @param type $mime_type |
|
* @param type $force |
|
* @param type $logMessage |
|
* @param type $quiet |
|
* |
|
* @return type |
|
*/ |
|
function modify_datastream_by_value($content, $dsid, $label, $mime_type, $force = FALSE, $logMessage = 'Modified by Islandora API', $quiet=FALSE) { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
'altIDs' => NULL, |
|
'dsLabel' => $label, |
|
'MIMEType' => $mime_type, |
|
'formatURI' => NULL, |
|
'dsContent' => $content, |
|
'checksumType' => 'DISABLED', |
|
'checksum' => 'none', |
|
'logMessage' => $logMessage, |
|
'force' => $force, |
|
); |
|
return self::soap_call('modifyDatastreamByValue', $params, $quiet); |
|
} |
|
|
|
/** |
|
* |
|
* @param unknown_type $dsid |
|
* @param unknown_type $state |
|
* @param unknown_type $log_message |
|
* @param unknown_type $quiet |
|
*/ |
|
function set_datastream_state($dsid, $state, $log_message = 'Modified by Islandora API', $quiet = FALSE) { |
|
$valid_states = array('A', 'D', 'I'); |
|
if (array_search($state, $valid_states) !== FALSE) { |
|
$params = array( |
|
'pid' => $this->pid, |
|
'dsID' => $dsid, |
|
'dsState' => $state, |
|
'logMessage' => $log_message, |
|
); |
|
return self::soap_call('setDatastreamState', $params, $quiet); |
|
} |
|
} |
|
|
|
/** |
|
* Make a soap call to the fedora API. |
|
* |
|
* @param string $function |
|
* The name of the soap function to call. |
|
* @param array $parameters |
|
* Paramters to pass onto the soap call |
|
* @param boolean $quiet |
|
* If TRUE suppress drupal messages. |
|
* |
|
* @return mixed |
|
* The return value from the soap function if successful, NULL otherwise. |
|
*/ |
|
static function soap_call($function, $parameters, $quiet = FALSE) { |
|
if (!self::$connection_helper) { |
|
module_load_include('inc', 'fedora_repository', 'ConnectionHelper'); |
|
self::$connection_helper = new ConnectionHelper(); |
|
} |
|
$url = ( |
|
in_array($function, self::$SoapManagedFunctions) ? |
|
variable_get('fedora_soap_manage_url', 'http://localhost:8080/fedora/wsdl?api=API-M') : |
|
variable_get('fedora_soap_url', 'http://localhost:8080/fedora/services/access?wsdl') |
|
); |
|
try { |
|
$soap_client = self::$connection_helper->getSoapClient($url); |
|
if (isset($soap_client)) { |
|
$result = $soap_client->__soapCall($function, array('parameters' => $parameters)); |
|
} |
|
else { |
|
if (!$quiet) { |
|
drupal_set_message(t('Error trying to get SOAP client connection')); |
|
} |
|
watchdog('fedora_repository', 'Error trying to get SOAP client connection.'); |
|
return NULL; |
|
} |
|
} catch (Exception $e) { |
|
if (!$quiet) { |
|
preg_match('/org\.fcrepo\.server\.security\.xacml\.pep\.AuthzDeniedException/', $e->getMessage()) ? |
|
drupal_set_message(t('Insufficient permissions to call SOAP function "%func".', array('%func' => $function)), 'error') : |
|
drupal_set_message(t('Error trying to call SOAP function "%func". Check watchdog logs for more information.', array('%func' => $function)), 'error'); |
|
} |
|
watchdog('fedora_repository', 'Error Trying to call SOAP function "%func". Exception: @e in @f(@l)\n@t', array('%func' => $function, '@e' => $e->getMessage(), '@f' => $e->getFile(), '@l' => $e->getLine(), '@t' => $e->getTraceAsString()), NULL, WATCHDOG_ERROR); |
|
return NULL; |
|
} |
|
return $result; |
|
} |
|
|
|
/** |
|
* Creates the minimal FOXML for a new Fedora object, which is then passed to |
|
* ingest_from_FOXML to be added to the repository. |
|
* |
|
* @param string $pid if none given, getnextpid will be called. |
|
* @param string $state The initial state, A - Active, I - Inactive, D - Deleted |
|
* @param type $label |
|
* @param type $owner |
|
* |
|
* @return DOMDocument |
|
*/ |
|
static function create_object_FOXML($pid = '', $state = 'A', $label = 'Untitled', $owner = '') { |
|
$foxml = new DOMDocument("1.0", "UTF-8"); |
|
$foxml->formatOutput = TRUE; |
|
if (empty($pid)) { |
|
// Call getNextPid. |
|
$pid = self::get_next_PID_in_namespace(); |
|
} |
|
if (empty($owner)) { |
|
global $user; |
|
// Default to current Drupal user. |
|
if (!empty($user->uid)) { |
|
$owner = $user->uid; |
|
} |
|
// We are not inside Drupal. |
|
else { |
|
$owner = 'fedoraAdmin'; |
|
} |
|
} |
|
|
|
$root_element = $foxml->createElementNS("info:fedora/fedora-system:def/foxml#", "foxml:digitalObject"); |
|
$root_element->setAttribute("VERSION", "1.1"); |
|
$root_element->setAttribute("PID", $pid); |
|
$root_element->setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi:schemaLocation", "info:fedora/fedora-system:def/foxml# http://www.fedora.info/definitions/1/0/foxml1-1.xsd"); |
|
$foxml->appendChild($root_element); |
|
|
|
// FOXML object properties section. |
|
$object_properties = $foxml->createElementNS("info:fedora/fedora-system:def/foxml#", "foxml:objectProperties"); |
|
$state_property = $foxml->createElementNS("info:fedora/fedora-system:def/foxml#", "foxml:property"); |
|
$state_property->setAttribute("NAME", "info:fedora/fedora-system:def/model#state"); |
|
$state_property->setAttribute("VALUE", $state); |
|
|
|
$label_property = $foxml->createElementNS("info:fedora/fedora-system:def/foxml#", "foxml:property"); |
|
$label_property->setAttribute("NAME", "info:fedora/fedora-system:def/model#label"); |
|
$label_property->setAttribute("VALUE", truncate_utf8($label, 255, TRUE, TRUE)); |
|
|
|
$owner_property = $foxml->createElementNS("info:fedora/fedora-system:def/foxml#", "foxml:property"); |
|
$owner_property->setAttribute("NAME", "info:fedora/fedora-system:def/model#ownerId"); |
|
$owner_property->setAttribute("VALUE", $owner); |
|
|
|
$object_properties->appendChild($state_property); |
|
$object_properties->appendChild($label_property); |
|
$object_properties->appendChild($owner_property); |
|
$root_element->appendChild($object_properties); |
|
$foxml->appendChild($root_element); |
|
return $foxml; |
|
} |
|
|
|
/** |
|
* ingest new item |
|
* |
|
* @param type $pid |
|
* @param type $state |
|
* @param type $label |
|
* @param type $owner |
|
* |
|
* @return type |
|
*/ |
|
static function ingest_new_item($pid = '', $state = 'A', $label = '', $owner = '') { |
|
return self::ingest_from_FOXML(self::create_object_FOXML($pid, $state, $label, $owner)); |
|
} |
|
|
|
/** |
|
* fedora item exists |
|
* |
|
* @param type $pid |
|
* |
|
* @return type |
|
*/ |
|
static function fedora_item_exists($pid) { |
|
$item = new Fedora_Item($pid); |
|
return $item->exists(); |
|
} |
|
|
|
/** |
|
* This function will retrieve the ownerId |
|
* object property from Fedora using the SOAP API. |
|
* |
|
* @param string $PID |
|
* The Fedora PID to retrieve the |
|
*/ |
|
static function getOwnerId($PID) { |
|
|
|
$params = array( |
|
'query' => array(array('property' => 'pid', 'operator' => 'eq', 'value' => $PID)), |
|
'resultFields' => array('pid', 'ownerId'), |
|
'maxResults' => 1, |
|
); |
|
$response = Fedora_Item::soap_call('findObjects', $params); |
|
|
|
if (!$response) { |
|
return FALSE; |
|
} |
|
return $response->result->resultList->objectFields->ownerId; |
|
|
|
} |
|
}
|
|
|