Browse Source

Merge pull request #3 from jonathangreen/7.x-ingest

7.x ingest
pull/203/head
Nigel Banks 12 years ago
parent
commit
0274fc6512
  1. 5
      admin/islandora.admin.inc
  2. 100
      includes/IslandoraTuque.inc
  3. 2
      includes/add_datastream.form.inc
  4. 1
      includes/delete_object.form.inc
  5. 456
      includes/globals.inc
  6. 1
      includes/ingest.form.inc
  7. 3
      includes/solution_packs.inc
  8. 209
      includes/utilities.inc
  9. 1
      islandora.info
  10. 279
      islandora.module

5
admin/islandora.admin.inc

@ -16,6 +16,11 @@ function islandora_repository_admin($form, &$form_state) {
module_load_include('inc', 'islandora', 'includes/utilities');
drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css');
if (!IslandoraTuque::exists()) {
IslandoraTuque::getError();
return;
}
$form = array();
if (isset($form_state['values']['islandora_base_url'])) {
$url = $form_state['values']['islandora_base_url'];

100
includes/IslandoraTuque.inc

@ -6,6 +6,29 @@
* This file contains a class to include the Tuque php library.
*/
$islandora_module_path = drupal_get_path('module', 'islandora');
//do this until we expost these in a module or library
@include_once 'sites/all/libraries/tuque/Datastream.php';
@include_once 'sites/all/libraries/tuque/FedoraApi.php';
@include_once 'sites/all/libraries/tuque/FedoraApiSerializer.php';
@include_once 'sites/all/libraries/tuque/Object.php';
@include_once 'sites/all/libraries/tuque/RepositoryConnection.php';
@include_once 'sites/all/libraries/tuque/Cache.php';
@include_once 'sites/all/libraries/tuque/RepositoryException.php';
@include_once 'sites/all/libraries/tuque/Repository.php';
@include_once 'sites/all/libraries/tuque/FedoraRelationships.php';
@include_once "$islandora_module_path/libraries/tuque/Datastream.php";
@include_once "$islandora_module_path/libraries/tuque/FedoraApi.php";
@include_once "$islandora_module_path/libraries/tuque/FedoraApiSerializer.php";
@include_once "$islandora_module_path/libraries/tuque/Object.php";
@include_once "$islandora_module_path/libraries/tuque/RepositoryConnection.php";
@include_once "$islandora_module_path/libraries/tuque/Cache.php";
@include_once "$islandora_module_path/libraries/tuque/RepositoryException.php";
@include_once "$islandora_module_path/libraries/tuque/Repository.php";
@include_once "$islandora_module_path/libraries/tuque/FedoraRelationships.php";
class IslandoraTuque {
/**
@ -55,11 +78,11 @@ class IslandoraTuque {
}
if (self::exists()) {
$this->connection = new RepositoryConnection($url, $user_string, $pass_string);
$this->connection = new IslandoraRepositoryConnection($url, $user_string, $pass_string);
$this->connection->reuseConnection = TRUE;
$this->api = new FedoraApi($this->connection);
$this->cache = new SimpleCache();
$this->repository = new FedoraRepository($this->api, $this->cache);
$this->api = new IslandoraFedoraApi($this->connection);
$this->cache = new IslandoraSimpleCache();
$this->repository = new IslandoraFedoraRepository($this->api, $this->cache);
}
}
@ -74,3 +97,72 @@ class IslandoraTuque {
drupal_set_message(filter_xss($message), 'error', FALSE);
}
}
/**
* Just a wrapper around fetchings the IslandoraTuque object, with some very
* basic error logging.
*
* @return IslandoraTuque
* A IslandoraTuque instance
*/
function islandora_get_tuque_connection() {
$tuque = &drupal_static(__FUNCTION__);
if (!$tuque) {
if(IslandoraTuque::exists()) {
try {
$tuque = new IslandoraTuque();
} catch (Exception $e) {
drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error');
}
}
else {
return NULL;
}
}
return $tuque;
}
class IslandoraFedoraRepository extends FedoraRepository {
protected $queryClass = 'IslandoraRepositoryQuery';
protected $newObjectClass = 'IslandoraNewFedoraObject';
protected $objectClass = 'IslandoraFedoraObject';
}
class IslandoraRepositoryQuery extends RepositoryQuery {}
class IslandoraNewFedoraObject extends NewFedoraObject {
protected $newFedoraDatastreamClass = 'IslandoraNewFedoraDatastream';
protected $fedoraDatastreamClass = 'IslandoraFedoraDatastream';
protected $fedoraRelsExtClass = 'IslandoraFedoraRelsExt';
}
class IslandoraFedoraObject extends FedoraObject {
protected $newFedoraDatastreamClass = 'IslandoraNewFedoraDatastream';
protected $fedoraDatastreamClass = 'IslandoraFedoraDatastream';
protected $fedoraRelsExtClass = 'IslandoraFedoraRelsExt';
}
class IslandoraRepositoryConnection extends RepositoryConnection {}
class IslandoraFedoraApi extends FedoraApi {}
class IslandoraSimpleCache extends SimpleCache {}
class IslandoraNewFedoraDatastream extends NewFedoraDatastream {
protected $fedoraRelsIntClass = 'IslandoraFedoraRelsInt';
protected $fedoraDatastreamVersionClass = 'IslandoraFedoraDatastreamVersion';
}
class IslandoraFedoraDatastream extends FedoraDatastream {
protected $fedoraRelsIntClass = 'IslandoraFedoraRelsInt';
protected $fedoraDatastreamVersionClass = 'IslandoraFedoraDatastreamVersion';
}
class IslandoraFedoraDatastreamVersion extends FedoraDatastreamVersion {
protected $fedoraRelsIntClass = 'IslandoraFedoraRelsInt';
protected $fedoraDatastreamVersionClass = 'IslandoraFedoraDatastreamVersion';
}
class IslandoraFedoraRelsExt extends FedoraRelsExt {}
class IslandoraFedoraRelsInt extends FedoraRelsInt {}

2
includes/add_datastream.form.inc

@ -21,6 +21,7 @@
*/
function islandora_add_datastream_form(array $form, array &$form_state, FedoraObject $object) {
module_load_include('inc', 'islandora', 'includes/content_model');
module_load_include('inc', 'islandora', 'includes/utilities');
form_load_include($form_state, 'inc', 'islandora', 'includes/add_datastream.form');
$form_state['object'] = $object;
$form_state['datastream_requirements'] = islandora_get_missing_datastreams_requirements($object);
@ -219,6 +220,7 @@ function islandora_add_datastream_form_submit(array $form, array &$form_state) {
*/
function islandora_add_datastream_form_autocomplete_callback(FedoraObject $object, $query = '') {
module_load_include('inc', 'islandora', 'includes/content_model');
module_load_include('inc', 'islandora', 'includes/utilities');
$dsids = array_keys(islandora_get_missing_datastreams_requirements($object));
$dsids = array_combine($dsids, $dsids);
$query = trim($query);

1
includes/delete_object.form.inc

@ -41,6 +41,7 @@ function islandora_delete_object_form(array $form, array &$form_state, FedoraObj
*/
function islandora_delete_object_form_submit(array $form, array &$form_state) {
module_load_include('inc', 'islandora', 'includes/datastream');
module_load_include('inc', 'islandora', 'includes/utilities');
$object = $form_state['object'];
$parents = islandora_get_parents_from_rels_ext($object);
$parent = array_pop($parents);

456
includes/globals.inc

@ -1,456 +0,0 @@
<?php
/**
* @file
*
* This file contains any functions meant to be part of the global space, ie.
* functions that and other modules will use without including a module file.
*/
/**
* Just a wrapper around fetchings the IslandoraTuque object, with some very
* basic error logging.
*
* @return IslandoraTuque
* A IslandoraTuque instance
*/
function islandora_get_tuque_connection() {
$tuque = &drupal_static(__FUNCTION__);
if (!$tuque) {
try {
$tuque = new IslandoraTuque();
} catch (Exception $e) {
drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error');
}
}
return $tuque;
}
/**
* Gets the given object if found, NULL if it is inaccessible and FALSE if it
* was not found.
*
* @param string $object_id
* The identifier of the object to get.
*
* @return FedoraObject
* The object if found, NULL if it is inaccessible and FALSE if it was not
* found.
*/
function islandora_get_object_by_id($object_id) {
$tuque = islandora_get_tuque_connection();
if ($tuque) {
try {
$object = $tuque->repository->getObject($object_id);
drupal_alter('islandora_object', $object);
return $object;
} catch (Exception $e) {
if ($e->getCode() == '404') {
return FALSE;
}
else {
return NULL;
}
}
}
else {
IslandoraTuque::getError();
}
// Assuming access denied in all other cases for now.
return NULL;
}
/**
* Ingest the given object into Fedora calling its pre/post hooks as well.
*
* @param NewFedoraObject $object
* An ingestable FedoraObject.
*
* @return FedoraObject
* The ingested FedoraObject, after running the pre/post ingest hooks.
*/
function islandora_add_object(NewFedoraObject &$object) {
islandora_pre_add_object($object);
$object->repository->ingestObject($object);
islandora_post_add_object($object);
return $object;
}
/**
* Calls the ISLANDORA_PRE_INGEST_HOOK hooks.
*
* @param NewFedoraObject $object
* An ingestable FedoraObject.
*/
function islandora_pre_add_object(NewFedoraObject $object) {
module_load_include('inc', 'islandora', 'includes/utilities');
foreach (islandora_build_hook_list(ISLANDORA_PRE_INGEST_HOOK, $object->models) as $hook) {
module_invoke_all($hook, $object);
}
}
/**
* Calls the ISLANDORA_POST_INGEST_HOOK hooks.
*
* @param FedoraObject $object
* A recently ingestable FedoraObject.
*/
function islandora_post_add_object(FedoraObject $object) {
foreach (islandora_build_hook_list(ISLANDORA_POST_INGEST_HOOK, $object->models) as $hook) {
module_invoke_all($hook, $object);
}
}
/**
* Deletes the given object into Fedora calling its pre/post hooks as well.
*
* @param FedoraObject $object
* An object to delete.
*
* @return FedoraObject
* The ingested FedoraObject, after running the pre/post ingest hooks.
*/
function islandora_delete_object(FedoraObject &$object) {
$object_id = $object->id;
$models = $object->models;
$action = islandora_pre_delete_object($object);
switch ($action) {
case 'blocked':
// Do nothing.
return FALSE;
case 'delete':
// Change the state to deleted.
$object->delete();
islandora_post_delete_object($object_id, $models);
return TRUE;
default:
// Purge
$object->repository->purgeObject($object_id);
islandora_post_delete_object($object_id, $models);
$object = NULL;
return TRUE;
}
}
/**
* Calls the ISLANDORA_PRE_PURGE_OBJECT_HOOK hooks.
*
* @param FedoraObject $object
* The object that is about to be deleted.
*/
function islandora_pre_delete_object(FedoraObject $object) {
module_load_include('inc', 'islandora', 'includes/utilities');
$results = array();
foreach (islandora_build_hook_list(ISLANDORA_PRE_PURGE_OBJECT_HOOK, $object->models) as $hook) {
$results = array_merge_recursive($results, module_invoke_all($hook, $object));
}
$action = (isset($results['block']) && $results['block']) ? 'block' : FALSE;
$action = (!$action && isset($results['delete']) && $results['delete']) ? 'delete' : $action;
$action = !$action ? 'purge' : $action;
return $action;
}
/**
* Calls the ISLANDORA_POST_PURGE_OBJECT_HOOK hooks.
*
* @param string $object_id
* The object id of an the recently deleted object.
* @param array $models
* The list of content models the delete object subsribed to.
*/
function islandora_post_delete_object($object_id, array $models) {
module_load_include('inc', 'islandora', 'includes/utilities');
foreach (islandora_build_hook_list(ISLANDORA_POST_PURGE_OBJECT_HOOK, $models) as $hook) {
module_invoke_all($hook, $object_id, $models);
}
}
/**
* Delete's/Purges the given datastream.
*
* @throws Exception
* Which types are undefined, but more than likely because of the hooks
* there will be several kinds.
*
* @param FedoraDatastream $datastream
* The datastream to delete.
*
* @return boolean
* TRUE is returned if the datastream was Deleted/Purged, FALSE if it was
* blocked.
*/
function islandora_delete_datastream(FedoraDatastream &$datastream) {
$datastream_id = $datastream->id;
$object = $datastream->parent;
$action = islandora_pre_delete_datastream($datastream);
switch ($action) {
case 'blocked':
// Do nothing.
return FALSE;
case 'delete':
// Change the state to deleted.
$object[$datastream_id]->state = 'D';
// @todo Differentiate between delete/purge in the hooks.
islandora_post_delete_datastream($object, $datastream_id);
return TRUE;
default:
// Purge
$object->purgeDatastream($datastream_id);
islandora_post_delete_datastream($object, $datastream_id);
$datastream = NULL;
return TRUE;
}
}
/**
* The default behaviour is to 'purge' the datastream but this can be overridden
* by modules that implement the 'islandora_pre_purge_datastream' hook.
*
* @todo make this an alter.
*
* The returned array can include a 'block' => TRUE
* pair which will prevent the datastream from being deleted if it particularly
* needed for a certain function. Returning 'delete' => TRUE will cause the
* datastream to be put into a deleted state.
*
* @param FedoraDatastream $datastream
* The datastream to delete.
*
* @return string
* The action to take when deleting the given datastream, either 'purge',
* 'delete', or 'block'.
*/
function islandora_pre_delete_datastream(FedoraDatastream $datastream) {
module_load_include('inc', 'islandora', 'includes/utilities');
$results = array();
foreach (islandora_build_hook_list(ISLANDORA_PRE_PURGE_DATASTREAM_HOOK, $datastream->parent->models) as $hook) {
// Not sure this will work the greatest, probably an alter would be better..
$results = array_merge_recursive($results, module_invoke_all($hook, $datastream));
}
$action = (isset($results['block']) && $results['block']) ? 'block' : FALSE;
$action = (!$action && isset($results['delete']) && $results['delete']) ? 'delete' : $action;
$action = !$action ? 'purge' : $action;
return $action;
}
/**
* Calls the post purge datastream hooks.
*
* @todo Should differentiate between purging/deleting.
*
* @param FedoraObject $object
* The parent object of the deleted datastream.
* @param string $datastream_id
* The datastream id of the deleted datastream.
*/
function islandora_post_delete_datastream(FedoraObject $object, $datastream_id) {
module_load_include('inc', 'islandora', 'includes/utilities');
foreach (islandora_build_hook_list(ISLANDORA_POST_PURGE_DATASTREAM_HOOK, $object->models) as $hook) {
module_invoke_all($hook, $object, $datastream_id);
}
}
/**
* Gets any objects that the given object has a
* (isMemberOf, isMemberOfCollection) relationship with.
*
* This function gets its info from the RELS-EXT directly rather than through an
* risearch.
*
* @param FedoraObject $object
* The object whose parents will be returned.
*
* @return array
* An array of FedoraObject's that the given object has a
* (isMemberOf, isMemberOfCollection) relationship with.
*/
function islandora_get_parents_from_rels_ext(FedoraObject $object) {
try {
$collections = array_merge(
$object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOfCollection'),
$object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOf'));
}
catch (RepositoryException $e) {
// @todo some logging would be nice, not sure what this throws.
return array();
}
$collections = array_map(function($o) { return islandora_get_object_by_id($o['object']['value']); }, $collections);
return array_filter($collections);
}
/**
* Checks what datastreams the object already has against its required
* datastreams as defined by its content models, and returns their intersection.
*
* @param FedoraObject $object
* The object which models will be used to determine what datastreams it
* should have.
*
* @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object, but not already present.
*/
function islandora_get_missing_datastreams_requirements(FedoraObject $object) {
$datastreams = islandora_get_datastreams_requirements($object);
foreach ($datastreams as $dsid => $requirements) {
if (isset($object[$dsid])) {
unset($datastreams[$dsid]);
}
}
return $datastreams;
}
/**
* Checks the object's content model's for which datastream are expected to be
* used with this object, as defined by the DS-COMPOSITE-MODEL datastreams.
*
* For duplicate datastreams in the models, the first model defines the
* datastreams attributes regardless of what other models define.
* This should be undefined behavior according to the documentation.
* @see https://wiki.duraspace.org/display/FEDORA34/Fedora+Digital+Object+Model#FedoraDigitalObjectModel-ContentModelObjectCMODEL
*
* @param FedoraObject $object
* The object which models will be used to determine what datastreams it
* should have.
*
* @see islandora_get_required_datastreams_from_content_model() from more
* details on the return value.
*
* @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object.
*/
function islandora_get_datastreams_requirements(FedoraObject $object) {
return islandora_get_datastreams_requirements_from_models($object->models);
}
/**
* Get the list of which datastreams are valid in the given set of models.
*
* @param array $models
* An array of content models PIDs from which to parse the DS-COMPOSITE-MODEL
* stream.
*
* @return array
* An associative array of associative arrays, merged from calls to
* islandora_get_datastreams_requirements_from_content_model().
*/
function islandora_get_datastreams_requirements_from_models(array $models) {
$dsids = array();
foreach ($models as $model) {
$model = islandora_get_object_by_id($model);
$dsids += islandora_get_datastreams_requirements_from_content_model($model);
}
// The AUDIT Datastream can not really be added, so it can't really be missing.
unset($dsids['AUDIT']);
return $dsids;
}
/**
* Checks the given content model for which datastreams are required for
* subscribing objects, as defined by it's DS-COMPOSITE-MODEL datastream.
*
* @todo Add support for fetching the schema information.
*
* @param FedoraObject $object
* The content model whose DS-COMPOSITE-MODEL datastream will be used to
* determine what datastreams are required.
*
* @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object.
*
* @code
* array(
* 'DC' => array(
* 'id' => 'DC',
* 'mime' => 'text/xml',
* 'optional' => FALSE,
* )
* )
* @endcode
*/
function islandora_get_datastreams_requirements_from_content_model(FedoraObject $object) {
if (empty($object[DS_COMP_STREAM])) {
return array();
}
$xml = new SimpleXMLElement($object[DS_COMP_STREAM]->content);
foreach ($xml->dsTypeModel as $ds) {
$dsid = (string) $ds['ID'];
$optional = strtolower((string) $ds['optional']);
$mime = array();
foreach ($ds->form as $form) {
$mime[] = (string) $form['MIME'];
}
$dsids[$dsid] = array(
'id' => $dsid,
'mime' => $mime,
'optional' => ($optional == 'true') ? TRUE : FALSE
);
}
return $dsids;
}
/**
* Prepare an ingestable object.
*
* @param string $namespace
* The namespace in which the PID for the new object will be created.
* @param string $label
* An optional label to apply to the object.
* @param array $datastreams
* A array of datastreams to add, where each datastream definition is an
* associative array containing:
* - dsid: The datastream ID.
* - label: An optional label for the datastream.
* - mimetype: A MIMEtype for the datastream; defaults to text/xml.
* - control_group: One of X, M, R and E; defaults to M.
* - datastream_file: A web-accessible path, for which we try to get an
* absolute path using url().
* @param array $content_models
* An array of content model PIDs to which the new object should subscribe.
* @param array $relationships
* An array of relationships, where each relationship is an associative array
* containing:
* - relationship: The predicate for the relationship, from the Fedora
* RELS-EXT namespace.
* - pid: The object for the relationship, to which we are creating the
* relationhsip.
*
* @return NewFedoraObject
* An ingestable NewFedoraObject.
*/
function islandora_prepare_new_object($namespace = NULL, $label = NULL, $datastreams = array(), $content_models = array(), $relationships = array()) {
$tuque = islandora_get_tuque_connection();
$object = isset($namespace) ? $tuque->repository->constructObject($namespace) : new NewFedoraObject(NULL, $tuque->repository);
$object->owner = isset($user->name) ? $user->name : $object->owner;
$object->label = isset($label) ? $label : $object->label;
foreach ($content_models as $content_model) {
$object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $content_model);
}
foreach ($relationships as $relationship) {
$object->relationships->add(FEDORA_RELS_EXT_URI, $relationship['relationship'], $relationship['pid']);
}
foreach ($datastreams as $ds) {
$dsid = $ds['dsid'];
$label = isset($ds['label']) ? $ds['label'] : '';
$mimetype = isset($ds['mimetype']) ? $ds['mimetype'] : 'text/xml';
// Default 'Managed'
$control_group = (isset($ds['control_group']) && in_array($ds['control_group'], array('X', 'M', 'R', 'E'))) ? $ds['control_group'] : 'M';
$datastream_file = url($ds['datastream_file'], array('absolute' => TRUE));
$datastream = $object->constructDatastream($dsid, $control_group);
$datastream->label = $label;
$datastream->mimetype = $mimetype;
switch ($control_group) {
case 'M':
$datastream->setContentFromUrl($datastream_file);
break;
case 'X':
$datastream->setContentFromString(file_get_contents($datastream_file));
break;
}
$object->ingestDatastream($datastream);
}
return $object;
}

1
includes/ingest.form.inc

@ -67,6 +67,7 @@ function islandora_ingest_form_init_form_state(array &$form_state, array $config
* executed.
*/
function islandora_ingest_form_init_form_state_storage(array &$form_state, array $configuration) {
module_load_include('inc', 'islandora', 'includes/utilities');
if (empty($form_state['islandora'])) {
// Use ID if given.
$id = isset($configuration['id']) ? $configuration['id'] : NULL;

3
includes/solution_packs.inc

@ -226,7 +226,7 @@ function islandora_batch_reingest_object($object_model, &$context) {
$object_query = $connection->api->a->findObjects('query', 'pid=' . $pid);
$reinstall = FALSE;
if (!empty($object_query['results'])) {
$object = islandora_get_object_by_id($pid);
$object = islandora_object_load($pid);
if (isset($object)) {
islandora_delete_object($object);
}
@ -491,6 +491,7 @@ function islandora_solution_pack_add_object(array $object_definition) {
* An NewFedoraObject which has been initalized with the given properties.
*/
function islandora_solution_pack_prepare_new_object(array $object_definition) {
module_load_include('inc', 'islandora', 'includes/utilities');
$namespace = $object_definition['pid'];
$label = !empty($object_definition['label']) ? $object_definition['label'] : NULL;
$datastreams = array();

209
includes/utilities.inc

@ -3,6 +3,8 @@
/**
* @file
* Contains islandora utility functions
*
* @todo this file should be broken out into other files.
*/
/**
@ -199,3 +201,210 @@ function islandora_namespace_accessible($id) {
}
return TRUE;
}
/**
* Gets any objects that the given object has a
* (isMemberOf, isMemberOfCollection) relationship with.
*
* This function gets its info from the RELS-EXT directly rather than through an
* risearch.
*
* @param FedoraObject $object
* The object whose parents will be returned.
*
* @return array
* An array of FedoraObject's that the given object has a
* (isMemberOf, isMemberOfCollection) relationship with.
*/
function islandora_get_parents_from_rels_ext(FedoraObject $object) {
try {
$collections = array_merge(
$object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOfCollection'),
$object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOf'));
}
catch (RepositoryException $e) {
// @todo some logging would be nice, not sure what this throws.
return array();
}
$collections = array_map(function($o) { return islandora_object_load($o['object']['value']); }, $collections);
return array_filter($collections);
}
/**
* Checks what datastreams the object already has against its required
* datastreams as defined by its content models, and returns their intersection.
*
* @param FedoraObject $object
* The object which models will be used to determine what datastreams it
* should have.
*
* @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object, but not already present.
*/
function islandora_get_missing_datastreams_requirements(FedoraObject $object) {
module_load_include('inc', 'islandora', 'includes/utilities');
$datastreams = islandora_get_datastreams_requirements($object);
foreach ($datastreams as $dsid => $requirements) {
if (isset($object[$dsid])) {
unset($datastreams[$dsid]);
}
}
return $datastreams;
}
/**
* Checks the object's content model's for which datastream are expected to be
* used with this object, as defined by the DS-COMPOSITE-MODEL datastreams.
*
* For duplicate datastreams in the models, the first model defines the
* datastreams attributes regardless of what other models define.
* This should be undefined behavior according to the documentation.
* @see https://wiki.duraspace.org/display/FEDORA34/Fedora+Digital+Object+Model#FedoraDigitalObjectModel-ContentModelObjectCMODEL
*
* @param FedoraObject $object
* The object which models will be used to determine what datastreams it
* should have.
*
* @see islandora_get_required_datastreams_from_content_model() from more
* details on the return value.
*
* @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object.
*/
function islandora_get_datastreams_requirements(FedoraObject $object) {
return islandora_get_datastreams_requirements_from_models($object->models);
}
/**
* Get the list of which datastreams are valid in the given set of models.
*
* @param array $models
* An array of content models PIDs from which to parse the DS-COMPOSITE-MODEL
* stream.
*
* @return array
* An associative array of associative arrays, merged from calls to
* islandora_get_datastreams_requirements_from_content_model().
*/
function islandora_get_datastreams_requirements_from_models(array $models) {
$dsids = array();
foreach ($models as $model) {
$model = islandora_object_load($model);
$dsids += islandora_get_datastreams_requirements_from_content_model($model);
}
// The AUDIT Datastream can not really be added, so it can't really be missing.
unset($dsids['AUDIT']);
return $dsids;
}
/**
* Checks the given content model for which datastreams are required for
* subscribing objects, as defined by it's DS-COMPOSITE-MODEL datastream.
*
* @todo Add support for fetching the schema information.
*
* @param FedoraObject $object
* The content model whose DS-COMPOSITE-MODEL datastream will be used to
* determine what datastreams are required.
*
* @return array
* The DS-COMPOSITE-MODEL defined datastreams that are required for the given
* object.
*
* @code
* array(
* 'DC' => array(
* 'id' => 'DC',
* 'mime' => 'text/xml',
* 'optional' => FALSE,
* )
* )
* @endcode
*/
function islandora_get_datastreams_requirements_from_content_model(FedoraObject $object) {
if (empty($object[DS_COMP_STREAM])) {
return array();
}
$xml = new SimpleXMLElement($object[DS_COMP_STREAM]->content);
foreach ($xml->dsTypeModel as $ds) {
$dsid = (string) $ds['ID'];
$optional = strtolower((string) $ds['optional']);
$mime = array();
foreach ($ds->form as $form) {
$mime[] = (string) $form['MIME'];
}
$dsids[$dsid] = array(
'id' => $dsid,
'mime' => $mime,
'optional' => ($optional == 'true') ? TRUE : FALSE
);
}
return $dsids;
}
/**
* Prepare an ingestable object.
*
* @param string $namespace
* The namespace in which the PID for the new object will be created.
* @param string $label
* An optional label to apply to the object.
* @param array $datastreams
* A array of datastreams to add, where each datastream definition is an
* associative array containing:
* - dsid: The datastream ID.
* - label: An optional label for the datastream.
* - mimetype: A MIMEtype for the datastream; defaults to text/xml.
* - control_group: One of X, M, R and E; defaults to M.
* - datastream_file: A web-accessible path, for which we try to get an
* absolute path using url().
* @param array $content_models
* An array of content model PIDs to which the new object should subscribe.
* @param array $relationships
* An array of relationships, where each relationship is an associative array
* containing:
* - relationship: The predicate for the relationship, from the Fedora
* RELS-EXT namespace.
* - pid: The object for the relationship, to which we are creating the
* relationhsip.
*
* @return NewFedoraObject
* An ingestable NewFedoraObject.
*/
function islandora_prepare_new_object($namespace = NULL, $label = NULL, $datastreams = array(), $content_models = array(), $relationships = array()) {
module_load_include('inc', 'islandora', 'includes/IslandoraTuque');
global $user;
$tuque = islandora_get_tuque_connection();
$object = isset($namespace) ? $tuque->repository->constructObject($namespace) : new NewFedoraObject(NULL, $tuque->repository);
$object->owner = isset($user->name) ? $user->name : $object->owner;
$object->label = isset($label) ? $label : $object->label;
foreach ($content_models as $content_model) {
$object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $content_model);
}
foreach ($relationships as $relationship) {
$object->relationships->add(FEDORA_RELS_EXT_URI, $relationship['relationship'], $relationship['pid']);
}
foreach ($datastreams as $ds) {
$dsid = $ds['dsid'];
$label = isset($ds['label']) ? $ds['label'] : '';
$mimetype = isset($ds['mimetype']) ? $ds['mimetype'] : 'text/xml';
// Default 'Managed'
$control_group = (isset($ds['control_group']) && in_array($ds['control_group'], array('X', 'M', 'R', 'E'))) ? $ds['control_group'] : 'M';
$datastream_file = url($ds['datastream_file'], array('absolute' => TRUE));
$datastream = $object->constructDatastream($dsid, $control_group);
$datastream->label = $label;
$datastream->mimetype = $mimetype;
switch ($control_group) {
case 'M':
$datastream->setContentFromUrl($datastream_file);
break;
case 'X':
$datastream->setContentFromString(file_get_contents($datastream_file));
break;
}
$object->ingestDatastream($datastream);
}
return $object;
}

1
islandora.info

@ -1,7 +1,6 @@
name = Islandora
description = "View and manage Fedora objects"
package = Islandora
dependencies[] = tuque
version = 7.x-dev
core = 7.x
configure = admin/islandora/configure

279
islandora.module

@ -21,7 +21,6 @@
* You should have received a copy of the GNU General Public License
* along with the program. If not, see <http ://www.gnu.org/licenses/>.
*/
require_once __DIR__ . "/includes/globals.inc";
// Common datastreams
define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL');
@ -160,7 +159,7 @@ function islandora_menu() {
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback',
'access arguments' => array(FEDORA_VIEW, 2, 4),
'load arguments' => array('%map'),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/view'] = array(
'title' => 'View datastream',
@ -174,7 +173,7 @@ function islandora_menu() {
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback',
'access arguments' => array(FEDORA_VIEW, 2, 4),
'load arguments' => array('%map'),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array(
'title' => 'Edit datastream',
@ -184,7 +183,7 @@ function islandora_menu() {
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_object_datastream_access_callback',
'access arguments' => array(FEDORA_METADATA_EDIT, 2, 4),
'load arguments' => array('%map'),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array(
'title' => 'Delete data stream',
@ -194,7 +193,7 @@ function islandora_menu() {
'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_datastream_access_callback',
'access arguments' => array(FEDORA_PURGE, 2, 4),
'load arguments' => array('%map'),
'load arguments' => array(2),
);
$items['islandora/ingest'] = array(
'title' => 'Add an Object',
@ -459,21 +458,6 @@ function islandora_default_islandora_view_object($object) {
* A helper function to get a connection and return an object for objects
* specified in the menu path as '%islandora_object'.
*
* This should only be used by the Drupal menu wildcard system!
*
* When this function returns FALSE the Drupal menu system will issues a
* "page not found" error, when this function returns NULL, the access function
* is expected to check for the given object and return false generating a
* "accesss denied" error.
*
* This will currently display a message if the repository is inaccessable,
* ideally this would redirect to another page in such a case,
* as the access function will not be aware of this fact and will trigger
* the display of the "access denied" page.
*
* @todo When the repository down this should return a 500 error or a
* site offline notice. Currently only displays a message.
*
* @param string $object_id
* The pid of an object in the menu path identified by '%islandora_object'.
*
@ -487,34 +471,33 @@ function islandora_default_islandora_view_object($object) {
* drupal_access_denied().
*/
function islandora_object_load($object_id) {
static $object = NULL, $load_failed = FALSE; // Assume inaccessible.
if ($load_failed || isset($object)) {
return $object;
}
$object = islandora_get_object_by_id($object_id); // Either NULL or FALSE.
if (!isset($object)) {
module_load_include('inc', 'islandora', 'includes/utilities');
if (islandora_describe_repository() === FALSE) {
drupal_set_message(t('The repository is not availible please contact the administrator.'), 'error');
module_load_include('inc', 'islandora', 'includes/IslandoraTuque');
$tuque = islandora_get_tuque_connection();
if ($tuque) {
try {
$object = $tuque->repository->getObject($object_id);
drupal_alter('islandora_object', $object);
return $object;
} catch (Exception $e) {
if ($e->getCode() == '404') {
return FALSE;
}
else {
return NULL;
}
}
$load_failed = TRUE;
}
return $object;
else {
IslandoraTuque::getError();
}
// Assuming access denied in all other cases for now.
return NULL;
}
/**
* A helper function to get an datastream specified as '%islandora_datastream'
* for the object specified in the menu path as '%islandora_object'.
*
* This should only be used by the Drupal menu wildcard system!
*
* The following settings are required for any menu paths which intent to use
* this auto loader.
*
* @code
* 'load arguments' => array('%map'),
* @endcode
*
* Its up to the access callbacks and menu callbacks to trigger
* drupal_access_denied() when appropriate.
*
@ -522,24 +505,21 @@ function islandora_object_load($object_id) {
* The dsid of the datastream specified as '%islandora_datastream' to fetch
* from the given object in the menu path identified by '%islandora_object'.
*
* $param string $object_id
* The object to load the datastream from.
*
* @return FedoraDatastream
* If the given datastream ID exists then this returns a FedoraDatastream
* object, otherwise it returns NULL which triggers drupal_page_not_found().
*/
function islandora_datastream_load($datastream_id, $map) {
static $datastream = NULL, $load_failed = FALSE;
if ($load_failed || isset($datastream)) {
return $datastream;
}
foreach ($map as $element) {
$is_fedora_object = is_object($element) && strtolower(get_class($element)) == 'fedoraobject';
if ($is_fedora_object && isset($element[$datastream_id])) {
$datastream = $element[$datastream_id];
return $datastream;
}
function islandora_datastream_load($datastream_id, $object_id) {
$object = islandora_object_load($object_id);
if(!$object) {
return NULL;
}
$load_failed = TRUE;
return $datastream;
return $object[$datastream_id];
}
/**
@ -612,3 +592,196 @@ function islandora_islandora_required_objects() {
function islandora_islandora_undeletable_datastreams(array $models) {
return array('DC');
}
/**
* Ingest the given object into Fedora calling its pre/post hooks as well.
*
* @todo will be cleaned up in the future
*
* @param NewFedoraObject $object
* An ingestable FedoraObject.
*
* @return FedoraObject
* The ingested FedoraObject, after running the pre/post ingest hooks.
*/
function islandora_add_object(NewFedoraObject &$object) {
islandora_pre_add_object($object);
$object->repository->ingestObject($object);
islandora_post_add_object($object);
return $object;
}
/**
* Calls the ISLANDORA_PRE_INGEST_HOOK hooks.
*
* @param NewFedoraObject $object
* An ingestable FedoraObject.
*/
function islandora_pre_add_object(NewFedoraObject $object) {
module_load_include('inc', 'islandora', 'includes/utilities');
foreach (islandora_build_hook_list(ISLANDORA_PRE_INGEST_HOOK, $object->models) as $hook) {
module_invoke_all($hook, $object);
}
}
/**
* Calls the ISLANDORA_POST_INGEST_HOOK hooks.
*
* @param FedoraObject $object
* A recently ingestable FedoraObject.
*/
function islandora_post_add_object(FedoraObject $object) {
foreach (islandora_build_hook_list(ISLANDORA_POST_INGEST_HOOK, $object->models) as $hook) {
module_invoke_all($hook, $object);
}
}
/**
* Deletes the given object into Fedora calling its pre/post hooks as well.
*
* @param FedoraObject $object
* An object to delete.
*
* @return FedoraObject
* The ingested FedoraObject, after running the pre/post ingest hooks.
*/
function islandora_delete_object(FedoraObject &$object) {
$object_id = $object->id;
$models = $object->models;
$action = islandora_pre_delete_object($object);
switch ($action) {
case 'blocked':
// Do nothing.
return FALSE;
case 'delete':
// Change the state to deleted.
$object->delete();
islandora_post_delete_object($object_id, $models);
return TRUE;
default:
// Purge
$object->repository->purgeObject($object_id);
islandora_post_delete_object($object_id, $models);
$object = NULL;
return TRUE;
}
}
/**
* Calls the ISLANDORA_PRE_PURGE_OBJECT_HOOK hooks.
*
* @param FedoraObject $object
* The object that is about to be deleted.
*/
function islandora_pre_delete_object(FedoraObject $object) {
module_load_include('inc', 'islandora', 'includes/utilities');
$results = array();
foreach (islandora_build_hook_list(ISLANDORA_PRE_PURGE_OBJECT_HOOK, $object->models) as $hook) {
$results = array_merge_recursive($results, module_invoke_all($hook, $object));
}
$action = (isset($results['block']) && $results['block']) ? 'block' : FALSE;
$action = (!$action && isset($results['delete']) && $results['delete']) ? 'delete' : $action;
$action = !$action ? 'purge' : $action;
return $action;
}
/**
* Calls the ISLANDORA_POST_PURGE_OBJECT_HOOK hooks.
*
* @param string $object_id
* The object id of an the recently deleted object.
* @param array $models
* The list of content models the delete object subsribed to.
*/
function islandora_post_delete_object($object_id, array $models) {
module_load_include('inc', 'islandora', 'includes/utilities');
foreach (islandora_build_hook_list(ISLANDORA_POST_PURGE_OBJECT_HOOK, $models) as $hook) {
module_invoke_all($hook, $object_id, $models);
}
}
/**
* Delete's/Purges the given datastream.
*
* @throws Exception
* Which types are undefined, but more than likely because of the hooks
* there will be several kinds.
*
* @param FedoraDatastream $datastream
* The datastream to delete.
*
* @return boolean
* TRUE is returned if the datastream was Deleted/Purged, FALSE if it was
* blocked.
*/
function islandora_delete_datastream(FedoraDatastream &$datastream) {
$datastream_id = $datastream->id;
$object = $datastream->parent;
$action = islandora_pre_delete_datastream($datastream);
switch ($action) {
case 'blocked':
// Do nothing.
return FALSE;
case 'delete':
// Change the state to deleted.
$object[$datastream_id]->state = 'D';
// @todo Differentiate between delete/purge in the hooks.
islandora_post_delete_datastream($object, $datastream_id);
return TRUE;
default:
// Purge
$object->purgeDatastream($datastream_id);
islandora_post_delete_datastream($object, $datastream_id);
$datastream = NULL;
return TRUE;
}
}
/**
* The default behaviour is to 'purge' the datastream but this can be overridden
* by modules that implement the 'islandora_pre_purge_datastream' hook.
*
* @todo make this an alter.
*
* The returned array can include a 'block' => TRUE
* pair which will prevent the datastream from being deleted if it particularly
* needed for a certain function. Returning 'delete' => TRUE will cause the
* datastream to be put into a deleted state.
*
* @param FedoraDatastream $datastream
* The datastream to delete.
*
* @return string
* The action to take when deleting the given datastream, either 'purge',
* 'delete', or 'block'.
*/
function islandora_pre_delete_datastream(FedoraDatastream $datastream) {
module_load_include('inc', 'islandora', 'includes/utilities');
$results = array();
foreach (islandora_build_hook_list(ISLANDORA_PRE_PURGE_DATASTREAM_HOOK, $datastream->parent->models) as $hook) {
// Not sure this will work the greatest, probably an alter would be better..
$results = array_merge_recursive($results, module_invoke_all($hook, $datastream));
}
$action = (isset($results['block']) && $results['block']) ? 'block' : FALSE;
$action = (!$action && isset($results['delete']) && $results['delete']) ? 'delete' : $action;
$action = !$action ? 'purge' : $action;
return $action;
}
/**
* Calls the post purge datastream hooks.
*
* @todo Should differentiate between purging/deleting.
*
* @param FedoraObject $object
* The parent object of the deleted datastream.
* @param string $datastream_id
* The datastream id of the deleted datastream.
*/
function islandora_post_delete_datastream(FedoraObject $object, $datastream_id) {
module_load_include('inc', 'islandora', 'includes/utilities');
foreach (islandora_build_hook_list(ISLANDORA_POST_PURGE_DATASTREAM_HOOK, $object->models) as $hook) {
module_invoke_all($hook, $object, $datastream_id);
}
}
Loading…
Cancel
Save