diff --git a/README b/README index 7a642cc4..1a3479e8 100644 --- a/README +++ b/README @@ -1,9 +1,59 @@ +CONTENTS OF THIS FILE +--------------------- + + * summary + * requirements + * installation + * configuration + * customization + * troubleshooting + * faq + * contact + * sponsors + + +SUMMARY +------- + Islandora Fedora Repository Module -For installation and customization instructions please see the documentation and the DuraSpace Wiki: +For installation and customization instructions please see the documentation +and the DuraSpace Wiki: https://wiki.duraspace.org/display/ISLANDORA/Islandora -All bugs, feature requests and improvement suggestions are tracked at the DuraSpace JIRA: +All bugs, feature requests and improvement suggestions are tracked at the +DuraSpace JIRA: https://jira.duraspace.org/browse/ISLANDORA + +REQUIREMENTS +------------ + + +INSTALLATION +------------ + + +CONFIGURATION +------------- + + +CUSTOMIZATION +------------- + + +TROUBLESHOOTING +--------------- + + +F.A.Q. +------ + + +CONTACT +------- + + +SPONSORS +-------- \ No newline at end of file diff --git a/admin/islandora.admin.inc b/admin/islandora.admin.inc index 46bd06a6..3a71c652 100644 --- a/admin/islandora.admin.inc +++ b/admin/islandora.admin.inc @@ -2,7 +2,9 @@ /** * @file - * islandora.admin.inc: This file contains the general islandora admin form and callback functions. + * + * islandora.admin.inc: This file contains the general islandora admin form and + * callback functions. */ /** @@ -11,9 +13,7 @@ * @return array */ function islandora_repository_admin($form, &$form_state) { - module_load_include('inc', 'islandora', 'includes/tuque'); module_load_include('inc', 'islandora', 'includes/utilities'); - // add css drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css'); if (!IslandoraTuque::exists()) { @@ -22,7 +22,6 @@ function islandora_repository_admin($form, &$form_state) { } $form = array(); - if (isset($form_state['values']['islandora_base_url'])) { $url = $form_state['values']['islandora_base_url']; } @@ -30,7 +29,6 @@ function islandora_repository_admin($form, &$form_state) { $url = variable_get('islandora_base_url', 'http://localhost:8080/fedora'); } - module_load_include('inc', 'islandora', 'includes/tuque'); $connection = new IslandoraTuque(NULL, $url); try { $info = $connection->api->a->describeRepository(); @@ -156,7 +154,6 @@ function islandora_repository_admin($form, &$form_state) { function islandora_update_url_div($form, $form_state) { unset($form_state['submit_handlers']); $form_state['rebuild'] = TRUE; - return $form['islandora_tabs']['islandora_general']['wrapper']; } @@ -166,6 +163,5 @@ function islandora_update_url_div($form, $form_state) { function islandora_update_namespace_div($form, $form_state) { unset($form_state['submit_handlers']); $form_state['rebuild'] = TRUE; - return $form['islandora_tabs']['islandora_namespace']['wrapper']; } diff --git a/includes/islandora_dublin_core.inc b/includes/DublinCore.inc similarity index 93% rename from includes/islandora_dublin_core.inc rename to includes/DublinCore.inc index 25580b34..7c2b094c 100644 --- a/includes/islandora_dublin_core.inc +++ b/includes/DublinCore.inc @@ -2,6 +2,7 @@ /** * @file + * * Implements a simple class for working with Dublin Core data and exporting it * back to XML. Inspiration and design shamelessly stolen from the pyfedora * project at http://pypi.python.org/pypi/pyfedora/0.1.0 @@ -10,7 +11,7 @@ /** * Dublin Core Class */ -class Dublin_Core { +class DublinCore { public $dc = array( 'dc:title' => array(), @@ -32,11 +33,12 @@ class Dublin_Core { public $owner; /** - * Constructs a Dublin_Core object from a Fedora_Item object and populates - * the $dc array. - * @param $item + * Constructs a DublinCore object from a Fedora_Item object and populates the + * $dc array. + * + * @param string $dc_xml */ - function Dublin_Core($dc_xml = NULL) { + function DublinCore($dc_xml = NULL) { if (!empty($dc_string)) { $this->dc = self::import_from_xml_string($dc_xml); } @@ -134,14 +136,15 @@ class Dublin_Core { /** * Creates a new instance of the class by parsing dc_xml + * * @param string $dc_xml - * @return Dublin_Core + * @return DublinCore */ static function import_from_xml_string($dc_xml) { $dc_doc = new DomDocument(); if ($dc_doc->loadXML($dc_xml)) { $oai_dc = $dc_doc->getElementsByTagNameNS('http://purl.org/dc/elements/1.1/', '*'); - $new_dc = new Dublin_Core(); + $new_dc = new DublinCore(); foreach ($oai_dc as $child) { array_push($new_dc->dc[$child->nodeName], $child->nodeValue); } @@ -153,4 +156,3 @@ class Dublin_Core { } } - diff --git a/includes/tuque.inc b/includes/IslandoraTuque.inc similarity index 76% rename from includes/tuque.inc rename to includes/IslandoraTuque.inc index 7693a703..89086829 100644 --- a/includes/tuque.inc +++ b/includes/IslandoraTuque.inc @@ -2,6 +2,7 @@ /** * @file + * * This file contains a class to include the Tuque php library. */ @@ -77,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); } } @@ -97,3 +98,27 @@ class IslandoraTuque { } } +/** + * 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()) { + require_once(__DIR__ . '/IslandoraTuqueWrapper.inc'); + 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; +} diff --git a/includes/IslandoraTuqueWrapper.inc b/includes/IslandoraTuqueWrapper.inc new file mode 100644 index 00000000..ff109c1b --- /dev/null +++ b/includes/IslandoraTuqueWrapper.inc @@ -0,0 +1,55 @@ + "islandora/object/{$object->id}", + '#attributes' => array( + 'enctype' => 'multipart/form-data' + ), + 'fieldset' => array( + '#type' => 'fieldset', + '#title' => 'Add a datastream', + '#collapsible' => FALSE, + '#collapsed' => FALSE, + 'dsid' => array( + '#title' => 'Datastream ID', + '#description' => t('An ID for this stream that is unique to this object.' . + 'Must start with a letter and contain only alphanumeric ' . + 'characters and dashes and underscores. Datastreams that ' . + 'are defined by the content model don\'t currently exist: ' . + '@unused_dsids.', + array('@unused_dsids' => $unused_datastreams) + ), + '#type' => 'textfield', + '#size' => 64, + '#maxlength' => 64, + '#required' => TRUE, + '#element_validate' => array( + 'islandora_add_datastream_form_field_is_not_an_existing_datastream_id', + 'islandora_add_datastream_form_field_starts_with_a_letter', + 'islandora_add_datastream_form_field_is_valid_dsid', + ), + '#autocomplete_path' => "islandora/object/{$object->id}/manage/datastreams/add/autocomplete" + ), + 'label' => array( + '#title' => 'Datastream Label', + '#required' => TRUE, + '#size' => 64, + '#maxlength' => 64, + '#description' => t('A Human readable label'), + '#type' => 'textfield', + '#element_validate' => array('islandora_add_datastream_form_field_does_not_contain_a_forward_slash') + ), + 'file' => array( + '#type' => 'managed_file', + '#required' => TRUE, + '#title' => t('Upload Document'), + '#size' => 48, + '#description' => t('Select a file to upload.
Files must be less than @size MB.', array('@size' => $upload_size)), + '#default_value' => isset($form_state['values']['files']) ? $form_state['values']['files'] : NULL, + '#upload_location' => 'temporary://', + '#upload_validators' => array( + 'file_validate_extensions' => array(NULL), + // Assume its specified in MB + 'file_validate_size' => array($upload_size * 1024 * 1024), + ), + ), + 'submit' => array( + '#type' => 'submit', + '#value' => t('Add Datastream') + ), + ) + ); +} + +/** + * Checks if the given form field doesn't already repersent a Datastream ID. + * + * @param array $element + * The form field to check. + * @param array $form_state + * The Drupal form state. + * @param array $form + * The Drupal form. + */ +function islandora_add_datastream_form_field_is_not_an_existing_datastream_id(array $element, array &$form_state, array $form) { + if (isset($form_state['object'][$element['#value']])) { + form_error($element, t("@title already exists in the object.", array('@title' => $element['#title']))); + } +} + +/** + * Checks if the given form field starts with a letter. + * + * @param array $element + * The form field to check. + * @param array $form_state + * The Drupal form state. + * @param array $form + * The Drupal form. + */ +function islandora_add_datastream_form_field_starts_with_a_letter(array $element, array &$form_state, array $form) { + if (!(preg_match("/^[a-zA-Z]/", $element['#value']))) { + form_error($element, t("@title has to start with a letter.", array('@title' => $element['#title']))); + } +} + +/** + * Checks if the given form field contains only valid characters for a + * datastream id. + * + * @param array $element + * The form field to check. + * @param array $form_state + * The Drupal form state. + * @param array $form + * The Drupal form. + */ +function islandora_add_datastream_form_field_is_valid_dsid(array $element, array &$form_state, array $form) { + module_load_include('inc', 'islandora', 'includes/utilities'); + if (!islandora_is_valid_dsid($element['#value'])) { + form_error($element, t("@title contains invalid characters.", array('@title' => $element['#title']))); + } +} + +/** + * Checks if the given form field contains a "/" character. + * + * @param array $element + * The form field to check. + * @param array $form_state + * The Drupal form state. + * @param array $form + * The Drupal form. + */ +function islandora_add_datastream_form_field_does_not_contain_a_forward_slash(array $element, array &$form_state, array $form) { + if (strpos($element['#value'], '/') !== FALSE) { + form_error($element, t('@title cannot contain a "/" character.', array('@title' => $element['#title']))); + } +} + +/** + * Checks if the given datastream id requires that the upload file be of a + * certian MIME type. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_add_datastream_form_validate(array $form, array &$form_state) { + $file = file_load($form_state['values']['file']); + $dsid = $form_state['values']['dsid']; + if (isset($form_state['datastream_requirements'][$dsid]) && $file) { + $allowed_types = $form_state['datastream_requirements'][$dsid]['mime']; + $mime_detect = new MimeDetect(); + $allowed_extensions = array_map(array($mime_detect, 'getExtension'), $allowed_types); + $errors = file_validate_extensions($file, implode(' ', $allowed_extensions)); + if (count($errors) > 0) { + form_set_error('file', $errors[0]); + } + } +} + +/** + * Adds the new datastream based on the submitted values, only creates managed + * datastreams at the moment. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_add_datastream_form_submit(array $form, array &$form_state) { + $object = $form_state['object']; + $form_state['redirect'] = "islandora/object/{$object->id}"; + $file = file_load($form_state['values']['file']); + try { + $ds = $object->constructDatastream($form_state['values']['dsid'], 'M'); + $ds->label = $form_state['values']['label']; + $ds->mimetype = $file->filemime; + $path = drupal_realpath($file->uri); + $ds->setContentFromFile($path); + $object->ingestDatastream($ds); + file_delete($file); + } catch (exception $e) { + drupal_set_message(t('@message', array('@message' => check_plain($e->getMessage()))), 'error'); + file_delete($file); // Make sure to delete anyways. + return; + } + drupal_set_message(t("Successfully Added Datastream!")); +} + +/** + * Callback for an autocomplete field in the admin add datastream form. + * It lists the missing required (may be optional) datastreams. + * + * @param FedoraObject $object + * The object used to check for missing required datastreams used to populate + * the options in this callback. + * @param string $query + * vThe user query to match against the missing required datastreams. + */ +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); + if (!empty($query)) { + $dsids = array_filter($dsids, function($id) use($query) { return stripos($id, $query) !== FALSE; }); + } + drupal_json_output($dsids); +} diff --git a/includes/breadcrumb.inc b/includes/breadcrumb.inc index 5e553277..6abb480c 100644 --- a/includes/breadcrumb.inc +++ b/includes/breadcrumb.inc @@ -2,23 +2,36 @@ /** * @file + * * This file contains functions to create breadcrumbs on Islandora object pages. */ /** - * Callback function to get the breadcrumbs for an object page + * Get an array of links to be passed to drupal_set_breadcrumb(). This is used + * for generating the bread-crumbs for the view object page. + * + * Each link in the bread-crumbs represents a member of the given objects ancestry + * which is identified by any of the following RELS-EXT terms + * (isMemberOf,isMemberOfCollection,isPartOf). + * + * @param FedoraObject $object + * An object whose ancestry will be mapped to bread-crumbs. + * + * @see drupal_set_breadcrumb() + * + * @return array + * Array of links, starting with most distant ancestor proceeding up to but + * not including the given object. For use in the function + * drupal_set_breadcrumb(). */ function islandora_get_breadcrumbs($object) { $breadcrumbs = array(); - islandora_get_breadcrumbs_recursive($object->id, $breadcrumbs, $object->repository); - if (isset($breadcrumbs[0])) { + // Remove the actual object. unset($breadcrumbs[0]); } - $breadcrumbs = array_reverse($breadcrumbs); - return $breadcrumbs; } @@ -27,14 +40,19 @@ function islandora_get_breadcrumbs($object) { * * @todo Make fully recursive... * - * @global type $base_url - * @param type $pid - * @param type $breadcrumbs - * @param type $level + * @todo Could use some clean up, can't be called multiple times safely due to + * the use of static variables. + * + * @param string $pid + * THe object id whose parent will be fetched for the next link. + * @param array $breadcrumbs + * The list of existing bread-crumb links in reverse order. + * @param FedoraRepository $repository + * The fedora repository. */ -function islandora_get_breadcrumbs_recursive($pid, &$breadcrumbs, $repository) { - // Before executing the query, we hve a base case of accessing the top-level collection - global $base_url; +function islandora_get_breadcrumbs_recursive($pid, array &$breadcrumbs, FedoraRepository $repository) { + // Before executing the query, we hve a base case of accessing the + // top-level collection static $max_level = 10; static $level = -1; @@ -77,8 +95,10 @@ function islandora_get_breadcrumbs_recursive($pid, &$breadcrumbs, $repository) { islandora_get_breadcrumbs_recursive($parent, $breadcrumbs, $repository); } else { - $breadcrumbs[] = '...'; // Add an non-link, as we don't know how to get back to the root. - islandora_get_breadcrumbs_recursive($root, $breadcrumbs, $repository); // And render the last two links and break (on the next pass). + // Add an non-link, as we don't know how to get back to the root. + $breadcrumbs[] = '...'; + // And render the last two links and break (on the next pass). + islandora_get_breadcrumbs_recursive($root, $breadcrumbs, $repository); } } -} \ No newline at end of file +} diff --git a/includes/datastream.inc b/includes/datastream.inc index ba986c12..c6cb2780 100644 --- a/includes/datastream.inc +++ b/includes/datastream.inc @@ -2,492 +2,143 @@ /** * @file - * This file contains the admin form and callback functions for datastream manipulations. + * + * This file contains the admin form and callback functions for datastream + * manipulations. */ -define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL'); +/** + * Callback to download the given datastream to the users computer. + * + * @param FedoraDatastream $datastream + * The datastream to download. + */ +function islandora_download_datastream(FedoraDatastream $datastream) { + islandora_view_datastream($datastream, TRUE); +} /** * Callback function to view or download a datastream. * - * @global object $user - * @param string $object_id - * @param string $dsid - * @return stream - * prints datastream to browser + * @note + * This function calls exit(). + * + * @param FedoraDatastream $datastream + * The datastream to view/download. + * @param boolean $download + * If TRUE the file is download to the user computer for viewing otherwise it + * will attempt to display in the browser natively. */ -function islandora_view_datastream($object, $dsid, $method = 'view') { - // if the object exists but the datastream doesn't - if (!isset($object[$dsid])) { - return drupal_not_found(); - } +function islandora_view_datastream(FedoraDatastream $datastream, $download = FALSE) { header_remove('Cache-Control'); header_remove('Expires'); - header('Content-type: ' . $object[$dsid]->mimetype); - if ($object[$dsid]->controlGroup == 'M' || $object[$dsid]->controlGroup == 'X') { - header('Content-length: ' . $object[$dsid]->size); + header('Content-type: ' . $datastream->mimetype); + if ($datastream->controlGroup == 'M' || $datastream->controlGroup == 'X') { + header('Content-length: ' . $datastream->size); } - - if ($method == 'download') { - header("Content-Disposition: attachment; filename=\"" . $object[$dsid]->label); + if ($download) { + header("Content-Disposition: attachment; filename=\"{$datastream->label}\""); } - - // Disable page caching drupal_page_is_cacheable(FALSE); - - // Try not to load the file into PHP memory + // Try not to load the file into PHP memory! $file = drupal_tempnam(file_directory_temp(), 'islandora'); - $object[$dsid]->getContent($file); + $datastream->getContent($file); readfile($file); drupal_unlink($file); exit(); } /** - * For a given object, return all parent collections. - */ -function islandora_datastream_get_parents($islandora_object) { - $parent_collections = array(); - - try { - $repository = $islandora_object->repository; - $collections1 = $islandora_object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOfCollection'); - $collections2 = $islandora_object->relationships->get(FEDORA_RELS_EXT_URI, 'isMemberOf'); - } - catch (RepositoryException $e) { - $collections1 = array(); - $collections2 = array(); - } - $collections = array_merge($collections1, $collections2); - - foreach ($collections as $collection) { - try { - $pid = $collection['object']['value']; - $object = $repository->getObject($collection['object']['value']); - $parent_collections[$pid] = array(); - $parent_collections[$pid]['object'] = $object; - $parent_collections[$pid]['url'] = 'islandora/object/' . $object->id; - $parent_collections[$pid]['label'] = $object->label; - $parent_collections[$pid]['label_link'] = l($parent_collections[$pid]['label'], $parent_collections[$pid]['url']); - } - catch (RepositoryException $e) { - - } - } - - return $parent_collections; -} - -/** + * Get the human readable size of the given datastream. + * + * @param FedoraDatastream $datastream + * The datastream to check. * - * @param array $arr - * an array of dsids that are defined by this objects cmodels - * @param string $ds_comp_stream - * the dscomposite stream as xml + * @return string + * A human readable size of the given datastream, or '-' if the size could not + * be determined. */ -function islandora_get_defined_dsids_array(&$arr, $ds_comp_stream) { - $sxml = new SimpleXMLElement($ds_comp_stream); - foreach ($sxml->dsTypeModel as $ds) { - //$arr[$ds['ID']] - $mimes = array(); - foreach ($ds->form as $form) { - $mimetype = (string) $form['MIME']; - $mimes[] = $mimetype; - } - $dsid = (string) $ds['ID']; - if ($dsid != 'AUDIT') { - $arr[(string) $ds['ID']] = $mimes; - } - } +function islandora_datastream_get_human_readable_size(FedoraDatastream $datastream) { + module_load_include('inc', 'islandora', 'includes/utilities'); + $size_is_calculatable = $datastream->controlGroup == 'M' || $datastream->controlGroup == 'X'; + return $size_is_calculatable ? islandora_convert_bytes_to_human_readable($datastream->size) : '-'; } /** + * Get either the 'view' or 'download' url for the given datastream if possible. * - * @global type $user - * @param string $object_id - * @return string|array + * @param FedoraDatastream $datastream + * The datastream to generated the url to. + * + * @return string + * either the 'view' or 'download' url for the given datastream. */ -function islandora_get_unused_dsids($object) { - - $defined_dsids = array(); - - if (!$object) { - return $defined_dsids; - } - - $models = $object->models; - if (isset($models)) { - foreach ($models as $model) { - try { - $model_object = $object->repository->getObject($model); - if (isset($model_object[DS_COMP_STREAM])) { - $dscomposite_stream = $model_object[DS_COMP_STREAM]->content; - islandora_get_defined_dsids_array($defined_dsids, $dscomposite_stream); - } - } catch (Exception $e) { - //do nothing as other objects may have a dscompsite stream - } - } - } - foreach ($defined_dsids as $key => $value) { - if (isset($object[$key])) { - unset($defined_dsids[$key]); //ds exists in the object so don't show in the dropdown - } - } - return $defined_dsids; +function islandora_datastream_get_url(FedoraDatastream $datastream, $type = 'download') { + return $datastream->controlGroup == 'R' ? $datastream->url : "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/$type"; } /** - * buids the default add datastream form - * @param string $object_id - * @param array $form_state - * @return array - * a form ready to be rendered with a call to Drupal render + * Gets the delete link. + * + * @param FedoraDatastream $datastream + * The datastream to generated the url to. */ -function islandora_get_add_datastream_form($object, &$form_state) { - $unused_dsids = islandora_get_unused_dsids($object); - $form = array(); - $form['add_fieldset'] = array( - '#type' => 'fieldset', - '#title' => 'Add a datastream', - '#collapsible' => TRUE, - '#collapsed' => TRUE, - ); - $form['add_fieldset']['add_datastream_label'] = array( - '#value' => t('

Add Datastream:

'), - '#weight' => -10, - ); - - $form['pid'] = array( - '#type' => 'hidden', - '#value' => "$object->id" - ); - - $form['add_fieldset']['stream_label'] = array( - '#title' => 'Datastream Label', - '#required' => 'TRUE', - '#description' => t('A Human readable label'), - '#type' => 'textfield' - ); - - $form['#attributes']['enctype'] = 'multipart/form-data'; - $form['add_fieldset']['add-stream-file-location'] = array( - '#type' => 'file', - '#title' => t('Upload Document'), - '#size' => 48, - // '#required'=>'TRUE', - '#description' => t('The file to upload.') - ); - $form['#redirect'] = "islandora/object/$object->id/"; - $form['add_fieldset']['submit'] = array( - '#type' => 'submit', - '#value' => t('Add Datastream') - ); - - if (!empty($unused_dsids)) { - $dsids_for_form = array(); - foreach ($unused_dsids as $key => $value) { - $dsids_for_form[$key] = $key; - } - $form['add_fieldset']['stream_id'] = array( - '#type' => 'select', - '#title' => t('Datastream ID'), - '#default_value' => variable_get('feed_item_length', 'teaser'), - '#weight' => '-1', - '#description' => t('Datastream IDs defined by the content model.'), - ); - $form['add_fieldset']['stream_id']['#options'] = $dsids_for_form; - } - else { - $form['add_fieldset']['stream_id'] = array( - '#title' => 'Datastream ID', - '#required' => 'TRUE', - '#description' => t('An ID for this stream that is unique to this object. Must start with a letter and contain only alphanumeric characters and dashes and underscores.'), - '#type' => 'textfield', - '#weight' => -1, - ); - } - return $form; +function islandora_datastream_get_delete_link(FedoraDatastream $datastream) { + $datastreams = module_invoke_all('islandora_undeletable_datastreams', $datastream->parent->models); + $can_delete = !in_array($datastream->id, $datastreams); + return $can_delete ? l(t('delete'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/delete") : ''; } /** - * Default implmentation currently only does M (managed datastreams) - * other modules can hook form alter to add other functionality - * @global string $base_url - * @global object $user - * Drupal user - * @param array $form - * @param array $form_state - * @return type + * Gets the edit link. + * + * @param FedoraDatastream $datastream + * The datastream to generated the url to. */ -function islandora_add_datastream_form_submit($form, &$form_state) { - global $base_url; - if (!empty($form_state['submit']) && $form_state['submit'] == 'OK') { - $form_state['rebuild'] = TRUE; - return; - } - - module_load_include('inc', 'islandora', 'includes/mime.detect'); - $mimetype = new MimeDetect(); - - $file = $form_state['values']['add-stream-file-location']; - $file = drupal_realpath($file); - - $object_id = $form_state['values']['pid']; - $dsid = $form_state['values']['stream_id']; - $ds_label = $form_state['values']['stream_label']; - $dformat = $mimetype->getMimeType($file); - $control_group = "M"; - - try { - $fedora_object = islandora_object_load($object_id); - $ds = $fedora_object->constructDatastream($dsid, $control_group); - $ds->label = $ds_label; - $ds->mimetype = $dformat; - $ds->setContentFromFile($file); - $fedora_object->ingestDatastream($ds); - $d_file = file_load($form_state['values']['fid']); - file_delete($d_file); - } catch (exception $e) { - drupal_set_message(t('@message', array('@message' => check_plain($e->getMessage()))), 'error'); - return; - } - drupal_set_message(t("Successfully Added Datastream!")); - drupal_goto("islandora/object/$object_id"); +function islandora_datastream_edit_get_link(FedoraDatastream $datastream) { + $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); + $can_edit = count($edit_registry) > 0 && user_access(FEDORA_METADATA_EDIT); + return $can_edit ? l(t('edit'), "islandora/object/{$datastream->parent->id}/datastream/{$datastream->id}/edit") : ''; } /** - * validates this datastream id against its allowed mimetypes in the dscomposite - * of its content models. - * @param array $form - * @param array $form_state - * @return boolean + * Display the edit datastream page. + * + * @param FedoraDatastream $datastream + * The datastream to edit. */ -function islandora_add_datastream_form_validate($form, &$form_state) { - module_load_include('inc', 'islandora', 'includes/mime.detect'); - $mimetype = new MimeDetect(); - if ($form_state['clicked_button']['#value'] == 'OK') { - $form_state['rebuild'] = TRUE; - return; - } - $dsid = $form_state['values']['stream_id']; - $ds_label = $form_state['values']['stream_label']; - if (drupal_strlen($dsid) > 64) { - form_set_error('', t('Data stream ID cannot be more than 64 characters.')); - return FALSE; - } - if (!(preg_match("/^[a-zA-Z]/", $dsid))) { - form_set_error('', t("Data stream ID (@dsid) has to start with a letter.", array('@dsid' => check_plain($dsid)))); - return FALSE; - } - if (drupal_strlen($ds_label) > 64) { - form_set_error('', t('Data stream Label cannot be more than 64 characters.')); - return FALSE; - } - if (strpos($ds_label, '/')) { - form_set_error('', t('Data stream Label cannot contain a "/".')); - return FALSE; - } - - $object_id = $form_state['values']['pid']; - $fedora_object = islandora_object_load($object_id); - - if (isset($fedora_object[$dsid])) { - form_set_error('', t('Data stream ID already exists in object.')); - return FALSE; - } - - $mimetype = new MimeDetect(); - $object = islandora_object_load($form_state['values']['pid']); - $unused_dsids = islandora_get_unused_dsids($object); - if (isset($unused_dsids[$dsid])) { - $types_allowed = $unused_dsids[$dsid]; - $arr = array(); - foreach ($types_allowed as $type) { - $arr[] = $mimetype->getExtension($type); - } - } - else { - // @TODO: this is unsafe, should probably be fixed see: - // http://api.drupal.org/api/drupal/includes!file.inc/function/file_save_upload/7 - $arr = array(); - } - - - $file = file_save_upload('add-stream-file-location', array('file_validate_extensions' => $arr)); - if ($file) { - $form_state['values']['add-stream-file-location'] = $file->uri; - $form_state['values']['fid'] = $file->fid; //so we can load it to delete later - } - else { - form_set_error('add-stream-file-location', t('There was no file uploaded')); +function islandora_edit_datastream(FedoraDatastream $datastream) { + $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $datastream->parent, $datastream); + $edit_count = count($edit_registry); + switch ($edit_count) { + case 0: + // No edit implementations. + drupal_set_message(t('There are no edit methods specified for this datastream.')); + drupal_goto("islandora/object/{$object->id}/manage/datastreams"); + break; + case 1: + // One registry implementation, go there + drupal_goto($edit_registry[0]['url']); + break; + default: + // Multiple edit routes registered + return islandora_edit_datastream_registry_render($edit_registry); } } - /** - * buids the default add datastream form - * @param string $object_id - * @param array $form_state - * @return array - * a form ready to be rendered with a call to Drupal render + * Displays links to all the edit datastream registry items. + * + * @param array $edit_registry + * A list of 'islandora_edit_datastream_registry' values. */ -function islandora_add_datastream_form($form, &$form_state, $object) { - // Ensure we're loaded, in case AJAX stuff is ever added. - form_load_include($form_state, 'inc', 'islandora', 'includes/datastream'); - - $unused_dsids = islandora_get_unused_dsids($object); //$defined_dsids; - $form = array(); - $form['add_fieldset'] = array( - '#type' => 'fieldset', - '#title' => 'Add a datastream', - '#collapsible' => FALSE, - '#collapsed' => FALSE, - ); - $form['add_fieldset']['add_datastream_label'] = array( - '#value' => t('

Add Datastream:

'), - '#weight' => -10, - ); - - $form['pid'] = array( - '#type' => 'hidden', - '#value' => "$object->id" - ); - - $form['add_fieldset']['stream_label'] = array( - '#title' => 'Datastream Label', - '#required' => 'TRUE', - '#description' => t('A Human readable label'), - '#type' => 'textfield' - ); - - $form['#attributes']['enctype'] = 'multipart/form-data'; - $form['add_fieldset']['add-stream-file-location'] = array( - '#type' => 'file', - '#title' => t('Upload Document'), - '#size' => 48, - // '#required'=>'TRUE', - '#description' => t('The file to upload.') - ); - $form['#redirect'] = "islandora/object/$object->id/"; - $form['add_fieldset']['submit'] = array( - '#type' => 'submit', - '#value' => t('Add Datastream') - ); - - $unused_dsids = islandora_get_unused_dsids($object); - $dsids_for_form = ''; - $i = 0; - foreach ($unused_dsids as $key => $value) { - if ($i++) { - $dsids_for_form .= ", "; - } - $dsids_for_form .= "'$key'"; - } - - $form['add_fieldset']['stream_id'] = array( - '#title' => 'Datastream ID', - '#required' => 'TRUE', - '#description' => t('An ID for this stream that is unique to this object. Must start with a letter and contain only alphanumeric characters and dashes and underscores. Datastreams that are defined by the content model don\'t currently exist: @unused_dsids.', array( - '@unused_dsids' => $dsids_for_form, - )), - '#type' => 'textfield', - '#weight' => -1, - '#autocomplete_path' => "islandora/object/$object->id/manage/datastreams/add/autocomplete", - ); - return $form; -} - -function islandora_datastream_autocomplete_callback($object, $string = '') { - $dsids = islandora_get_unused_dsids($object); - $output = array(); - foreach ($dsids as $id => $ds) { - if (trim($string) == '') { - $output[$id] = $id; - } - else { - $ret = stripos($id, $string); - if ($ret !== FALSE) { - $output[$id] = $id; - } - } - } - drupal_json_output($output); -} - -function islandora_datastream_get_human_readable_size($ds) { - module_load_include('inc', 'islandora', 'includes/utilities'); - - // we return - if we don't have a size - if ($ds->controlGroup == 'M' || $ds->controlGroup == 'X') { - return islandora_convert_bytes_to_human_readable($ds->size); - } - else { - return '-'; - } -} - -function islandora_datastream_get_url($ds, $type = 'download') { - if ($ds->controlGroup == 'R') { - return $ds->url; - } - else { - return "islandora/object/{$ds->parent->id}/datastream/{$ds->id}/$type"; +function islandora_edit_datastream_registry_render(array $edit_registry) { + $markup = ''; + foreach ($edit_registry as $edit_route) { + $markup .= l($edit_route['name'], $edit_route['url']) . '
'; } -} - -function islandora_datastream_get_delete_link($ds) { - $datastreams = module_invoke_all('islandora_undeletable_datastreams', $ds->parent->models); - - if (in_array($ds->id, $datastreams)) { - return ''; - } - else { - return l(t('delete'), 'islandora/object/' . $ds->parent->id . '/datastream/' . $ds->id . '/delete'); - } -} - -function islandora_islandora_undeletable_datastreams($models) { - return array('DC'); -} - -function islandora_datastream_edit_get_link($object, $ds_id) { - $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $object, $ds_id); - if (count($edit_registry) > 0 && user_access(FEDORA_METADATA_EDIT)) { - return l(t('edit'), 'islandora/object/' . $object->id . '/datastream/' . $ds_id . '/edit'); - } - else { - return ''; - } -} - -function islandora_edit_datastream($object, $ds_id) { - $edit_registry = module_invoke_all('islandora_edit_datastream_registry', $object, $ds_id); - $edit_count = count($edit_registry); - - if ($edit_count == 0) { - // No edit implementations. - drupal_set_message(t('There are no edit methods specified for this datastream.')); - drupal_goto('islandora/object/' . $object->id . '/manage/datastreams'); - } - elseif ($edit_count == 1) { - // One registry implementation, go there - drupal_goto($edit_registry[0]['url']); - } - else { - // Multiple edit routes registered - return islandora_edit_datastream_registry_render($edit_registry); - } -} - -// @TODO: theme / preprocess -function islandora_edit_datastream_registry_render($edit_registry) { - $output = array( + return array( '#type' => 'markup', - '#markup' => '', + '#markup' => $markup, ); - foreach ($edit_registry AS $edit_route) { - $output['#markup'] .= l($edit_route['name'], $edit_route['url']) . '
'; - } - return $output; } diff --git a/includes/delete_datastream.form.inc b/includes/delete_datastream.form.inc new file mode 100644 index 00000000..9c3cd368 --- /dev/null +++ b/includes/delete_datastream.form.inc @@ -0,0 +1,66 @@ + $datastream->id)), + "islandora/object/{$datastream->parent->id}", + t('This action cannot be undone.'), + t('Delete'), + t('Cancel') + ); +} + +/** + * Submit handler for the delete datastream form. Purges/Delete's the given + * FedoraDatastream if possible. + * + * The ISLANDORA_PRE_PURGE_DATASTREAM_HOOK will query other modules as to + * whether the given FedoraDatastream + * should be: blocked from purging; state set to 'Deleted'; or purged. + * + * @see islandora_delete_datastream(). + * + * @param string $object_id + * ID of the object + * @param string $datastream_id + * ID of the datastream + */ +function islandora_delete_datastream_form_submit(array $form, array &$form_state) { + $datastream = $form_state['datastream']; + $datastream_id = $datastream->id; + $object = $datastream->parent; + $deleted = FALSE; + try { + $deleted = islandora_delete_datastream($datastream); + } catch (Exception $e) { + drupal_set_message(t('Error deleting %s datastream from object %o %e', array('%s' => $datastream_id, '%o' => $object->label, '%e' => $e->getMessage())), 'error'); + } + if ($deleted) { + drupal_set_message(t('%d datastream sucessfully deleted from Islandora object %o', array('%d' => $datastream_id, '%o' => $object->label))); + } + else { + drupal_set_message(t('Error deleting %s datastream from object %o', array('%s' => $datastream_id, '%o' => $object->label)), 'error'); + } + $form_state['redirect'] = "islandora/object/{$object->id}"; +} diff --git a/includes/delete_object.form.inc b/includes/delete_object.form.inc new file mode 100644 index 00000000..07cc2c21 --- /dev/null +++ b/includes/delete_object.form.inc @@ -0,0 +1,50 @@ + $object->label)), + "islandora/object/$object->id", + t('This action cannot be undone.'), + t('Delete'), + t('Cancel') + ); +} + +/** + * Delete's the object in questionGives deloption of deleting or purging and object. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +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); + $form_state['redirect'] = isset($parent) ? "islandora/object/{$parent->id}" : 'islandora'; + islandora_delete_object($object); +} diff --git a/includes/ingest-menu.inc b/includes/ingest-menu.inc deleted file mode 100644 index 5e7d9436..00000000 --- a/includes/ingest-menu.inc +++ /dev/null @@ -1,47 +0,0 @@ -label))); - drupal_goto('islandora/object/' . $collection_object->id); - } - elseif ($registry_count == 1) { - // One registry implementation, go there - drupal_goto($ingest_registry[0]['url']); - } - else { - // Multiple ingest routes registered - return islandora_ingest_registry_render($ingest_registry); - } -} - -// @TODO: theme -function islandora_ingest_registry_render($ingest_registry) { - $output = array( - '#type' => 'markup', - '#markup' => '', - ); - foreach ($ingest_registry AS $ingest_route) { - $output['#markup'] .= l($ingest_route['name'], $ingest_route['url']) . '
'; - } - return $output; -} \ No newline at end of file diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc new file mode 100644 index 00000000..ad4fc308 --- /dev/null +++ b/includes/ingest.form.inc @@ -0,0 +1,428 @@ + 'isMemberOfCollection', 'pid' => $o); }; + $relationships = empty($configuration['collections']) ? array() : array_map($relationship_map, $configuration['collections']); + $object = islandora_prepare_new_object($namespace, $label, array(), array(), $relationships); + $form_state['islandora'] = array( + 'step' => 0, + 'steps' => islandora_ingest_get_steps($configuration), + 'objects' => array($object), + 'configuration' => $configuration + ); + } +} + +/** + * Executes the current step, building the form definition and appending on any + * additonal elements required for the step to function. + * + * @param array $form + * The drupal form. + * @param array $form_state + * The drupal form state. + * + * @return array + * The form definition of the current step. + */ +function islandora_ingest_form_execute_step(array $form, array &$form_state) { + $step_info = islandora_ingest_form_get_step_info($form_state); + switch ($step_info['type']) { + case 'form': + $args = array($form, &$form_state); + $args = isset($step_info['args']) ? array_merge($args, $step_info['args']) : $args; + $form = call_user_func_array($step_info['form_id'], $args); + return islandora_ingest_form_stepify($form, $form_state, $step_info); + case 'batch': + // @todo Implement if possible. + break; + } + return array(); +} + +/** + * Append Prev/Next buttons submit/validation handlers etc. + * + * @param array $form + * The drupal form. + * @param array $form_state + * The drupal form state. + * @param array $step_info + * The info for building the current form step. + * + * @return array + * The stepified drupal form definition for the given step. + */ +function islandora_ingest_form_stepify(array $form, array &$form_state, array $step_info) { + $step = islandora_ingest_form_get_step($form_state); + $first_step = $step > 0; + $last_step = $step == (islandora_ingest_form_get_step_count($form_state) - 1); + $form['prev'] = $first_step ? islandora_ingest_form_previous_button() : NULL; + $form['next'] = $last_step ? islandora_ingest_form_ingest_button($step_info) : islandora_ingest_form_next_button($step_info); + return $form; +} + +/** + * Defines the previous button for the ingest form. + * + * @return array + * The previous button for the ingest form. + */ +function islandora_ingest_form_previous_button() { + return array( + '#type' => 'submit', + '#value' => t('Previous'), + '#name' => 'prev', + '#submit' => array('islandora_ingest_form_previous_submit'), + // #limit_validation_errors, is why when the previous button is pressed no + // values persisted in the form_state, but its also what allows us to go + // back when validation errors occur. To have a better solution going + // forward we can either limit validation only on required fields, or we can + // convert all required fields to use #element_validation functions, and + // Remove the need for #limit_validation_errors. Or maybe there is some + // other solution, regardless of what it is, it won't be standard. + '#limit_validation_errors' => array() + ); +} + +/** + * The submit handler for the ingest form previous button. + * + * Stores the current form steps values in the form storage. + * Moves the focus of the multi-page ingest form back one step. + * Restores the form values for the previous step. + * + * @param array $form + * The drupal form. + * @param array $form_state + * The drupal form state. + */ +function islandora_ingest_form_previous_submit(array $form, array &$form_state) { + $step = &islandora_ingest_form_get_step($form_state); + $step_info = &islandora_ingest_form_get_step_info($form_state, $step); + $step_info['values'] = $form_state['values']; + $step--; + $step_info = &islandora_ingest_form_get_step_info($form_state, $step); + $form_state['values'] = isset($step_info['values']) ? $step_info['values'] : NULL; + $form_state['rebuild'] = TRUE; +} + +/** + * Defines the next button for the ingest form. + * + * Adds submit/validate handlers for the form step if they exist. + * + * @return array + * The next button for the ingest form. + */ +function islandora_ingest_form_next_button(array $step_info) { + $form_id = $step_info['form_id']; + $validate_callback = $form_id . '_validate'; + $validate = function_exists($validate_callback) ? array($validate_callback) : NULL; + $submit_callback = $form_id . '_submit'; + $submit = function_exists($submit_callback) ? array($submit_callback, 'islandora_ingest_form_next_submit') : array('islandora_ingest_form_next_submit'); + return array( + '#type' => 'submit', + '#value' => t('Next'), + '#name' => 'next', + '#validate' => $validate, + '#submit' => $submit + ); +} + +/** + * The submit handler for the ingest form next button. + * + * Stores the current form steps values in the form storage. + * Moves the focus of the multi-page ingest form forward one step. + * Restores the form values for the next step if present. + * + * @param array $form + * The drupal form. + * @param array $form_state + * The drupal form state. + */ +function islandora_ingest_form_next_submit(array $form, array &$form_state) { + $step = &islandora_ingest_form_get_step($form_state); + $step_info = &islandora_ingest_form_get_step_info($form_state, $step); + $step_info['values'] = $form_state['values']; + $step++; + $step_info = &islandora_ingest_form_get_step_info($form_state, $step); + $form_state['values'] = isset($step_info['values']) ? $step_info['values'] : array(); + $form_state['rebuild'] = TRUE; +} + +/** + * Defines the ingest button for the ingest form. + * + * This button is only shown on the last page of the multi-page ingest form. + * + * @return array + * The ingest button for the ingest form. + */ +function islandora_ingest_form_ingest_button(array $step_info) { + $form_id = $step_info['form_id']; + $validate_callback = $form_id . '_validate'; + $validate = function_exists($validate_callback) ? array($validate_callback) : NULL; + $submit_callback = $form_id . '_submit'; + $submit = function_exists($submit_callback) ? array($submit_callback, 'islandora_ingest_form_submit') : array('islandora_ingest_form_submit'); + return array( + '#type' => 'submit', + '#name' => 'ingest', + '#value' => t('Ingest'), + '#validate' => $validate, + '#submit' => $submit + ); +} + +/** + * The submit handler for the ingest form. + * + * Attempts to ingest every object built by the previous steps. + * + * @param array $form + * The drupal form. + * @param array $form_state + * The drupal form state. + */ +function islandora_ingest_form_submit(array $form, array &$form_state) { + foreach ($form_state['islandora']['objects'] as $object) { + try { + islandora_add_object($object); + $form_state['redirect'] = "islandora/object/{$object->id}"; + } catch (Exception $e) { + // If post hooks throws it may already exist at this point but may be invalid, so don't say failed :P + watchdog('islandora', $e->getMessage(), NULL, WATCHDOG_ERROR); + drupal_set_message(t('A problem occured while ingesting "@label" (ID: @pid), please notifiy the administrator.', array('@label' => $object->label, '@pid' => $object->id)), 'error'); + } + } +} + +/** + * Gets the configuration used to create the multi-page ingest form. + * + * @param array $form_state + * The drupal form state. + * + * @return array + * The configuration used to generate the multi-page ingest forms. + */ +function islandora_ingest_form_get_configuration(array $form_state) { + return $form_state['islandora']['configuration']; +} + +/** + * Gets a reference to the stored NewFedoraObject's which are to be ingested + * when the final step submits. + * + * @param array $form_state + * The drupal form state. + * + * @return array + * A reference to the stored NewFedoraObjects to be ingested when the final + * step submits. + */ +function &islandora_ingest_form_get_objects(array $form_state) { + return $form_state['islandora']['objects']; +} + +/** + * Gets a single object from the stored NewFedoraObject's. + * + * @note - In our current use case we are only dealing with a single object + * ingest, this makes it convenient to access it. Ideally the steps + * implementations will be abstracted to be indifferent to what object it's + * currently working on. This will act as a placeholder for such + * functionality. + * + * @param array $form_state + * The drupal form state. + * + * @return array + * Returns the 'current' object in the array of NewFedoraObjects, generally + * this is only used when there is one object in the list of objects. + */ +function islandora_ingest_form_get_object(array $form_state) { + $objects = &islandora_ingest_form_get_objects($form_state); + return current($objects); +} + +/** + * Get a reference to the current step index. + * + * @param array $form_state + * The drupal form state. + * + * @return int + * The current step index. + */ +function &islandora_ingest_form_get_step(array &$form_state) { + return $form_state['islandora']['step']; +} + +/** + * Get a reference to the step info of the given step or the current step if + * none is given. + * + * @param array $form_state + * The drupal form state. + * @param int $step + * The index of the step to get. + * + * @return integer + * The step info of the requested step if found, NULL otherwise. + */ +function &islandora_ingest_form_get_step_info(array &$form_state, $step = NULL) { + $step = isset($step) ? $step : islandora_ingest_form_get_step($form_state); + $steps = &islandora_ingest_form_get_steps($form_state); + if (!empty($steps[$step])) { + return $steps[$step]; + } + // @todo deal with unknown case. + return NULL; +} + +/** + * Get a reference to the steps stored in the form state. + * + * @param array $form_state + * The drupal form state. + * + * @return array + * All the steps to be used in the ingest process. + */ +function &islandora_ingest_form_get_steps(array &$form_state) { + return $form_state['islandora']['steps']; +} + +/** + * Call form_load_include, for the current step if it defines a required file. + * + * @param array $form_state + * The drupal form state. + */ +function islandora_ingest_form_step_form_load_include(array &$form_state) { + form_load_include($form_state, 'inc', 'islandora', 'includes/ingest.form'); + $step_info = islandora_ingest_form_get_step_info($form_state); + // Load include files + if (isset($step_info['file']) && isset($step_info['module'])) { + $matches = array(); + preg_match('/^(.*)\.(.*)$/', $step_info['file'], $matches); + list($file, $name, $type) = $matches; + form_load_include($form_state, $type, $step_info['module'], $name); + } +} + +/** + * Get the number of steps. + * + * @param array $form_state + * The drupal form state. + * + * @return int + * The number of steps. + */ +function islandora_ingest_form_get_step_count(array $form_state) { + $steps = islandora_ingest_form_get_steps($form_state); + return count($steps); +} + +/** + * Buildes the initial list of ingest steps. + * + * Sorted by weight expected range between -50 to 50. + * + * The sort order is undefined for steps which have the same weight. + * + * @param array $configuration + * The configuration options used to build the multi-paged ingest process. + * + * @return array + * The initial list of sorted ingest steps as defined by all implementers + * of ISLANDORA_INGEST_STEP_HOOK. + */ +function islandora_ingest_get_steps(array $configuration) { + module_load_include('inc', 'islandora', 'includes/utilities'); + $steps = array(); + $models = isset($configuration['models']) ? $configuration['models'] : array(); + foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $models) as $hook) { + $steps = array_merge($steps, module_invoke_all($hook, $configuration)); + } + // Remove NULL values. + $steps = array_filter($steps); + usort($steps, 'drupal_sort_weight'); + return $steps; +} diff --git a/includes/ingest.menu.inc b/includes/ingest.menu.inc new file mode 100644 index 00000000..ac551014 --- /dev/null +++ b/includes/ingest.menu.inc @@ -0,0 +1,66 @@ +'; + // Redirect back to referer or top level collection. + drupal_goto($redirect); + } + module_load_include('inc', 'islandora', 'includes/ingest.form'); + return drupal_get_form('islandora_ingest_form', $configuration); +} + +/** + * Fetches/validates the ingest configuration from the $_GET parameters. + * + * Generic parameters as accepted by all ingest processes, other modules may + * add to this list. + * id -> The pid of the object to create. optional. + * models -> Comma delimited list of all the content models the created object + * should have. + * collections -> Comma delimited list of all the collections the created + * object should belong to. + * + * @return array + * The configuration options used to build the multi-paged ingest process. + */ +function islandora_ingest_get_configuration() { + $configuration = $_GET; + unset($configuration['q']); + $convert_to_array_keys = array_intersect(array('models', 'collections'), array_keys($configuration)); + foreach ($convert_to_array_keys as $key) { + $configuration[$key] = explode(',', $configuration[$key]); + } + // @todo add hook for manipulating/validating the configuration. + return islandora_valid_ingest_configuration($configuration) ? $configuration : FALSE; +} + +/** + * Validates the given ingest configuration. + * + * At the moment it requires that models and collections are present. + * + * @param array $configuration + * The key value pairs that are used to build the multi-paged ingest process. + * + * @return boolean + * TRUE if the configuration is valid, FALSE otherwise. + */ +function islandora_valid_ingest_configuration(array $configuration) { + // @todo Add more robust validation, add watchdog logs, etc. + return isset($configuration['models']) && isset($configuration['collections']); +} diff --git a/includes/islandora.ingest.inc b/includes/islandora.ingest.inc deleted file mode 100644 index e7356133..00000000 --- a/includes/islandora.ingest.inc +++ /dev/null @@ -1,237 +0,0 @@ -models; - $collection_info = module_invoke_all('islandora_ingest_get_information', $models, $collection_object); - - return $collection_info; -} - -/** - * Get an ingestable object. - * - * @deprecated - * Deprecated in favour of the more flexible - * islandora_ingest_new_object_prepare()--which this function has been made - * to call behind the scenes anyway. - * - * @param array $content_models - * An array of content models to which the new object should subscribe, where - * each content model is described by an associative array containing: - * - pid: The Fedora PID of the content model. - * @param string $collection_pid - * The collection to which the new object should belong. - * @param string $relationship - * The relationship this object will have to the collection. - * @param string $namespace - * The namespace in which the PID for the new object will be created. - * - * @return NewFedoraObject - * A NewFedoraObject which may be adjusted before ingesting. - */ -function islandora_ingest_get_object($content_models, $collection_pid, $relationship, $namespace) { - $models = array(); - foreach ($content_models as $relation) { - $models[] = $relation['pid']; - } - - return islandora_ingest_new_object_prepare($namespace, NULL, array(), $models, array( - array( - 'pid' => $collection_pid, - 'relationship' => $relationship, - ), - ), $collection_pid); -} - -/** - * 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_ingest_new_object_prepare($namespace = NULL, $label = NULL, $datastreams = array(), $content_models = array(), $relationships = array(), $collection_pid = NULL) { - // include Tuque library - module_load_include('inc', 'islandora', 'includes/tuque'); - global $user; - // new connection - try { - $connection = new IslandoraTuque($user); - } catch (Exception $e) { - drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error'); - return; - } - // construct new object - $object = $connection->repository->constructObject($namespace); - - // add label - if (!empty($label)) { - $object->label = $label; - } - // add content model relationship(s) - foreach ($content_models as $content_model) { - $object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $content_model); - } - // add collection relationship(s) - if (!empty($relationships)) { - foreach ($relationships as $relationship) { - $object->relationships->add(FEDORA_RELS_EXT_URI, $relationship['relationship'], $relationship['pid']); - } - } - // add datastreams - foreach ((array) $datastreams as $ds) { - // variables - $ds_id = $ds['dsid']; - $ds_label = isset($ds['label']) ? $ds['label'] : ''; - $ds_mimetype = isset($ds['mimetype']) ? $ds['mimetype'] : 'text/xml'; - $ds_control_group = (isset($ds['control_group']) AND in_array($ds['control_group'], array('X', 'M', 'R', 'E'))) ? $ds['control_group'] : 'M'; - $ds_datastream_file = url($ds['datastream_file'], array('absolute' => TRUE)); - - // datastream object - $datastream = $object->constructDatastream($ds_id, $ds_control_group); - $datastream->label = $ds_label; - $datastream->mimetype = $ds_mimetype; - switch ($ds_control_group) { - case 'M': - $datastream->setContentFromUrl($ds_datastream_file); - break; - case 'X': - $datastream->setContentFromString(file_get_contents($ds_datastream_file)); - break; - } - $object->ingestDatastream($datastream); - } - - module_load_include('inc', 'islandora', 'includes/utilities'); - foreach (islandora_build_hook_list('islandora_ingest_pre_ingest', $content_models) as $hook) { - module_invoke_all($hook, $object, $content_models, $collection_pid); - } - - return $object; -} - -/** - * Ingest the given object into Fedora. - * - * @param NewFedoraObject $object - * An ingestable FedoraObject. - * - * @return FedoraObject - * The ingested FedoraObject, after running the post ingest hooks. - */ -function islandora_ingest_add_object(&$object) { - drupal_alter('islandora_pre_ingest', $object); - - $object->repository->ingestObject($object); - - module_load_include('inc', 'islandora', 'includes/utilities'); - - foreach (islandora_build_hook_list(ISLANDORA_POST_INGEST_HOOK, $object->models) as $hook) { - module_invoke_all($hook, $object); - } - - return $object; -} - -/** - * Ingest an object. - * - * @param array $object_model - * An associative array containing the necessary parameters to create the - * desired object: - * - pid: The PID with which the object will be created. - * - label: An optional label to apply to the object. - * - datastreams: Same as the "datastreams" array accepted by - * islandora_ingest_new_object_prepare(). - * - cmodel: Either an array of content models as accepted by - * islandora_ingest_new_object_prepare(), or a single content model PID to add - * to the object. - * - parent: Either an array of parents, or a single parent PID to which to - * relate to; uses isMemberOfCollection by default. - * - relationships: An array of relationships as accepted by - * islandora_ingest_new_object_prepare(). - * - * @return FedoraObject - * An FedoraObject which has been ingested into Fedora. - */ -function islandora_ingest_new_object($object_model) { - // prepare variables - // namespace - $namespace = $object_model['pid']; - // label - $label = !empty($object_model['label']) ? $object_model['label'] : NULL; - // datastreams - $datastreams = array(); - if (!empty($object_model['datastreams']) AND is_array($object_model['datastreams'])) { - $datastreams = $object_model['datastreams']; - } - // content models - $content_models = array(); - if (!empty($object_model['cmodel'])) { - if (is_array($object_model['cmodel'])) { - $content_models = $object_model['cmodel']; - } - else { - $content_models[] = $object_model['cmodel']; - } - } - // relationships - $relationships = array(); - // single parent - if (!empty($object_model['parent']) AND !is_array($object_model['parent'])) { - $relationships[] = array('relationship' => 'isMemberOfCollection', 'pid' => $object_model['parent']); - } - // parents array - if (!empty($object_model['parents']) AND is_array($object_model['parents'])) { - foreach ($object_model['parents'] as $parent) { - $relationships[] = array('relationship' => 'isMemberOfCollection', 'pid' => $parent); - } - } - // other relationships - if (!empty($object_model['relationships']) AND is_array($object_model['relationships'])) { - foreach ($object_model['relationships'] as $relationship) { - $relationships[] = array('relationship' => $relationship['relationship'], 'pid' => $relationship['pid']); - } - } - - // build new object - $object = islandora_ingest_new_object_prepare($namespace, $label, $datastreams, $content_models, $relationships); - - // ingest (and return) new object - return islandora_ingest_add_object($object); -} - - - - - diff --git a/includes/object_properties.form.inc b/includes/object_properties.form.inc new file mode 100644 index 00000000..4cafd36c --- /dev/null +++ b/includes/object_properties.form.inc @@ -0,0 +1,120 @@ +label); + $form_state['object'] = $object; + return array( + 'pid' => array( + '#type' => 'hidden', + '#value' => $object->id + ), + 'object_label' => array( + '#title' => t('Item Label'), + '#default_value' => $object->label, + '#required' => 'TRUE', + '#description' => t('A Human readable label'), + // Double the normal length + '#size' => 120, + // Max length for a Fedora Label + '#maxlength' => 255, + '#type' => 'textfield' + ), + // @todo Make this into an autocomplete field that list the users in the + // system as well. + 'object_owner' => array( + '#title' => t('Owner'), + '#default_value' => $object->owner, + '#required' => FALSE, + '#description' => t('The owner id'), + '#type' => 'textfield' + ), + 'object_state' => array( + '#title' => t('State'), + '#default_value' => $object->state, + '#required' => TRUE, + '#description' => t('The items state one of active, inactive or deleted'), + '#type' => 'select', + '#options' => array('A' => 'Active', 'I' => 'Inactive', 'D' => 'Deleted') + ), + 'submit' => array( + '#type' => 'submit', + '#value' => 'Update Properties' + ), + 'delete' => array( + '#type' => 'submit', + '#value' => t('Delete'), + '#submit' => array('islandora_object_properties_form_delete'), + '#limit_validation_errors' => array(array('pid')) + ) + ); +} + +/** + * Submit handler for object properties admin form. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_object_properties_form_submit(array $form, array &$form_state) { + $object = $form_state['object']; + $owner = $form_state['values']['object_owner']; + $state = $form_state['values']['object_state']; + $label = $form_state['values']['object_label']; + if (isset($owner) && $owner != $object->owner) { + try { + $object->owner = $owner; + drupal_set_message(t('Successfully updated owner %s', array('%s' => $owner))); + } catch (Exception $e) { + form_set_error('object_owner', t('Error updating owner %s', array('%s' => $e->getMessage()))); + } + } + if (isset($state) && $state != $object->state) { + try { + $object->state = $state; + drupal_set_message(t('Successfully updated state %s', array('%s' => $state))); + } catch (Exception $e) { + form_set_error('object_state', t('Error updating state %s', array('%s' => $e->getMessage()))); + } + } + if (isset($label) && $label != $object->label) { + try { + $object->label = $label; + drupal_set_message(t('Successfully updated label %s', array('%s' => check_plain($label)))); + } catch (Exception $e) { + form_set_error(t('Error updating label %s', array('%s' => $e->getMessage()))); + } + } +} + +/** + * Callback function for object properties admin form delete button. + * + * @param array $form + * The Drupal form. + * @param array $form_state + * The Drupal form state. + */ +function islandora_object_properties_form_delete(array $form, array &$form_state) { + drupal_goto("islandora/object/{$form_state['values']['pid']}/delete"); +} diff --git a/includes/object_properties.inc b/includes/object_properties.inc deleted file mode 100644 index d4f7eeca..00000000 --- a/includes/object_properties.inc +++ /dev/null @@ -1,125 +0,0 @@ -owner) { - try { - $islandora_object->owner = $owner; - drupal_set_message(t('Successfully updated owner %s', array('%s' => $owner))); - } catch (Exception $e) { - form_set_error('object_owner', t('Error updating owner %s', array('%s' => $e->getMessage()))); - } - } - if (isset($state) && $state != $islandora_object->state) { - try { - $islandora_object->state = $state; - drupal_set_message(t('Successfully updated state %s', array('%s' => $state))); - } catch (Exception $e) { - form_set_error('object_state', t('Error updating state %s', array('%s' => $e->getMessage()))); - } - } - if (isset($label) && $label != $islandora_object->label) { - try { - $islandora_object->label = $label; - drupal_set_message(t('Successfully updated label %s', array('%s' => check_plain($label)))); - } catch (Exception $e) { - form_set_error(t('Error updating label %s', array('%s' => $e->getMessage()))); - } - } -} - -/** - * Callback function for object properties admin form delete button. - */ -function islandora_edit_properties_form_delete($form, &$form_state) { - $islandora_object = $form_state['values']['pid']; - drupal_goto("islandora/object/$islandora_object/delete"); -} - -/** - * Object properties admin form. - * - * @param array $form - * @param array $form_state - * @param string $object_id - * an object id - * @return array - */ -function islandora_edit_properties_form($form, &$form_state, $object) { - $form = array(); - if (!isset($object)) { - return NULL; - } - drupal_set_title($object->label); - $form['pid'] = array( - '#type' => 'hidden', - '#value' => $object->id, - ); - - $form['object_label'] = array( - '#title' => t('Item Label'), - '#default_value' => $object->label, - '#required' => 'TRUE', - '#description' => t('A Human readable label'), - '#type' => 'textfield' - ); - $form['object_owner'] = array( - '#title' => t('Owner'), - '#default_value' => $object->owner, - '#required' => FALSE, - '#description' => t('The owner id'), - '#type' => 'textfield', - ); - $form['object_state'] = array( - '#title' => t('State'), - '#default_value' => $object->state, - '#required' => TRUE, - '#description' => t('The items state one of active, inactive or deleted'), - '#type' => 'select', - '#options' => array('A' => 'Active', 'I' => 'Inactive', 'D' => 'Deleted'), - ); - $form['submit'] = array( - '#type' => 'submit', - '#value' => 'Update Properties', - ); - $form['delete'] = array( - '#type' => 'submit', - '#value' => t('Delete'), - '#submit' => array('islandora_edit_properties_form_delete'), - '#limit_validation_errors' => array(array('pid')), - ); - return $form; -} diff --git a/includes/purge.form.inc b/includes/purge.form.inc deleted file mode 100644 index 32517933..00000000 --- a/includes/purge.form.inc +++ /dev/null @@ -1,138 +0,0 @@ - TRUE. - * Once the object has been deleted/purged then a second call lets the solution packs know that - * the object has been dealt with. In this call the object id and content models are sent out so - * that the solution packs can act on this news. There is no guarantee that the object still exists - * and so the object object isn't sent. - * - * @param string $object_id - * ID of the object - * @return type - */ -function islandora_purge_object_submit($form, &$form_state) { - - $object_id = $form_state['values']['pid']; - $collection = $form_state['values']['col']; - - // purge object - islandora_object_purge($object_id); - - drupal_goto($collection); -} - -function islandora_purge_object($form, &$form_state, $object) { - module_load_include('inc', 'islandora', 'includes/datastream'); - - $parent = islandora_datastream_get_parents($object); - $key = array_keys($parent); - - if (count($key) > 0) { - $redirect = "islandora/object/$key[0]"; - } - else { - $redirect = "islandora"; - } - - $form['pid'] = array('#type' => 'value', '#value' => $object->id); - $form['col'] = array('#type' => 'value', '#value' => $redirect); - - return confirm_form($form, - t('Are you sure you want to delete %title?', array('%title' => $object->label)), - "islandora/object/$object->id", - t('This action cannot be undone.'), - t('Delete'), - t('Cancel') - ); -} - -function islandora_purge_datastream($form, &$form_state, $object, $datastream_id) { - module_load_include('inc', 'islandora', 'includes/datastream'); - - $datastream = $object->getDatastream($datastream_id); - - $redirect = "islandora/object/$object->id"; - - $form['pid'] = array('#type' => 'value', '#value' => $object->id); - $form['dsid'] = array('#type' => 'value', '#value' => $datastream_id); - $form['col'] = array('#type' => 'value', '#value' => $redirect); - - return confirm_form($form, - t('Are you sure you want to delete the %dsid datastream?', array('%dsid' => $datastream->id)), - "islandora/object/$object->id", - t('This action cannot be undone.'), - t('Delete'), - t('Cancel') - ); -} - -/** - * Gives the option of purging or deleting a datastream. - * - * The default behaviour is to purge the datastream but this can be overridden using the - * 'islandora_pre_purge_datastream' hook. 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 string $object_id - * ID of the object - * @param string $datastream_id - * ID of the datastream - * - */ -function islandora_purge_datastream_submit($form, &$form_state) { - $object_id = $form_state['values']['pid']; - $datastream_id = $form_state['values']['dsid']; - - if (!isset($datastream_id)) { - drupal_set_message(t('Cannot remove datastream, datastream id not set')); - return; - } - - $object = islandora_object_load($object_id); - - if (!isset($object)) { - drupal_set_message(t('Could not remove object, object not found')); - return; - } - - //notify modules of pending deletion so we can update rels etc - $arr = module_invoke_all('islandora_pre_purge_datastream', $object[$datastream_id]); - - if (isset($arr['block']) && $arr['block']) { - drupal_set_message(t('Purging of the %d datastream was blocked', array('%d' => $datastream_id)), 'warning'); - return; - } - if (isset($arr['delete']) && $arr['delete']) { - try { - $object[$datastream_id]->state = 'D'; - } catch (Exception $e) { - drupal_set_message(t('Error deleting %s datastream from Islandora object %o %e', array('%s' => $datastream_id, '%o' => $object->id, '%e' => $e)), 'error'); - return; - } - } - else { - try { - $object->purgeDatastream($datastream_id); - } catch (Exception $e) { - drupal_set_message(t('Error purging %s datastream from Islandora object %o %e', array('%s' => $datastream_id, '%o' => $object_id, '%e' => $e)), 'error'); - return; - } - } - //notify modules post deletion - module_invoke_all('islandora_post_purge_datastream', $object, $datastream_id); - drupal_set_message(t('%d datastream sucessfully purged from Islandora object %o', array('%d' => $datastream_id, '%o' => $object->label))); - drupal_goto('islandora/object/' . $object->id); -} diff --git a/includes/solution_packs.inc b/includes/solution_packs.inc index ffc8d31f..8c8cb3e0 100644 --- a/includes/solution_packs.inc +++ b/includes/solution_packs.inc @@ -2,29 +2,25 @@ /** * @file - * This file contains all admin and callback functions for solution pack management. + * + * This file contains all admin and callback functions for solution pack + * management. */ /** - * Solution pack admin page callback + * Solution pack admin page callback. */ function islandora_solution_packs_admin() { - // add css - drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css'); - // check connection module_load_include('inc', 'islandora', 'includes/utilities'); - $url = variable_get('islandora_base_url', 'http://localhost:8080/fedora'); - $info = islandora_describe_repository($url); - if (!$info) { - $config_url = url('admin/islandora/configure'); - drupal_set_message(t('Could not connect to the repository. Please check the settings on the Islandora configuration page.', array('@config_url' => $config_url)), 'error'); + drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css'); + if (!islandora_describe_repository()) { + $message = t('Could not connect to the repository. Please check the settings on the ' . + 'Islandora configuration page.', + array('@config_url' => url('admin/islandora/configure'))); + drupal_set_message($message, 'error'); } - - // set variables $enabled_solution_packs = module_invoke_all('islandora_required_objects'); - $output = ''; - foreach ($enabled_solution_packs as $solution_pack_module => $solution_pack_info) { $objects = array(); foreach ($solution_pack_info as $field => $value) { @@ -37,12 +33,9 @@ function islandora_solution_packs_admin() { break; } } - // get form $form_array = drupal_get_form('islandora_solution_pack_form_' . $solution_pack_module, $solution_pack_module, $solution_pack_name, $objects); - // render form $output .= drupal_render($form_array); } - return $output; } @@ -50,10 +43,7 @@ function islandora_solution_packs_admin() { * Solution pack admin page */ function islandora_solution_pack_form($form, &$form_state, $solution_pack_module, $solution_pack_name, $objects = array()) { - - // set variables global $base_url; - global $base_path; $needs_update = FALSE; $needs_install = FALSE; $could_not_connect = FALSE; @@ -80,25 +70,15 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul '#value' => $objects, ); - // table - // header $table_header = array(t('Label'), t('PID'), t('Status')); $table_rows = array(); - // loop over defined objects foreach ($objects as $object) { $datastreams = NULL; if (isset($object['pid'])) { - // set variables $pid = $object['pid']; - - // table row $table_row = array(); - - // check object status $object_status = islandora_check_object_status($object); - - // set status labels switch ($object_status) { case 'up_to_date': $object_status = t('Up-to-date'); @@ -120,8 +100,6 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul $could_not_connect = TRUE; break; } - - // label if ($needs_install OR $could_not_connect) { $label = $object['label'] ? $object['label'] : ''; } @@ -129,11 +107,8 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul $label = $object['label'] ? l($object['label'], $base_url . '/islandora/object/' . $pid) : ''; } $table_row[] = $label; - // pid $table_row[] = $pid; - // object status $table_row[] = $object_status; - // add row $table_rows[] = $table_row; } } @@ -146,7 +121,6 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul '#suffix' => '', ); - // install status $form['solution_pack']['install_status'] = array( '#markup' => '' . t('Object status:') . ' ', '#prefix' => '
', @@ -169,14 +143,12 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul $submit_button_text = ''; } - // table $form['solution_pack']['table'] = array( '#type' => 'item', '#markup' => theme('table', array('header' => $table_header, 'rows' => $table_rows)), ); } - // submit if (!$could_not_connect) { $form['solution_pack']['submit'] = array( '#value' => $submit_button_text, @@ -185,12 +157,8 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul '#attributes' => array('class' => array('islandora-solution-pack-submit')), '#weight' => 40, ); - // submit callback - $form['solution_pack']['#submit'] = array( - 'islandora_solution_pack_form_submit', - ); + $form['solution_pack']['#submit'] = array('islandora_solution_pack_form_submit'); } - return $form; } @@ -203,8 +171,6 @@ function islandora_solution_pack_form($form, &$form_state, $solution_pack_modul * The state of the form submited. */ function islandora_solution_pack_form_submit($form, &$form_state) { - - // get variables $solution_pack_module = $form_state['values']['solution_pack_module']; $solution_pack_name = $form_state['values']['solution_pack_name']; $objects = $form_state['values']['objects']; @@ -228,22 +194,16 @@ function islandora_solution_pack_form_submit($form, &$form_state) { } - - - /** * Batch reingest object(s) * - * @param type $object + * @param array $object * @param type $context * @return type */ function islandora_batch_reingest_object($object_model, &$context) { - module_load_include('inc', 'islandora', 'includes/utilities'); - module_load_include('inc', 'islandora', 'includes/islandora.ingest'); - // include Tuque library - module_load_include('inc', 'islandora', 'includes/tuque'); + global $user; global $base_url; // new connection @@ -256,9 +216,8 @@ function islandora_batch_reingest_object($object_model, &$context) { } if (!empty($object_model) && is_array($object_model)) { - // set and validate PID $pid = $object_model['pid']; - if (!islandora_validate_pid($pid)) { + if (!islandora_is_valid_pid($pid)) { return NULL; } @@ -267,13 +226,16 @@ function islandora_batch_reingest_object($object_model, &$context) { $object_query = $connection->api->a->findObjects('query', 'pid=' . $pid); $reinstall = FALSE; if (!empty($object_query['results'])) { - islandora_object_purge($pid); + $object = islandora_object_load($pid); + if (isset($object)) { + islandora_delete_object($object); + } $reinstall = TRUE; } // build and ingest new object try { - $object = islandora_ingest_new_object($object_model); + $object = islandora_solution_pack_add_object($object_model); $object_name = $object->label; if ($reinstall) { drupal_set_message(t('Successfully reinstalled @object_name.', array('@object_name' => $object_name, '@pid' => $pid))); @@ -297,11 +259,7 @@ function islandora_batch_reingest_object($object_model, &$context) { function islandora_install_solution_pack($module_name = NULL, $op = 'install') { // check if a module name is given. // @TODO: check module name for existance if (!empty($module_name)) { - - // include files - module_load_include('inc', 'islandora', 'includes/tuque'); module_load_include('module', 'islandora', 'islandora'); - module_load_include('inc', 'islandora', 'includes/islandora.ingest'); module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('module', $module_name, $module_name); @@ -381,9 +339,7 @@ function islandora_install_solution_pack($module_name = NULL, $op = 'install') { } } else { - // build and ingest new object - islandora_ingest_new_object($object); - // set message + islandora_solution_pack_add_object($object); drupal_set_message(st('@module_label: installed @label object.', array('@module_label' => $module_label, '@label' => $label, '@pid' => $pid, '@object_url' => $object_url))); } break; @@ -414,7 +370,8 @@ function islandora_install_solution_pack($module_name = NULL, $op = 'install') { * * @see islandora_solution_pack_form() * @see islandora_install_solution_pack() - * @TODO: should this function live in islandora.module so it can be called easier without having to include the solution_packs.inc file? + * @todo: Should this function live in islandora.module so it can be called + * easier without having to include the solution_packs.inc file? */ function islandora_check_object_status($object_model = array()) { if (!empty($object_model)) { @@ -441,7 +398,8 @@ function islandora_check_object_status($object_model = array()) { $object_status = 'missing'; } else { - // object defined with single datastream file // @TODO: should dsversion be mandatory for the check to valid? + // object defined with single datastream file + // @TODO: should dsversion be mandatory for the check to valid? if (isset($object_model['dsid']) && isset($object_model['datastream_file']) && isset($object_model['dsversion'])) { $datastreams = array( array( @@ -485,6 +443,88 @@ function islandora_check_object_status($object_model = array()) { } } +/** + * Converts the given definition into an object and add's it to the repository. + * + * @param array $object_definition + * An associative array containing the necessary parameters to create the + * desired object: + * - pid: The PID with which the object will be created. + * - label: An optional label to apply to the object. + * - datastreams: Same as the "datastreams" array accepted by + * islandora_prepare_new_object(). + * - cmodel: Either an array of content models as accepted by + * islandora_preprare_new_object(), or a single content model PID to add + * to the object. + * - parent: Either an array of parents, or a single parent PID to which to + * relate to; uses isMemberOfCollection by default. + * - relationships: An array of relationships as accepted by + * islandora_prepare_new_object(). + * + * @return FedoraObject + * The newly created object. + */ +function islandora_solution_pack_add_object(array $object_definition) { + $object = islandora_solution_pack_prepare_new_object($object_definition); + return islandora_add_object($object); +} + +/** + * Prepares a new object based on the solution pack style of declaring them as arrays. + * + * @param array $object_definition + * An associative array containing the necessary parameters to create the + * desired object: + * - pid: The PID with which the object will be created. + * - label: An optional label to apply to the object. + * - datastreams: Same as the "datastreams" array accepted by + * islandora_prepare_new_object(). + * - cmodel: Either an array of content models as accepted by + * islandora_prepare_new_object(), or a single content model PID to add + * to the object. + * - parent: Either an array of parents, or a single parent PID to which to + * relate to; uses isMemberOfCollection by default. + * - relationships: An array of relationships as accepted by + * islandora_prepare_new_object(). + * + * @return NewFedoraObject + * 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(); + if (!empty($object_definition['datastreams']) AND is_array($object_definition['datastreams'])) { + $datastreams = $object_definition['datastreams']; + } + $content_models = array(); + if (!empty($object_definition['cmodel'])) { + if (is_array($object_definition['cmodel'])) { + $content_models = $object_definition['cmodel']; + } + else { + $content_models[] = $object_definition['cmodel']; + } + } + $relationships = array(); + if (!empty($object_definition['parent']) AND !is_array($object_definition['parent'])) { + $relationships[] = array('relationship' => 'isMemberOfCollection', 'pid' => $object_definition['parent']); + } + if (!empty($object_definition['parents']) AND is_array($object_definition['parents'])) { + foreach ($object_definition['parents'] as $parent) { + $relationships[] = array('relationship' => 'isMemberOfCollection', 'pid' => $parent); + } + } + if (!empty($object_definition['relationships']) AND is_array($object_definition['relationships'])) { + foreach ($object_definition['relationships'] as $relationship) { + $relationships[] = array('relationship' => $relationship['relationship'], 'pid' => $relationship['pid']); + } + } + return islandora_prepare_new_object($namespace, $label, $datastreams, $content_models, $relationships); +} + + /** * @defgroup viewer-functions * @{ @@ -531,13 +571,15 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL) { '#type' => 'item', '#title' => t('Select a viewer'), '#description' => t('Preferred viewer for your solution pack. These may be provided by third-party modules.'), - '#tree' => TRUE, // this attribute is important to return the submitted values in a deeper nested arrays in + // This attribute is important to return the submitted values in a deeper + // nested arrays in + '#tree' => TRUE, '#theme' => 'islandora_viewers_table', ); // table loop foreach ($viewers as $name => $profile) { - + $options[$name] = ''; // machine name $form['viewers'][$variable_id]['name'][$name] = array( @@ -582,16 +624,17 @@ function islandora_viewers_form($variable_id = NULL, $mimetype = NULL) { * Returns all defined viewers. * * @param string $mimetype - * specify a mimetype to return only viewers that support this certain mimetype. + * specify a mimetype to return only viewers that support this certain + * mimetype. * @return * array of viewer definitions, or FALSE if none are found. */ function islandora_get_viewers($mimetype = NULL) { $viewers = array(); // get all viewers - $defined_viewers = module_invoke_all('islandora_viewer_info'); + $defined_viewers = module_invoke_all('islandora_viewer_info'); // filter viewers by mimetype - foreach($defined_viewers as $key => $value) { + foreach ($defined_viewers as $key => $value) { if (in_array($mimetype, $value['mimetype']) OR $mimetype == NULL) { $viewers[$key] = $value; } @@ -702,11 +745,9 @@ function islandora_get_viewer_id($variable_id) { */ function islandora_get_viewer_callback($viewer_id = NULL) { if ($viewer_id !== NULL) { - // get defined viewers $viewers = module_invoke_all('islandora_viewer_info'); if (isset($viewers[$viewer_id]['callback'])) { - // return callback function - return $viewers[$viewer_id]['callback']; + return $viewers[$viewer_id]['callback']; } } return FALSE; diff --git a/includes/utilities.inc b/includes/utilities.inc index 820e7660..2e36e7bd 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -3,6 +3,8 @@ /** * @file * Contains islandora utility functions + * + * @todo this file should be broken out into other files. */ /** @@ -58,45 +60,44 @@ function islandora_control_group_to_human_readable($control_group) { } /** - * valid pid ?? - * @param type $pid + * Checks if the given pid is valid. + * + * @param string $pid + * The object id to check. + * * @return boolean + * TRUE if valid, FALSE otherwise. */ -function islandora_validate_pid($pid) { - $valid = FALSE; - if (drupal_strlen(trim($pid)) <= 64 && preg_match('/^([A-Za-z0-9]|-|\.)+:(([A-Za-z0-9])|-|\.|~|_|(%[0-9A-F]{2}))+$/', trim($pid))) { - $valid = TRUE; - } - - return $valid; +function islandora_is_valid_pid($pid) { + return drupal_strlen(trim($pid)) <= 64 && preg_match('/^([A-Za-z0-9]|-|\.)+:(([A-Za-z0-9])|-|\.|~|_|(%[0-9A-F]{2}))+$/', trim($pid)); } /** - * Valid Dsid ?? - * @param type $dsid + * Checks if the given datastream id is valid. + * + * @param string $dsid + * The datastream id to check. + * * @return boolean + * TRUE if valid, FALSE otherwise. */ -function islandora_validate_dsid($dsid) { - $valid = FALSE; - if (drupal_strlen(trim($dsid)) <= 64 && preg_match('/^[a-zA-Z0-9\_\-\.]+$/', trim($dsid))) { - $valid = TRUE; - } - - return $valid; +function islandora_is_valid_dsid($dsid) { + return drupal_strlen(trim($dsid)) <= 64 && preg_match('/^[a-zA-Z0-9\_\-\.]+$/', trim($dsid)); } -/* Helper function to describe a Fedora repository. +/** + * Helper function to describe a Fedora repository. * * Can be used to check if Fedora is available. * - * @param $url - * A url to a Fedora repository. + * @param string $url + * A url to a Fedora repository, if NULL the default is used. * @return * Returns an array describing the repository. Returns FALSE if Fedora is down * or if the url is incorrect. */ -function islandora_describe_repository($url) { - module_load_include('inc', 'islandora', 'includes/tuque'); +function islandora_describe_repository($url = NULL) { + $url = isset($url) ? $url : variable_get('islandora_base_url', 'http://localhost:8080/fedora'); $connection = new IslandoraTuque(NULL, $url); try { $info = $connection->api->a->describeRepository(); @@ -125,8 +126,9 @@ function islandora_describe_repository($url) { function islandora_build_hook_list($hook, $pids = array()) { $hooks = array(); - foreach ($pids as $model) { - $hooks[] = islandora_escape_pid_for_function($model) . '_' . $hook; + $pids = array_unique($pids); + foreach ($pids as $pid) { + $hooks[] = islandora_escape_pid_for_function($pid) . '_' . $hook; } $hooks[] = $hook; @@ -152,3 +154,258 @@ function islandora_escape_pid_for_function($pid) { $pid ); } + +/** + * Gets the namespace of the given id. + * + * @param string $id + * Either a PID or namespace to check for accessibility. Any string like those + * below are fine. + * + * @code + * 'islandora', + * 'islandora:', + * 'islandora:1234', + * @endcode + * + * @return string + * The namespace portion of the given string. + */ +function islandora_get_namespace($id) { + $matches = array(); + preg_match('/^([^:]*)/', $id, $matches); + return $matches[0]; +} + +/** + * Checks the given namespace or PID is/has an accessible namespace as defined + * by the "islandora_pids_allowed" variable. + * + * @param string $namespace + * Either a PID or namespace to check for accessibility. Any string like those + * below are fine. + * + * @code + * 'islandora', + * 'islandora:', + * 'islandora:1234', + * @endcode + * + * @return boolean + * TRUE if accessible, FALSE otherwise. + */ +function islandora_namespace_accessible($id) { + if (variable_get('islandora_namespace_restriction_enforced', FALSE)) { + $namespace = islandora_get_namespace($id) . ':'; + $allowed_namespaces = explode(" ", variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora: ilives: islandora-book: books: newspapers: ')); + return in_array($namespace, $allowed_namespaces); + } + 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; +} diff --git a/islandora.api.php b/islandora.api.php index 918b5502..337814fa 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -155,17 +155,15 @@ function hook_islandora_object_alter($fedora_object) {} * * @param type $islandora_object * A Tuque FedoraObject - * @param array $content_models - * @param string $collection_pid */ -function hook_islandora_ingest_pre_ingest($islandora_object, $content_models, $collection_pid) {} +function hook_islandora_ingest_pre_ingest($islandora_object) {} /** * Allow modification of objects of a certain content model before ingesting. * * @see hook_islandora_ingest_pre_ingest() */ -function hook_CMODEL_PID_islandora_ingest_pre_ingest($islandora_object, $content_models, $collection_pid) {} +function hook_CMODEL_PID_islandora_ingest_pre_ingest($islandora_object) {} /** * Allow modules to setup for the purge of a datastream. @@ -218,3 +216,43 @@ function hook_islandora_required_objects() {} * @see islandora_get_viewer_callback() */ function hook_islandora_viewer_info() {} + + +/** + * Returns a list of datastreams that are determined to be undeletable. + */ +function hook_islandora_undeletable_datastreams(array $models) {} + +/** + * Define steps used in the islandora_ingest_form() ingest process. + * + * @return array + * An array of associative arrays which define each step in the ingest + * process. Steps are defined by by a number of properties (keys) including: + * - type: The type of step. Currently, only "form" is implemented. + * - weight: The "weight" of this step--heavier(/"larger") values sink to the + * end of the process while smaller(/"lighter") values are executed first. + * - form_id: The form building function to call to get the form structure + * for this step. + * - args: An array of arguments to pass to the form building function. + * And may optionally include both: + * - module: A module from which we want to load an include. + * - file: A file to include (relative to the module's path, including the + * file's extension). + */ +function hook_islandora_ingest_steps(array $configuration) { + return array( + array( + 'type' => 'form', + 'weight' => 1, + 'form_id' => 'my_cool_form', + 'args' => array('arg_one', 'numero deux'), + ), + ); +} +/** + * Content model specific version of hook_islandora_ingest_steps(). + * + * @see hook_islandora_ingest_steps() + */ +function hook_CMODEL_PID_islandora_ingest_steps(array $configuration) {} diff --git a/islandora.info b/islandora.info index 188380f9..d43d5c3a 100644 --- a/islandora.info +++ b/islandora.info @@ -6,4 +6,7 @@ core = 7.x configure = admin/islandora/configure stylesheets[all][] = css/islandora.base.css stylesheets[all][] = css/islandora.theme.css +files[] = includes/MimeDetect.inc +files[] = includes/DublinCore.inc +files[] = includes/IslandoraTuque.inc php = 5.3 diff --git a/islandora.install b/islandora.install index c44c6418..88549ce5 100644 --- a/islandora.install +++ b/islandora.install @@ -2,7 +2,8 @@ /** * @file - * This file contains all install functions. + * + * This file contains all install related hooks. */ /** @@ -12,7 +13,6 @@ */ function islandora_install() { module_load_include('inc', 'islandora', 'includes/solution_packs'); - // install object(s) islandora_install_solution_pack('islandora'); } @@ -23,6 +23,5 @@ function islandora_install() { */ function islandora_uninstall() { module_load_include('inc', 'islandora', 'includes/solution_packs'); - // uninstall callback islandora_install_solution_pack('islandora', 'uninstall'); -} \ No newline at end of file +} diff --git a/islandora.module b/islandora.module index c12b034b..f2d49ebb 100644 --- a/islandora.module +++ b/islandora.module @@ -1,9 +1,10 @@ . */ +// Common datastreams +define('DS_COMP_STREAM', 'DS-COMPOSITE-MODEL'); // Permissions define('FEDORA_VIEW', 'view fedora repository'); @@ -34,16 +37,23 @@ define('FEDORA_MANAGE', 'manage fedora items'); // Hooks define('ISLANDORA_VIEW_HOOK', 'islandora_view_object'); define('ISLANDORA_EDIT_HOOK', 'islandora_edit_object'); +define('ISLANDORA_PRE_INGEST_HOOK', 'islandora_ingest_pre_ingest'); define('ISLANDORA_POST_INGEST_HOOK', 'islandora_ingest_post_ingest'); define('ISLANDORA_PRE_PURGE_OBJECT_HOOK', 'islandora_pre_purge_object'); +define('ISLANDORA_POST_PURGE_OBJECT_HOOK', 'islandora_post_purge_object'); +define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps'); +define('ISLANDORA_PRE_PURGE_DATASTREAM_HOOK', 'islandora_pre_purge_datastream'); +define('ISLANDORA_POST_PURGE_DATASTREAM_HOOK', 'islandora_post_purge_datastream'); +define('ISLANDORA_EDIT_DATASTREAM_HOOK', 'islandora_edit_datastream'); /** * Implements hook_menu(). - * we need some standard entry points so we can have consistent urls for different Object actions + * + * We need some standard entry points so we can have consistent urls for + * different Object actions */ function islandora_menu() { $items = array(); - $items['admin/islandora'] = array( 'title' => 'Islandora', 'description' => "Configure settings associated with Islandora.", @@ -60,7 +70,6 @@ function islandora_menu() { 'type' => MENU_NORMAL_ITEM, 'weight' => -1, ); - $items['admin/islandora/solution_packs'] = array( 'title' => 'Solution packs', 'description' => 'Install content models and collections required by installed solution packs.', @@ -69,146 +78,130 @@ function islandora_menu() { 'file' => 'includes/solution_packs.inc', 'type' => MENU_NORMAL_ITEM, ); - - $items['islandora/object/%islandora_object/manage/ingest'] = array( - 'title' => 'Add an object', - 'page callback' => 'islandora_ingest_callback', - 'page arguments' => array(2), - 'file' => 'includes/ingest-menu.inc', - 'type' => MENU_LOCAL_ACTION, - 'access callback' => 'islandora_ingest_access_callback', - 'access arguments' => array(2, FEDORA_INGEST), - ); - $items['islandora'] = array( 'title' => 'Islandora Repository', 'page callback' => 'islandora_view_default_object', 'type' => MENU_NORMAL_ITEM, 'access arguments' => array(FEDORA_VIEW), ); - $items['islandora/object/%islandora_object'] = array( 'title' => 'Repository', 'page callback' => 'islandora_view_object', 'page arguments' => array(2), 'type' => MENU_NORMAL_ITEM, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_VIEW), + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(FEDORA_VIEW, 2), ); - - $items['islandora/object/%islandora_object/view'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, ); - $items['islandora/object/%islandora_object/view/default'] = array( 'title' => 'View', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -1, ); - $items['islandora/object/%islandora_object/manage'] = array( 'title' => 'Manage', 'page callback' => 'islandora_edit_object', 'page arguments' => array(2), 'type' => MENU_LOCAL_TASK, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_MODIFY_STATE), + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(FEDORA_MODIFY_STATE, 2), ); - $items['islandora/object/%islandora_object/manage/datastreams'] = array( 'title' => 'Datastreams', 'type' => MENU_DEFAULT_LOCAL_TASK, 'weight' => -10, ); - $items['islandora/object/%islandora_object/manage/properties'] = array( 'title' => 'Properties', 'page callback' => 'drupal_get_form', - 'file' => 'includes/object_properties.inc', - 'page arguments' => array('islandora_edit_properties_form', 2), + 'file' => 'includes/object_properties.form.inc', + 'page arguments' => array('islandora_object_properties_form', 2), 'type' => MENU_LOCAL_TASK, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_MODIFY_STATE), + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(FEDORA_MODIFY_STATE, 2), 'weight' => -5, ); - $items['islandora/object/%islandora_object/delete'] = array( 'title' => 'Delete object', - 'file' => 'includes/purge.form.inc', + 'file' => 'includes/delete_object.form.inc', 'page callback' => 'drupal_get_form', - 'page arguments' => array('islandora_purge_object', 2), + 'page arguments' => array('islandora_delete_object_form', 2), 'type' => MENU_CALLBACK, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_PURGE), + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(FEDORA_PURGE, 2), ); - $items['islandora/object/%islandora_object/manage/datastreams/add'] = array( 'title' => 'Add a datastream', - 'file' => 'includes/datastream.inc', + 'file' => 'includes/add_datastream.form.inc', 'page callback' => 'drupal_get_form', 'page arguments' => array('islandora_add_datastream_form', 2), 'type' => MENU_LOCAL_ACTION, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_ADD_DS) + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(FEDORA_ADD_DS, 2) ); - $items['islandora/object/%islandora_object/manage/datastreams/add/autocomplete'] = array( - 'file' => 'includes/datastream.inc', - 'page callback' => 'islandora_datastream_autocomplete_callback', + 'file' => 'includes/add_datastream.form.inc', + 'page callback' => 'islandora_add_datastream_form_autocomplete_callback', 'page arguments' => array(2), 'type' => MENU_CALLBACK, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_ADD_DS) + 'access callback' => 'islandora_object_access_callback', + 'access arguments' => array(FEDORA_ADD_DS, 2) ); - - $items['islandora/object/%islandora_object/datastream/%'] = array( + $items['islandora/object/%islandora_object/datastream/%islandora_datastream'] = array( 'title' => 'View datastream', 'page callback' => 'islandora_view_datastream', - 'page arguments' => array(2, 4), + 'page arguments' => array(4, FALSE), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_VIEW), + 'access callback' => 'islandora_object_datastream_access_callback', + 'access arguments' => array(FEDORA_VIEW, 2, 4), + 'load arguments' => array(2), ); - - $items['islandora/object/%islandora_object/datastream/%/view'] = array( + $items['islandora/object/%islandora_object/datastream/%islandora_datastream/view'] = array( 'title' => 'View datastream', 'type' => MENU_DEFAULT_LOCAL_TASK, ); - - $items['islandora/object/%islandora_object/datastream/%/download'] = array( + $items['islandora/object/%islandora_object/datastream/%islandora_datastream/download'] = array( 'title' => 'Download datastream', - 'page callback' => 'islandora_view_datastream', - 'page arguments' => array(2, 4, 5), + 'page callback' => 'islandora_download_datastream', + 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_VIEW), + 'access callback' => 'islandora_object_datastream_access_callback', + 'access arguments' => array(FEDORA_VIEW, 2, 4), + 'load arguments' => array(2), ); - - $items['islandora/object/%islandora_object/datastream/%/edit'] = array( + $items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array( 'title' => 'Edit datastream', 'page callback' => 'islandora_edit_datastream', - 'page arguments' => array(2, 4), + 'page arguments' => array(4), 'type' => MENU_CALLBACK, 'file' => 'includes/datastream.inc', - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_METADATA_EDIT), + 'access callback' => 'islandora_object_datastream_access_callback', + 'access arguments' => array(FEDORA_METADATA_EDIT, 2, 4), + 'load arguments' => array(2), ); - - $items['islandora/object/%islandora_object/datastream/%/delete'] = array( - 'title' => 'Purge data stream', + $items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array( + 'title' => 'Delete data stream', 'page callback' => 'drupal_get_form', - 'page arguments' => array('islandora_purge_datastream', 2, 4), - 'file' => 'includes/purge.form.inc', + 'page arguments' => array('islandora_delete_datastream_form', 4), + 'file' => 'includes/delete_datastream.form.inc', 'type' => MENU_CALLBACK, - 'access callback' => 'islandora_access_callback', - 'access arguments' => array(2, FEDORA_PURGE), + 'access callback' => 'islandora_object_datastream_access_callback', + 'access arguments' => array(FEDORA_PURGE, 2, 4), + 'load arguments' => array(2), + ); + $items['islandora/ingest'] = array( + 'title' => 'Add an Object', + 'page callback' => 'islandora_ingest_callback', + 'file' => 'includes/ingest.menu.inc', + 'type' => MENU_SUGGESTED_ITEM, + 'access arguments' => array(FEDORA_INGEST), ); - return $items; } @@ -225,8 +218,6 @@ function islandora_admin_paths() { /** * Implements hook_theme(). - * - * @return array */ function islandora_theme() { return array( @@ -252,8 +243,6 @@ function islandora_theme() { /** * Implements hook_permission(). - * - * @return array */ function islandora_permission() { return array( @@ -302,97 +291,101 @@ function islandora_forms($form_id) { } /** - * determines whether we can see the object or not - * checks PID namespace permissions, and user permissions - * @global object $user - * @param string $op - * @param string $pid + * Checks whether the user can access the given object with the given + * permission. * - * @return boolean + * Checks for object existance, accessiblitly, namespace permissions, + * and user permissions + * + * @see islandora_object_load() To find potential solutions to enable + * page not found errors. + * + * @param string $perm + * The user permission to test for. + * @param FedoraObject $object + * The object to test, if NULL given the object doesn't exist or is + * inaccessible. + * + * @return boolean + * TRUE if the user is allowed to access this object, FALSE otherwise. */ -function islandora_access_callback($object = NULL, $perm = NULL) { - if (!$object || !$perm) { - return FALSE; - } - - $is_restricted = variable_get('islandora_namespace_restriction_enforced', FALSE); - - if (!$is_restricted) { - $namespace_access = TRUE; - } - else { - $pid_namespace = substr($object->id, 0, strpos($object->id, ':') + 1); // Get the namespace (with colon) - $allowed_namespaces = explode(" ", variable_get('islandora_pids_allowed', 'default: demo: changeme: islandora: ilives: islandora-book: books: newspapers: ')); - $namespace_access = in_array($pid_namespace, $allowed_namespaces); - } +function islandora_object_access_callback($perm, $object = NULL) { + module_load_include('inc', 'islandora', 'includes/utilities'); + return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id); +} - return ($namespace_access && user_access($perm)); +/** + * Checks whether the user can access the given object and datastream with + * the given permission. + * + * Checks for object existance, accessiblitly, namespace permissions, + * and user permissions + * + * @see islandora_object_load() To find potential solutions to enable page + * not found errors. + * + * @param string $perm + * The user permission to test for. + * @param FedoraObject $object + * The object to test, if NULL given the object doesn't exist or is + * inaccessible. + * @param FedoraDatastream $datastream + * The datastream to test, if NULL given the datastream doesn't exist + * or is inaccessible. + * + * @return boolean + * TRUE if the user is allowed to access this object, FALSE otherwise. + */ +function islandora_object_datastream_access_callback($perm, $object = NULL, $datastream = NULL) { + module_load_include('inc', 'islandora', 'includes/utilities'); + return user_access($perm) && is_object($object) && islandora_namespace_accessible($object->id) && is_object($datastream); } /** - * a function to call other modules edit page. If there are not any modules - * that handle this function this module will build a default page. - * @global object $user - * @param string $object_id + * Renders the given objects manage page. + * + * Its possible to modify the output of this function if 'ISLANDORA_EDIT_HOOK' + * is implemented in other modules. + * + * If no modules implement 'ISLANDORA_EDIT_HOOK' then this function returns the + * default manage view. + * + * @param FedoraObject $object + * The object to manage. + * * @return string + * The HTML repersentation of the manage object page. */ -function islandora_edit_object($object) { - if (!$object) { - return drupal_not_found(); - } - +function islandora_edit_object(FedoraObject $object) { module_load_include('inc', 'islandora', 'includes/utilities'); - - // Accumulate the output. $output = array(); - - // Call cmodel oriented variants first. foreach (islandora_build_hook_list(ISLANDORA_EDIT_HOOK, $object->models) as $hook) { $temp = module_invoke_all($hook, $object); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } } - - // Add in the default, if we did not get any results. if (empty($output)) { + // Add in the default, if we did not get any results. $output = islandora_default_islandora_edit_object($object); } - arsort($output); - drupal_alter(ISLANDORA_EDIT_HOOK, $object, $output); - return implode('', $output); } /** - * edit properties form - * @param type $object_id - * @return string - */ -function islandora_edit_properties($object_id) { - $object = islandora_object_load($object_id); - if (isset($object)) { - module_load_include('inc', 'islandora', 'includes/object_properties'); - $form = drupal_get_form('islandora_edit_properties_form', $object); - drupal_set_title($object->label); - return drupal_render($form); - } - return ""; -} - -/** - * Builds a default page for the edit tab. + * Renders the default manage object page for the given object. + * + * @param FedoraObject $object + * The object used to render the manage object page. * - * @param object $fedora_object - * A tuque Fedora Object + * @return array + * The default rendering of the object manage page, indexed at + * 'Default Edit output'. */ -function islandora_default_islandora_edit_object($fedora_object) { - $output = theme('islandora_default_edit', array( - 'islandora_object' => $fedora_object, - )); - +function islandora_default_islandora_edit_object(FedoraObject $object) { + $output = theme('islandora_default_edit', array('islandora_object' => $object)); return array('Default Edit output' => $output); } @@ -400,7 +393,7 @@ function islandora_default_islandora_edit_object($fedora_object) { * Page callback for the path "islandora". * * Redirects to the view of the object indicated by the Drupal variable - * islandora_repository_pid. + * 'islandora_repository_pid'. */ function islandora_view_default_object() { $pid = variable_get('islandora_repository_pid', 'islandora:root'); @@ -408,59 +401,53 @@ function islandora_view_default_object() { } /** - * The view entry point. modules should implement hook_islandora_view_object for the Fedora Content models that - * their modules want to provide a view for. - * @global object $user - * @param string $object_id + * Renders the default view object page for the given object. + * + * Modules should implement ISLANDORA_VIEW_HOOK for the Fedora Content + * models that their modules want to provide a view for. + * + * If no modules implement the hook then the default view object page + * will be rendered. + * + * @param FedoraObject $object + * The object to view. * * @return string + * The html repersentation of this object. */ -function islandora_view_object($fedora_object = NULL) { +function islandora_view_object(FedoraObject $object) { module_load_include('inc', 'islandora', 'includes/breadcrumb'); module_load_include('inc', 'islandora', 'includes/utilities'); - - global $user; - - if (!$fedora_object) { - return drupal_not_found(); - } - - // set breadcrumbs - drupal_set_breadcrumb(islandora_get_breadcrumbs($fedora_object)); - // optional pager parameters + drupal_set_breadcrumb(islandora_get_breadcrumbs($object)); + // Optional pager parameters $page_number = (empty($_GET['page'])) ? '1' : $_GET['page']; $page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize']; - - // Accumulate the output. $output = array(); - - // Call cmodel oriented variants first. - foreach (islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $fedora_object->models) as $hook) { - $temp = module_invoke_all($hook, $fedora_object, $page_number, $page_size); + foreach (islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $object->models) as $hook) { + // @todo Remove page number and size from this hook, implementers of the + // hook should use drupal page handling directly. + $temp = module_invoke_all($hook, $object, $page_number, $page_size); if (!empty($temp)) { $output = array_merge_recursive($output, $temp); } } - - // Add in the default, if we did not get any results. if (empty($output)) { - $output = islandora_default_islandora_view_object($fedora_object); + // No results, use the default view. + $output = islandora_default_islandora_view_object($object); } - arsort($output); - - drupal_alter(ISLANDORA_VIEW_HOOK, $fedora_object, $output); - + drupal_alter(ISLANDORA_VIEW_HOOK, $object, $output); return implode('', $output); } /** - * If there are no modules registered to handle this objects cmodels or there are - * not any cmodels specified this will create a default display. + * Renders the default view object page for the given object. * * @param FedoraObject $object - * The object whose display we are to render. + * The object used to render the view object page. + * * @return array + * The default rendering of the object view page, indexed at 'Default output'. */ function islandora_default_islandora_view_object($object) { $output = theme('islandora_default', array('islandora_object' => $object)); @@ -468,111 +455,77 @@ function islandora_default_islandora_view_object($object) { } /** - * A helper function to get a connection and return an object + * A helper function to get a connection and return an object for objects + * specified in the menu path as '%islandora_object'. * - * @global object $user * @param string $object_id + * The pid of an object in the menu path identified by '%islandora_object'. + * * @return FedoraObject + * If the given object id exists in the repository then this returns a + * FedoraObject. + * If no object was found it returns FALSE which triggers + * drupal_page_not_found(). + * If the object was inaccessible then NULL is returned, and the + * access callback is expected to catch that case, triggering + * drupal_access_denied(). */ function islandora_object_load($object_id) { - module_load_include('inc', 'islandora', 'includes/tuque'); - $islandora_tuque = &drupal_static(__FUNCTION__); - - if (!$islandora_tuque) { - $islandora_tuque = new IslandoraTuque(); - } - - if (IslandoraTuque::exists()) { + module_load_include('inc', 'islandora', 'includes/IslandoraTuque'); + $tuque = islandora_get_tuque_connection(); + if ($tuque) { try { - $fedora_object = $islandora_tuque->repository->getObject($object_id); + $object = $tuque->repository->getObject($object_id); + drupal_alter('islandora_object', $object); + return $object; } catch (Exception $e) { - return NULL; + if ($e->getCode() == '404') { + return FALSE; + } + else { + return NULL; + } } - - drupal_alter('islandora_object', $fedora_object); - return $fedora_object; } else { IslandoraTuque::getError(); - return NULL; } + // Assuming access denied in all other cases for now. + return NULL; } /** - * A helper function to get a connection and purge an object + * A helper function to get an datastream specified as '%islandora_datastream' + * for the object specified in the menu path as '%islandora_object'. * - * @global object $user - * @param string $object_id - * @return FedoraObject + * Its up to the access callbacks and menu callbacks to trigger + * drupal_access_denied() when appropriate. + * + * @param string $datastream_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_object_purge($object_id) { - if (!$object_id) { - drupal_set_message(t('Cannot remove object, object id not set')); - return; - } - - // load object +function islandora_datastream_load($datastream_id, $object_id) { $object = islandora_object_load($object_id); if (!$object) { - drupal_set_message(t('Could not remove object, object not found')); - return; - } - - module_load_include('inc', 'islandora', 'includes/utilities'); - - $content_models = $object->models; - - $arr = array(); - foreach (islandora_build_hook_list(ISLANDORA_PRE_PURGE_OBJECT_HOOK, $object->models) as $hook) { - $temp = module_invoke_all($hook, $object); - if (!empty($temp)) { - $arr = array_merge_recursive($arr, $temp); - } - } - - if (isset($arr['delete']) && $arr['delete']) { - try { - $object->delete(); - } catch (Exception $e) { - drupal_set_message(t('Error deleting Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error'); - return ""; - } - } - else { - try { - $object->repository->purgeObject($object_id); - } catch (Exception $e) { - drupal_set_message(t('Error purging Islandora object %s %e', array('%s' => $object_id, '%e' => $e)), 'error'); - return ""; - } + return NULL; } - module_invoke_all('islandora_post_purge_object', $object_id, $content_models); // notify modules post deletion + return $object[$datastream_id]; } - /** - * Ingest access callback - */ -function islandora_ingest_access_callback($object, $perm) { - if (islandora_access_callback($object, $perm) === FALSE) { - return FALSE; - } - - $ingest_registry = module_invoke_all('islandora_ingest_registry', $object); - - if (count($ingest_registry) > 0) { - return TRUE; - } - else { - return FALSE; - } -} - -/** - * Content model, collection view and collection policy datastreams may now optionally define a version - * number in their top-level XML element as an attribute, as in: + * Content model, collection view and collection policy datastreams may now + * optionally define a version number in their top-level XML element as an + * attribute, as in: * array( @@ -634,7 +586,202 @@ function islandora_islandora_required_objects() { ); } +/** + * Implements islandora_undeleteable_datastreams(). + */ +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); + } +} diff --git a/theme/islandora-object-edit.tpl.php b/theme/islandora-object-edit.tpl.php index f0005083..0772a899 100644 --- a/theme/islandora-object-edit.tpl.php +++ b/theme/islandora-object-edit.tpl.php @@ -2,8 +2,9 @@ /** * @file - * islandora-object-edit.tpl.php: This is a template for objects that do not have - * a module to registered to build their display. + * + * islandora-object-edit.tpl.php: This is a template for objects that do not + * have a module to registered to build their display. * * islandora_object is a fedora tuque Object * $object->label @@ -11,9 +12,10 @@ * to get the contents of a datastream * $object['dsid']->content * - * $dublin_core is a Dublin_Core object + * $dublin_core is a DublinCore object * which is an array of elements, such as dc.title - * and each element has an array of values. dc.title can have none, one or many titles + * and each element has an array of values. + * dc.title can have none, one or many titles * this is the case for all dc elements. * */ @@ -21,4 +23,4 @@ label); ?> - \ No newline at end of file + diff --git a/theme/islandora-object.tpl.php b/theme/islandora-object.tpl.php index e876f679..9062098c 100644 --- a/theme/islandora-object.tpl.php +++ b/theme/islandora-object.tpl.php @@ -1,9 +1,11 @@ label - The label for this object. * $object->id - The identifier of the object. @@ -17,7 +19,7 @@ * to test if a datastream exists isset($object['dsid']) * * to iterate over datastreams: - * foreach($object as $ds) { + * foreach ($object as $ds) { * $ds->label, etc * } * @@ -35,22 +37,25 @@ * $ds->size - The size of the datastream * $ds->checksum - The checksum of the datastream * $ds->checksumType - The type of checksum for the datastream. - * $ds->createdDate->format("Y-m-d") - The created date with an option to use a format of your choice + * $ds->createdDate->format("Y-m-d") - The created date with an option to use + * a format of your choice * $ds->content - The content of the datastream - * $ds->url - The URL. This is only valid for R and E datastreams. - * - * $dublin_core is a Dublin_Core object + * $ds->url - The URL. This is only valid for R and E + * datastreams. + * + * $dublin_core is a DublinCore object * which is an array of elements, such as dc.title - * and each element has an array of values. dc.title can have none, one or many titles + * and each element has an array of values. + * dc.title can have none, one or many titles * this is the case for all dc elements. * * - * + * * we can get a list of datastreams by doing - * foreach ($object as $ds){ + * foreach ($object as $ds) { * do something here * } - * + * */ ?> @@ -80,8 +85,8 @@
Collections
- $value): ?> -
+ +
label, "islandora/object/{$collection->id}"); ?>
@@ -96,7 +101,7 @@ - + $value): ?> diff --git a/theme/islandora.theme.inc b/theme/islandora.theme.inc index 7999e0d0..7cac4d1a 100644 --- a/theme/islandora.theme.inc +++ b/theme/islandora.theme.inc @@ -2,6 +2,7 @@ /** * @file + * * This file contains all theme and preprocess functions. */ @@ -13,13 +14,12 @@ * theme variables for the edit template */ function islandora_preprocess_islandora_default_edit(&$variables) { - $islandora_object = $variables['islandora_object']; global $base_url; + $islandora_object = $variables['islandora_object']; $datastreams = array(); $variables['islandora_editmetadata_url'] = $base_url . '/islandora/edit_form/' . $islandora_object->id; module_load_include('inc', 'islandora', 'includes/datastream'); module_load_include('inc', 'islandora', 'includes/utilities'); - // $variables['add_datastream_form'] = drupal_get_form('islandora_add_datastream_form', $islandora_object->id); $header = array( array('data' => t('ID')), array('data' => t('Label')), @@ -27,7 +27,6 @@ function islandora_preprocess_islandora_default_edit(&$variables) { array('data' => t('Mime type')), array('data' => t('Size')), array('data' => t('Operations'), 'colspan' => '3'), - //array('data' => t('Delete')), ); $table_attributes = array('class' => array('manage-datastreams')); $rows = array(); @@ -39,7 +38,7 @@ function islandora_preprocess_islandora_default_edit(&$variables) { array('class' => 'datastream-mime', 'data' => $ds->mimeType), array('class' => 'datastream-size', 'data' => islandora_datastream_get_human_readable_size($ds)), array('class' => 'datastream-download', 'data' => l(t('download'), islandora_datastream_get_url($ds, 'download'))), - array('class' => 'datstream-edit', 'data' => islandora_datastream_edit_get_link($islandora_object, $ds->id)), + array('class' => 'datstream-edit', 'data' => islandora_datastream_edit_get_link($ds)), array('class' => 'datastream-delete', 'data' => islandora_datastream_get_delete_link($ds)), ); } @@ -59,11 +58,10 @@ function islandora_preprocess_islandora_default(&$variables) { drupal_add_js('misc/form.js'); drupal_add_js('misc/collapse.js'); $islandora_object = $variables['islandora_object']; - module_load_include('inc', 'islandora', 'includes/islandora_dublin_core'); module_load_include('inc', 'islandora', 'includes/utilities'); module_load_include('inc', 'islandora', 'includes/datastream'); - $variables['parent_collections'] = islandora_datastream_get_parents($islandora_object); + $variables['parent_collections'] = islandora_get_parents_from_rels_ext($islandora_object); $datastreams = array(); foreach ($islandora_object as $ds) { @@ -88,8 +86,7 @@ function islandora_preprocess_islandora_default(&$variables) { $variables['datastreams'] = $datastreams; try { $dc = $islandora_object['DC']->content; - //$dc_xml = simplexml_load_string($dc); - $dc_object = Dublin_Core::import_from_xml_string($dc); + $dc_object = DublinCore::import_from_xml_string($dc); $dc_array = $dc_object->as_formatted_array(); } catch (Exception $e) { drupal_set_message(t('Error retrieving object %s %t', array('%s' => $islandora_object->id, '%t' => $e->getMessage())), 'error', FALSE); @@ -101,4 +98,4 @@ function islandora_preprocess_islandora_default(&$variables) { if (isset($islandora_object['TN'])) { $variables['islandora_thumbnail_url'] = $base_url . '/islandora/object/' . $islandora_object->id . '/datastream/TN/view'; } -} \ No newline at end of file +}