Skip to content
Permalink
Branch: 7.x
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
2227 lines (2093 sloc) 76.9 KB
<?php
/**
* @file
* Defines all the hooks this module implements.
*
* islandora.module: defines paths (drupal menu items) as entry points and acts
* as a hub for dispatching tasks to other modules.
*
* This file is part of Islandora.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the program. If not, see <http ://www.gnu.org/licenses/>.
*/
// Common datastreams.
define('ISLANDORA_DS_COMP_STREAM', 'DS-COMPOSITE-MODEL');
// Permissions.
define('ISLANDORA_VIEW_OBJECTS', 'view fedora repository objects');
define('ISLANDORA_METADATA_EDIT', 'edit fedora metadata');
define('ISLANDORA_ADD_DS', 'add fedora datastreams');
define('ISLANDORA_INGEST', 'ingest fedora objects');
define('ISLANDORA_PURGE', 'delete fedora objects and datastreams');
define('ISLANDORA_MANAGE_PROPERTIES', 'manage object properties');
define('ISLANDORA_VIEW_DATASTREAM_HISTORY', 'view old datastream versions');
define('ISLANDORA_ACCESS_INACTIVE_AND_DELETED_OBJECTS', 'access inactive and deleted objects');
define('ISLANDORA_MANAGE_DELETED_OBJECTS', 'manage deleted objects');
define('ISLANDORA_REVERT_DATASTREAM', 'revert to old datastream');
define('ISLANDORA_REGENERATE_DERIVATIVES', 'regenerate derivatives for an object');
define('ISLANDORA_REPLACE_DATASTREAM_CONTENT', 'replace a datastream with new content, preserving version history');
define('ISLANDORA_MANAGE_ORPHANED_OBJECTS', 'view and delete a list of orphaned objects');
// Hooks.
define('ISLANDORA_VIEW_HOOK', 'islandora_view_object');
define('ISLANDORA_PRINT_HOOK', 'islandora_view_print_object');
define('ISLANDORA_EDIT_HOOK', 'islandora_edit_object');
define('ISLANDORA_OVERVIEW_HOOK', 'islandora_overview_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_UPDATE_RELATED_OBJECTS_PROPERTIES_HOOK', 'islandora_update_related_objects_properties');
define('ISLANDORA_METADATA_OBJECT_ALTER', 'islandora_metadata_object');
define('ISLANDORA_METADATA_OBJECT_DESCRIPTION_ALTER', 'islandora_metadata_object_description');
define('ISLANDORA_BREADCRUMB_FILTER_PREDICATE_HOOK', 'islandora_get_breadcrumb_query_predicates');
define('ISLANDORA_EDIT_DATASTREAM_REGISTRY_HOOK', 'islandora_edit_datastream_registry');
// @todo Add Documentation.
define('ISLANDORA_OBJECT_INGESTED_HOOK', 'islandora_object_ingested');
define('ISLANDORA_OBJECT_MODIFIED_HOOK', 'islandora_object_modified');
define('ISLANDORA_OBJECT_PURGED_HOOK', 'islandora_object_purged');
define('ISLANDORA_DATASTREAM_INGESTED_HOOK', 'islandora_datastream_ingested');
define('ISLANDORA_DATASTREAM_MODIFIED_HOOK', 'islandora_datastream_modified');
define('ISLANDORA_DATASTREAM_PURGED_HOOK', 'islandora_datastream_purged');
define('ISLANDORA_INGEST_STEP_HOOK', 'islandora_ingest_steps');
define('ISLANDORA_DERIVATIVE_CREATION_HOOK', 'islandora_derivative');
// Autocomplete paths.
define('ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE', 'islandora/autocomplete/content-models');
define('ISLANDORA_MIME_TYPES_AUTOCOMPLETE', 'islandora/autocomplete/mime-types');
const ISLANDORA_BREADCRUMB_LEGACY_BACKEND = 'islandora_breadcrumbs_legacy_sparql';
/**
* Implements hook_menu().
*
* 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.",
'access arguments' => array('administer site configuration'),
'type' => MENU_NORMAL_ITEM,
);
$items['admin/islandora/configure'] = array(
'title' => 'Configuration',
'description' => 'Configure settings for Islandora.',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_repository_admin'),
'file' => 'includes/admin.form.inc',
'access arguments' => array('administer site configuration'),
'type' => MENU_NORMAL_ITEM,
'weight' => -1,
);
$items['admin/islandora/metadata'] = array(
'title' => 'Metadata Display',
'description' => 'Configure settings for metadata display on Islandora objects',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_metadata_display_form'),
'file' => 'includes/metadata.inc',
'access arguments' => array('administer site configuration'),
);
$items['admin/islandora/solution_pack_config'] = array(
'title' => 'Solution pack configuration',
'description' => 'Configure Islandora solution packs.',
'access callback' => 'islandora_find_package',
'access arguments' => array('Islandora Solution Packs'),
'type' => MENU_NORMAL_ITEM,
);
$items['admin/islandora/islandora_viewers'] = array(
'title' => 'Islandora Viewers',
'description' => 'Configure custom viewers.',
'access callback' => 'islandora_find_package',
'access arguments' => array('Islandora Viewers'),
'type' => MENU_NORMAL_ITEM,
);
$items['admin/islandora/tools'] = array(
'title' => 'Islandora Utility Modules',
'description' => 'Configure Islandora utility modules.',
'access callback' => 'islandora_find_package',
'access arguments' => array('Islandora Tools'),
'type' => MENU_NORMAL_ITEM,
);
$items['admin/islandora/solution_pack_config/solution_packs'] = array(
'title' => 'Solution packs required objects',
'description' => 'Install content models and collections required by installed solution packs.',
'page callback' => 'islandora_solution_packs_admin',
'access arguments' => array(ISLANDORA_ADD_DS),
'file' => 'includes/solution_packs.inc',
'type' => MENU_NORMAL_ITEM,
'weight' => -1,
);
$items['islandora'] = array(
'title' => 'Islandora Repository',
'page callback' => 'islandora_view_default_object',
'type' => MENU_NORMAL_ITEM,
'access arguments' => array(ISLANDORA_VIEW_OBJECTS),
);
$items['islandora/object/%islandora_object'] = array(
'title callback' => 'islandora_drupal_title',
'title arguments' => array(2),
'page callback' => 'islandora_view_object',
'page arguments' => array(2),
'type' => MENU_NORMAL_ITEM,
'access callback' => 'islandora_object_access_callback',
'access arguments' => array(ISLANDORA_VIEW_OBJECTS, 2),
);
$items['islandora/object/%islandora_object/print_object'] = array(
'title' => 'Print Object',
'weight' => 20,
'page callback' => 'islandora_printer_object',
'page arguments' => array(2),
'type' => MENU_LOCAL_TASK,
'access callback' => 'islandora_print_object_access',
'access arguments' => array(ISLANDORA_VIEW_OBJECTS, 2),
);
$items['islandora/object/%islandora_object/print'] = array(
'title' => 'Print Object',
'page callback' => 'islandora_print_object',
'page arguments' => array(2),
'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access',
'access arguments' => array(ISLANDORA_VIEW_OBJECTS, 2),
'load arguments' => array(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_manage_overview_object',
'page arguments' => array(2),
'type' => MENU_LOCAL_TASK,
'access callback' => 'islandora_object_manage_access_callback',
'access arguments' => array(
array(
ISLANDORA_MANAGE_PROPERTIES,
ISLANDORA_METADATA_EDIT,
ISLANDORA_ADD_DS,
ISLANDORA_PURGE,
ISLANDORA_INGEST,
), 2),
);
$items['islandora/object/%islandora_object/manage/overview'] = array(
'title' => 'Overview',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -20,
);
$items['islandora/object/%islandora_object/manage/datastreams'] = array(
'title' => 'Datastreams',
'type' => MENU_LOCAL_TASK,
'page callback' => 'islandora_edit_object',
'page arguments' => array(2),
'access callback' => 'islandora_object_manage_access_callback',
'access arguments' => array(
array(
ISLANDORA_METADATA_EDIT,
ISLANDORA_ADD_DS,
ISLANDORA_PURGE,
), 2),
'weight' => -10,
);
$items['islandora/object/%islandora_object/manage/properties'] = array(
'title' => 'Properties',
'page callback' => 'drupal_get_form',
'file' => 'includes/object_properties.form.inc',
'page arguments' => array('islandora_object_properties_form', 2),
'type' => MENU_LOCAL_TASK,
'access callback' => 'islandora_object_access_callback',
'access arguments' => array(ISLANDORA_MANAGE_PROPERTIES, 2),
'weight' => -5,
);
$items['islandora/object/%islandora_object/delete'] = array(
'title' => 'Delete object',
'file' => 'includes/delete_object.form.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_delete_object_form', 2),
'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access_callback',
'access arguments' => array(ISLANDORA_PURGE, 2),
);
$items['islandora/object/%islandora_object/regenerate'] = array(
'title' => 'Regenerate all derivatives on an object',
'file' => 'includes/regenerate_derivatives.form.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_regenerate_object_derivatives_form', 2),
'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access_callback',
'access arguments' => array(ISLANDORA_REGENERATE_DERIVATIVES, 2),
);
$items['islandora/object/%islandora_object/manage/datastreams/add'] = array(
'title' => 'Add a datastream',
'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_object_access_callback',
'access arguments' => array(ISLANDORA_ADD_DS, 2),
);
$items['islandora/object/%islandora_object/manage/datastreams/add/autocomplete'] = array(
'file' => 'includes/add_datastream.form.inc',
'page callback' => 'islandora_add_datastream_form_autocomplete_callback',
'page arguments' => array(2),
'type' => MENU_CALLBACK,
'access callback' => 'islandora_object_access_callback',
'access arguments' => array(ISLANDORA_ADD_DS, 2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream'] = array(
'title' => 'View datastream',
'page callback' => 'islandora_view_datastream',
'page arguments' => array(4, FALSE, NULL),
'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_VIEW_OBJECTS, 4),
'load arguments' => array(2),
);
// This menu item uses token authentication in islandora_tokened_object.
$items['islandora/object/%islandora_tokened_object/datastream/%islandora_tokened_datastream/view'] = array(
'title' => 'View datastream',
'load arguments' => array('%map'),
'access callback' => 'islandora_object_datastream_tokened_access_callback',
'access arguments' => array(ISLANDORA_VIEW_OBJECTS, 2, 4),
'type' => MENU_DEFAULT_LOCAL_TASK,
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/download'] = array(
'title' => 'Download datastream',
'page callback' => 'islandora_download_datastream',
'page arguments' => array(4),
'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_VIEW_OBJECTS, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/edit'] = array(
'title' => 'Edit datastream',
'page callback' => 'islandora_edit_datastream',
'page arguments' => array(4),
'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_METADATA_EDIT, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/delete'] = array(
'title' => 'Delete data stream',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_delete_datastream_form', 4),
'file' => 'includes/delete_datastream.form.inc',
'type' => MENU_CALLBACK,
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_PURGE, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/version'] = array(
'title' => 'Datastream Versions',
'page arguments' => array(4),
'page callback' => 'islandora_datastream_version_table',
'file' => 'includes/datastream.version.inc',
'type' => MENU_CALLBACK,
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/replace'] = array(
'title' => 'Replace Datastream',
'page arguments' => array('islandora_datastream_version_replace_form', 4),
'page callback' => 'drupal_get_form',
'file' => 'includes/datastream.version.inc',
'type' => MENU_CALLBACK,
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_REPLACE_DATASTREAM_CONTENT, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/version/%/delete'] = array(
'title' => 'Delete datastream version',
'page arguments' => array('islandora_delete_datastream_version_form', 4, 6),
'page callback' => 'drupal_get_form',
'file' => 'includes/datastream.version.inc',
'type' => MENU_CALLBACK,
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_PURGE, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/version/%/revert'] = array(
'title' => 'Revert to datastream version',
'page arguments' => array('islandora_revert_datastream_version_form', 4, 6),
'page callback' => 'drupal_get_form',
'file' => 'includes/datastream.version.inc',
'type' => MENU_CALLBACK,
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_REVERT_DATASTREAM, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/version/%/view'] = array(
'title' => 'View datastream version',
'page callback' => 'islandora_view_datastream',
'page arguments' => array(4, FALSE, 6),
'type' => MENU_CALLBACK,
'file' => 'includes/datastream.inc',
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_VIEW_DATASTREAM_HISTORY, 4),
'load arguments' => array(2),
);
$items['islandora/object/%islandora_object/datastream/%islandora_datastream/regenerate'] = array(
'title' => 'Regenrate datastream derivative',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_regenerate_datastream_derivative_form', 4),
'file' => 'includes/regenerate_derivatives.form.inc',
'type' => MENU_CALLBACK,
'access callback' => 'islandora_datastream_access',
'access arguments' => array(ISLANDORA_REGENERATE_DERIVATIVES, 4),
'load arguments' => array(2),
);
$items['islandora/event-status'] = array(
'title' => 'Event Status',
'page callback' => 'islandora_event_status',
'type' => MENU_CALLBACK,
'access callback' => TRUE,
'file' => 'includes/utilities.inc',
);
$items[ISLANDORA_CONTENT_MODELS_AUTOCOMPLETE] = array(
'title' => 'Autocomplete callback',
'description' => 'Autocomplete a Fedora content model PID.',
'file' => 'includes/content_model.autocomplete.inc',
'page callback' => 'islandora_content_model_autocomplete',
'page arguments' => array(3),
'access arguments' => array('administer site configuration'),
'type' => MENU_CALLBACK,
);
$items[ISLANDORA_MIME_TYPES_AUTOCOMPLETE] = array(
'title' => 'Autocomplete callback',
'description' => 'Autocomplete MIME Types.',
'file' => 'includes/mime_type.autocomplete.inc',
'page callback' => 'islandora_mime_type_autocomplete',
'page arguments' => array(3),
'access arguments' => array('administer site configuration'),
'type' => MENU_CALLBACK,
);
$items['admin/islandora/restore/prep'] = array(
'description' => 'Restore or permanantly remove objects with Deleted status',
'title' => 'Manage Deleted Objects',
'file' => 'includes/manage_deleted_objects.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_deleted_objects_prep_form'),
'type' => MENU_NORMAL_ITEM,
'access arguments' => array(ISLANDORA_MANAGE_DELETED_OBJECTS),
);
$items['admin/reports/orphaned_objects/list'] = array(
'title' => 'Orphaned Islandora objects',
'description' => 'List of orphaned Islandora objects.',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_manage_orphaned_objects_form'),
'access arguments' => array(ISLANDORA_MANAGE_ORPHANED_OBJECTS),
'file' => 'includes/orphaned_objects.inc',
);
$items['admin/islandora/restore/manage'] = array(
'description' => 'Restore or permanantly remove objects with Deleted status',
'title' => 'Manage Deleted Objects',
'file' => 'includes/manage_deleted_objects.inc',
'page callback' => 'drupal_get_form',
'page arguments' => array('islandora_deleted_objects_manage_form'),
'type' => MENU_SUGGESTED_ITEM,
'access arguments' => array(ISLANDORA_MANAGE_DELETED_OBJECTS),
);
return $items;
}
/**
* Implements hook_admin_paths().
*/
function islandora_admin_paths() {
$paths = array();
$paths['islandora/object/*/manage*'] = TRUE;
$paths['islandora/object/*/delete*'] = TRUE;
$paths['islandora/object/*/datastream/*/edit'] = TRUE;
$paths['islandora/object/*/datastream/*/versions'] = TRUE;
return $paths;
}
/**
* Implements hook_theme().
*
* The theme entries 'islandora_objects' and 'islandora_objects_subset'
* utilize the same template file. When theming, be sure to utilize the theme
* name, and not the template file names. Similar situation found here:
* @link https://jira.duraspace.org/browse/ISLANDORA-934. @endlink
*/
function islandora_theme() {
return array(
// Default object template.
'islandora_default' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-object',
'variables' => array('islandora_object' => NULL),
),
// Default edit page.
'islandora_default_edit' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-object-edit',
'variables' => array('islandora_object' => NULL),
),
// Admin table for solution pack viewer selection.
'islandora_viewers_table' => array(
'file' => 'includes/solution_packs.inc',
'render element' => 'form',
),
// Print used by the clipper.
'islandora_object_print' => array(
'file' => 'theme/theme.inc',
'variables' => array('object' => NULL, 'content' => array()),
),
// Print object view, prints islandora objects.
'islandora_object_print_object' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-object-print',
'variables' => array(
'object' => NULL,
'content' => NULL,
'islandora_content' => NULL,
),
),
// Render a bunch of objects as either a grid or a list.
'islandora_objects' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects',
'variables' => array(
'objects' => NULL,
'display' => NULL,
'page_size' => 20,
'limit' => 12,
),
),
// Render a bunch of objects as either a grid or a list.
'islandora_objects_subset' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects',
'variables' => array(
'objects' => NULL,
'display' => 'grid',
'limit' => 10,
'total' => NULL,
'pager_element' => 0,
),
),
// Render a bunch of objects as a grid.
'islandora_objects_grid' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects-grid',
'variables' => array('objects' => NULL),
),
// Render a bunch of objects as a list.
'islandora_objects_list' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-objects-list',
'variables' => array('objects' => NULL),
),
'islandora_datastream_edit_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_delete_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL, 'version' => NULL),
),
'islandora_datastream_revert_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL, 'version' => NULL),
),
'islandora_datastream_view_link' => array(
'file' => 'theme/theme.inc',
'variables' => array(
'datastream' => NULL,
'version' => NULL,
'label' => NULL,
),
),
'islandora_datastream_download_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_version_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_regenerate_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_datastream_replace_link' => array(
'file' => 'theme/theme.inc',
'variables' => array('datastream' => NULL),
),
'islandora_dublin_core_display' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-dublin-core-display',
// We can add PIDs to the end of this pattern in our preprocess function
// and templates will be able to have have a pid appended to the
// template name to overide a template on a per object basis.
// An example template might be named:
// "islandora-dublin-core-display--islandora-27.tpl.php".
'pattern' => 'islandora_dublin_core_display__',
'variables' => array(
'islandora_object' => NULL,
'print' => NULL,
),
),
'islandora_dublin_core_description' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-dublin-core-description',
// We can add PIDs to the end of this pattern in our preprocess function
// and templates will be able to have have a pid appended to the
// template name to overide a template on a per object basis.
// An example template might be named:
// "islandora-dublin-core-description--islandora-27.tpl.php".
'pattern' => 'islandora_dublin_core_description__',
'variables' => array('islandora_object' => NULL),
),
// Table for install/reinstall content model and collections.
'islandora_solution_pack_table' => array(
'file' => 'includes/solution_packs.inc',
'render element' => 'form',
),
// Overview for manage tab.
'islandora_object_overview' => array(
'file' => 'theme/theme.inc',
'template' => 'theme/islandora-object-overview',
'variables' => array('islandora_object' => NULL),
),
);
}
/**
* Implements hook_permission().
*/
function islandora_permission() {
$permissions = array(
ISLANDORA_VIEW_OBJECTS => array(
'title' => t('View repository objects'),
'description' => t('View objects in the repository. Note: Fedora XACML security policies may override this permission.'),
),
ISLANDORA_ADD_DS => array(
'title' => t('Add datastreams to repository objects'),
'description' => t('Add datastreams to objects in the repository. Note: Fedora XACML security policies may override this position.'),
),
ISLANDORA_METADATA_EDIT => array(
'title' => t('Edit metadata'),
'description' => t('Edit metadata for objects in the repository.'),
),
ISLANDORA_INGEST => array(
'title' => t('Create new repository objects'),
'description' => t('Create new objects in the repository.'),
),
ISLANDORA_PURGE => array(
'title' => t('Permanently remove objects from the repository'),
'description' => t('Permanently remove objects from the repository.'),
),
ISLANDORA_MANAGE_PROPERTIES => array(
'title' => t('Manage object properties'),
'description' => t('Modify object labels, owner IDs, and states.'),
),
ISLANDORA_VIEW_DATASTREAM_HISTORY => array(
'title' => t('View datastream history'),
'description' => t('View all previous versions of a datastream.'),
),
ISLANDORA_REVERT_DATASTREAM => array(
'title' => t('Revert datastream history'),
'description' => t('Revert to a previous version of a datastream.'),
),
ISLANDORA_MANAGE_DELETED_OBJECTS => array(
'title' => t('Manage deleted objects'),
'description' => t('Purge or revert deleted objects.'),
),
ISLANDORA_REGENERATE_DERIVATIVES => array(
'title' => t('Regenerate derivatives'),
'description' => t('Regenerate derivatives for an object or per datastream.'),
),
ISLANDORA_REPLACE_DATASTREAM_CONTENT => array(
'title' => t('Replace datastreams'),
'description' => t('Add new datastream content as latest version.'),
),
ISLANDORA_MANAGE_ORPHANED_OBJECTS => array(
'title' => t('Manage orphaned Islandora objects'),
'description' => t('View a list of orphaned Islandora objects.'),
),
);
if (variable_get('islandora_deny_inactive_and_deleted', FALSE)) {
$permissions[ISLANDORA_ACCESS_INACTIVE_AND_DELETED_OBJECTS] = array(
'title' => t('Access inactive and deleted objects'),
'description' => t('Access objects with a Fedora state of Inactive or Deleted.'),
);
}
return $permissions;
}
/**
* Implements hook_i18n_string_info().
*/
function islandora_i18n_string_info() {
return array(
'islandora' => array(
'title' => t('Islandora'),
'description' => t('Translatable Metadata labels, etc.'),
'format' => FALSE,
'list' => TRUE,
),
);
}
/**
* Implements islandora_i18n_string_list().
*/
function islandora_i18n_string_list($group) {
if ($group == 'islandora') {
return array(
'islandora' => array(
'dc' => array(
'title' => array('label' => 'Title'),
'creator' => array('label' => 'Creator'),
'subject' => array('label' => 'Subject'),
'description' => array('label' => 'Description'),
'publisher' => array('label' => 'Publisher'),
'contributor' => array('label' => 'Contributor'),
'date' => array('label' => 'Date'),
'type' => array('label' => 'Type'),
'format' => array('label' => 'Format'),
'identifier' => array('label' => 'Identifier'),
'source' => array('label' => 'Source'),
'language' => array('label' => 'Language'),
'relation' => array('label' => 'Relation'),
'coverage' => array('label' => 'Coverage'),
),
),
);
}
}
/**
* Renders the print page for the given object.
*
* Modules can either implement preprocess functions to append content onto the
* 'content' variable, or override the display by providing a theme suggestion.
*
* @param AbstractObject $object
* The object.
*
* @return array
* A renderable array.
*/
function islandora_print_object(AbstractObject $object) {
drupal_set_title($object->label);
return theme('islandora_object_print', array('object' => $object));
}
/**
* View print tab access.
*
* Configurable option in islandora configuration.
*
* @param string $op
* String identifying an operation to check. Should correspond to a
* permission declared via hook_permission().
* @param AbstractObject $object
* An object to check for permissions.
*
* @return bool
* TRUE if at least one implementation of hook_islandora_object_access()
* returned TRUE, and no implementation return FALSE; FALSE otherwise, or
* FALSE if 'islandora_show_print_option' is not selected in islandora
* configuraton.
*/
function islandora_print_object_access($op, $object) {
if (!variable_get('islandora_show_print_option', FALSE)) {
return FALSE;
}
$access = islandora_object_access($op, $object);
return $access;
}
/**
* Implements hook_forms().
*/
function islandora_forms($form_id) {
$forms = array();
if (strpos($form_id, 'islandora_solution_pack_form_') !== FALSE) {
$forms[$form_id] = array('callback' => 'islandora_solution_pack_form');
}
return $forms;
}
/**
* Checks whether the user can access the given object.
*
* Checks for repository access, object/datastream existance, namespace access,
* user permissions, content models.
*
* Will check the given user or the user repersented by the GET token parameter,
* failing that it will use the global user.
*
* @global $user
*
* @param mixed $object_or_datastream
* The AbstractObject or AbstractDatastream to test for accessibility, if NULL
* is given the object is assumed to not exist or be inaccessible.
* @param array $permissions
* The required user permissions.
* @param array $content_models
* The required content models.
* @param bool $access_any
* (optional) TRUE to grant access if any single requirement is met from both
* the permissions and content models parameters. FALSE if all requirements
* must be met from both the permissions and content model parameters.
* @param object $user
* (optional) The account to check, if not given check the GET parameters for
* a token to restore the user. If no GET parameter is present use currently
* logged in user.
*
* @return bool
* TRUE if the user is allowed to access this object/datastream, FALSE
* otherwise.
*/
function islandora_user_access($object_or_datastream, array $permissions, $content_models = array(), $access_any = TRUE, $user = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
$is_repository_accessible = &drupal_static(__FUNCTION__);
// If the repository is inaccessible then access always fails.
if (!isset($is_repository_accessible)) {
$is_repository_accessible = islandora_describe_repository();
if (!$is_repository_accessible) {
// Only display the inaccessible message once.
islandora_display_repository_inaccessible_message();
return FALSE;
}
}
if (!$is_repository_accessible || !is_object($object_or_datastream) || empty($permissions)) {
return FALSE;
}
// Determine what has been passed as $object.
if (is_subclass_of($object_or_datastream, 'AbstractObject')) {
$object = $object_or_datastream;
$datastream = NULL;
}
elseif (is_subclass_of($object_or_datastream, 'AbstractDatastream')) {
$datastream = $object_or_datastream;
$object = $datastream->parent;
}
// Determine the user account to test against.
if (!isset($user)) {
$token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
if ($token) {
module_load_include('inc', 'islandora', 'includes/authtokens');
$token_user = islandora_validate_object_token($object->id, $datastream->id, $token);
if ($user) {
$user = user_load($token_user->uid);
}
}
else {
global $user;
}
}
// Check for access.
if ($access_any) {
$has_required_content_models = empty($content_models) ? TRUE : count(array_intersect($object->models, $content_models)) > 0;
if ($has_required_content_models) {
foreach ($permissions as $p) {
if ($datastream !== NULL) {
$check = islandora_datastream_access($p, $datastream, $user);
}
else {
$check = islandora_object_access($p, $object, $user);
}
if ($check) {
return TRUE;
}
}
return FALSE;
}
}
else {
$has_required_content_models = count(array_diff($content_models, $object->models)) == 0;
if ($has_required_content_models) {
foreach ($permissions as $p) {
if ($datastream !== NULL) {
$check = islandora_datastream_access($p, $datastream, $user);
}
else {
$check = islandora_object_access($p, $object, $user);
}
if (!$check) {
return FALSE;
}
}
// Should already have failed if there are no $permissions.
return TRUE;
}
}
return FALSE;
}
/**
* Checks whether the user can access the given object.
*
* Checks for object existance, accessiblitly, namespace permissions,
* and user permissions
*
* @param string $perm
* User permission to test for.
* @param AbstractObject $object
* The object to test, if NULL given the object doesn't exist or is
* inaccessible.
*
* @return bool
* TRUE if the user is allowed to access this object, FALSE otherwise.
*/
function islandora_object_access_callback($perm, $object = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
if (!$object && !islandora_describe_repository()) {
islandora_display_repository_inaccessible_message();
return FALSE;
}
return islandora_object_access($perm, $object);
}
/**
* Checks whether the user can access the given object and datastream.
*
* This function will validate and use a token if present in the GET parameters.
*
* Checks for object existance, accessibility, namespace permissions,
* and user permissions
*/
function islandora_object_datastream_tokened_access_callback($perm, $object = NULL, $datastream = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
// Token validation requires a valid object and PID in order to make a
// potential match in the db.
$token_account = NULL;
if (is_object($object) && is_object($datastream)) {
$token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
if ($token) {
$user = islandora_validate_object_token($object->id, $datastream->id, $token);
if ($user) {
$token_account = user_load($user->uid);
}
}
}
return islandora_datastream_access($perm, $datastream, $token_account);
}
/**
* Checks whether the user can access the given object's manage tab.
*
* Checks for object existance, accessiblitly, namespace permissions,
* and user permissions
*
* @param array $perms
* Array of user permission to test for.
* @param AbstractObject $object
* The object to test, if NULL given the object doesn't exist or is
* inaccessible.
*
* @return bool
* TRUE if the user is allowed to access this object, FALSE otherwise.
*/
function islandora_object_manage_access_callback($perms, $object = NULL) {
module_load_include('inc', 'islandora', 'includes/utilities');
if (!$object && !islandora_describe_repository()) {
islandora_display_repository_inaccessible_message();
return FALSE;
}
$has_access = FALSE;
for ($i = 0; $i < count($perms) && !$has_access; $i++) {
$has_access = $has_access || islandora_object_access($perms[$i], $object);
}
return $has_access;
}
/**
* Renders the given objects manage overview page.
*
* @param AbstractObject $object
* The object to manage.
*
* @return string
* The HTML repersentation of the manage object page.
*/
function islandora_manage_overview_object(AbstractObject $object) {
module_load_include('inc', 'islandora', 'includes/utilities');
$output = islandora_create_manage_overview($object);
$hooks = islandora_build_hook_list(ISLANDORA_OVERVIEW_HOOK, $object->models);
foreach ($hooks as $hook) {
$temp = module_invoke_all($hook, $object);
islandora_as_renderable_array($temp);
if (!empty($temp)) {
arsort($temp);
$output = array_merge_recursive($output, $temp);
}
}
drupal_alter($hooks, $object, $output);
islandora_as_renderable_array($output);
return $output;
}
/**
* 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 AbstractObject $object
* The object to manage.
*
* @return string
* The HTML repersentation of the manage object page.
*/
function islandora_edit_object(AbstractObject $object) {
module_load_include('inc', 'islandora', 'includes/breadcrumb');
module_load_include('inc', 'islandora', 'includes/utilities');
$output = array();
foreach (islandora_build_hook_list(ISLANDORA_EDIT_HOOK, $object->models) as $hook) {
$temp = module_invoke_all($hook, $object);
islandora_as_renderable_array($temp);
if (!empty($temp)) {
$output = array_merge_recursive($output, $temp);
}
}
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);
islandora_as_renderable_array($output);
return $output;
}
/**
* Renders the default manage object page for the given object.
*
* @param AbstractObject $object
* The object used to render the manage object page.
*
* @return array
* The default rendering of the object manage page, indexed at
* 'Default Edit output'.
*/
function islandora_default_islandora_edit_object(AbstractObject $object) {
$output = theme('islandora_default_edit', array('islandora_object' => $object));
return array('Default Edit output' => array('#markup' => $output));
}
/**
* Page callback for the path "islandora".
*
* Redirects to the view of the object indicated by the Drupal variable
* 'islandora_repository_pid'.
*/
function islandora_view_default_object() {
$pid = variable_get('islandora_repository_pid', 'islandora:root');
drupal_goto("islandora/object/$pid");
}
/**
* 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 AbstractObject $object
* The object to view.
*
* @return string
* The html repersentation of this object.
*/
function islandora_view_object(AbstractObject $object) {
module_load_include('inc', 'islandora', 'includes/breadcrumb');
module_load_include('inc', 'islandora', 'includes/utilities');
// Warn if object is inactive or deleted.
if ($object->state != 'A') {
drupal_set_message(t('This object is not active. Metadata may not display correctly.'), 'warning');
}
// Optional pager parameters.
$page_number = (empty($_GET['page'])) ? '1' : $_GET['page'];
$page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize'];
$output = array();
$hooks = islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $object->models);
foreach ($hooks 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);
islandora_as_renderable_array($temp);
if (!empty($temp)) {
$output = array_merge_recursive($output, $temp);
}
}
if (empty($output)) {
// No results, use the default view.
$output = islandora_default_islandora_view_object($object);
}
arsort($output);
drupal_alter($hooks, $object, $output);
islandora_as_renderable_array($output);
return $output;
}
/**
* This will prepare an object to be printed.
*
* By default all fedora objects can print DC record data. Solution packs that
* wish to modify the data to be printed can implement
* hook_islandora_view_print_object or hook_islandora_metadata_display_info.
*
* @param AbstractObject $object
* The object to print.
*
* @return string
* An HTML representation of this object.
*/
function islandora_printer_object(AbstractObject $object) {
$output = array();
$temp_arr = array();
// Dispatch print hook.
foreach (islandora_build_hook_list(ISLANDORA_PRINT_HOOK, $object->models) as $hook) {
$temp = module_invoke_all($hook, $object);
islandora_as_renderable_array($temp);
if (!empty($temp)) {
$temp_arr = array_merge_recursive($temp_arr, $temp);
}
}
$output = islandora_default_islandora_printer_object($object, drupal_render($temp_arr));
arsort($output);
islandora_as_renderable_array($output);
// Prompt to print.
drupal_add_js('jQuery(document).ready(function () { window.print(); });', 'inline');
return $output;
}
/**
* Title callback for drupal title.
*
* Changes the drupal title to be the objects label.
*
* @param AbstractObject $object
* The object to view.
*
* @return string
* The objects label. Note that we return the raw value to prevent
* double encoding, as we expect drupal_set_title() to check_plain() down
* the road.
*/
function islandora_drupal_title(AbstractObject $object) {
module_load_include('inc', 'islandora', 'includes/breadcrumb');
drupal_set_breadcrumb(islandora_get_breadcrumbs($object));
return $object->label;
}
/**
* Renders the default view object page for the given object.
*
* @param AbstractObject $object
* 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));
return array('Default output' => array('#markup' => $output));
}
/**
* Append the image alter to the printable form.
*
* @param AbstractObject $object
* The fedora object to print.
* @param string $alter
* The string representation of the themed viewable object.
*
* @return array
* A renderable array
*/
function islandora_default_islandora_printer_object($object, $alter) {
module_load_include('inc', 'islandora', 'includes/utilities');
module_load_include('inc', 'islandora', 'includes/datastream');
module_load_include('inc', 'islandora', 'includes/metadata');
$path = drupal_get_path('module', 'islandora');
drupal_add_css($path . '/css/islandora.print.css');
$islandora_object = islandora_object_load($object->id);
$repository = $islandora_object->repository;
try {
$dc = $islandora_object['DC']->content;
$dc_object = DublinCore::importFromXMLString($dc);
}
catch (Exception $e) {
drupal_set_message(t('Error retrieving object %s %t', array('%s' => $islandora_object->id, '%t' => $e->getMessage())), 'error', FALSE);
}
$metadata = islandora_retrieve_metadata_markup($object, TRUE);
$variables = isset($dc_object) ? $dc_object->asArray() : array();
$output = theme('islandora_object_print_object', array(
'object' => $object,
'dc_array' => $variables,
'metadata' => $metadata,
'islandora_content' => $alter));
return array('Default output' => array('#markup' => $output));
}
/**
* Just a wrapper around fetchings the IslandoraTuque object.
*
* Includes some very basic error logging.
*
* @param object $user
* The user to connect as.
* @param string $url
* The URL to connect to.
*
* @return IslandoraTuque
* A IslandoraTuque instance
*/
function islandora_get_tuque_connection($user = NULL, $url = NULL) {
module_load_include('inc', 'islandora', 'includes/tuque');
$tuque = &drupal_static(__FUNCTION__);
if (!$tuque) {
if (IslandoraTuque::exists()) {
try {
$tuque = new IslandoraTuque($user, $url);
}
catch (Exception $e) {
drupal_set_message(t('Unable to connect to the repository %e', array('%e' => $e)), 'error');
}
}
else {
return NULL;
}
}
return $tuque;
}
/**
* Loads the object from the given ID if possible.
*
* Often used to get a connection and return an object for the one specified in
* the menu path as '%islandora_object'.
*
* @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) {
$tuque = islandora_get_tuque_connection();
if ($tuque) {
try {
return $tuque->repository->getObject(urldecode($object_id));
}
catch (Exception $e) {
// Check to see if tuque failure is due to invalid PID.
module_load_include('inc', 'islandora', 'includes/utilities');
if (!islandora_is_valid_pid($object_id)) {
return FALSE;
}
elseif ($e->getCode() == '404') {
return FALSE;
}
else {
return NULL;
}
}
}
else {
IslandoraTuque::getError();
}
// Assuming access denied in all other cases for now.
return NULL;
}
/**
* Load the the object using a token if passed as a GET parameter.
*
* A helper function to get a connection and return an object using a token
* for authentication.
*
* @param string $object_id
* The PID of an object in the menu path identified by
* '%islandora_tokened_object'.
* @param array $map
* Used to extract the Fedora object's DSID at $map[4].
*
* @return FedoraObject
* A token authenticated object. @see islandora_object_load
*/
function islandora_tokened_object_load($object_id, $map) {
if (array_key_exists('token', $_GET)) {
$token = filter_input(INPUT_GET, 'token', FILTER_SANITIZE_STRING);
if ($token) {
module_load_include('inc', 'islandora', 'includes/authtokens');
$token_user = islandora_validate_object_token($object_id, $map[4], $token);
$token_user = $token_user ? user_load($token_user->uid) : NULL;
islandora_get_tuque_connection($token_user);
}
}
return islandora_object_load($object_id);
}
/**
* Fetches a datastream object.
*
* This datastream load must take in arguments in a different
* order than the usual islandora_datastream_load. This is because
* the function islandora_tokened_object_load needs DSID. It uses
* the path %map to avoid duplicate parameters. The menu system
* passes 'load arguments' to both islandora_tokened_object_load
* and this function and the first parameter is positional with the token.
* An alternative:
* islandora_tokened_object_load(PID, DSID, PID)
* islandora_tokened_datastream_load(DSID, DSID, PID)
*
* @param mixed $datastream_id
* %islandora_tokened_datastream @see islandora_datastream_load
* @param array $map
* Used to extract the Fedora object's PID at $map[2].
*
* @return FedoraDatastream
* A datastream from Fedora.
*
* @see islandora_datastream_load
*/
function islandora_tokened_datastream_load($datastream_id, $map) {
return islandora_datastream_load($datastream_id, $map[2]);
}
/**
* Fetches a datastream object.
*
* A helper function to get an datastream specified as '%islandora_datastream'
* for the object specified in the menu path as '%islandora_object'.
*
* 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 mixed $object_id
* The object to load the datastream from. This can be a Fedora PID or
* an instantiated IslandoraAbstractObject as it implements __toString()
* returning the PID.
*
* @return FedoraDatastream
* If the given datastream ID exists then this returns a FedoraDatastream
* object, otherwise it returns NULL which triggers drupal_page_not_found().
*/
function islandora_datastream_load($datastream_id, $object_id) {
$object = is_object($object_id) ? $object_id : islandora_object_load($object_id);
if (!$object) {
return NULL;
}
return $object[$datastream_id];
}
/**
* Fetches the given datastream version from its datastream.
*
* 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 name="Collection" version="2" ...
*
* @param AbstractObject $object
* The Object the datastream belongs to.
* @param string $dsid
* The ID of the datastream.
* @param string $datastream_file
* The datastream's content.
*
* @return int
* The datastreams version if found, NULL otherwise.
*/
function islandora_get_islandora_datastream_version($object = NULL, $dsid = NULL, $datastream_file = NULL) {
$return = NULL;
// @TODO, need better check for $object
if ($object && $object[$dsid]) {
$doc = simplexml_load_string($object[$dsid]->content);
}
elseif (!empty($datastream_file)) {
$doc = simplexml_load_file($datastream_file);
}
if (!empty($doc) && $version = (int) $doc->attributes()->version) {
$return = $version;
}
return $return;
}
/**
* Implements hook_islandora_required_objects().
*/
function islandora_islandora_required_objects(IslandoraTuque $connection) {
$module_path = drupal_get_path('module', 'islandora');
// Root Collection.
$root_collection = $connection->repository->constructObject('islandora:root');
$root_collection->owner = 'fedoraAdmin';
$root_collection->label = 'Top-level Collection';
$root_collection->models = 'islandora:collectionCModel';
// Collection Policy Datastream.
$datastream = $root_collection->constructDatastream('COLLECTION_POLICY', 'M');
$datastream->label = 'Collection policy';
$datastream->mimetype = 'application/xml';
$datastream->setContentFromFile("$module_path/xml/islandora_collection_policy.xml", FALSE);
$root_collection->ingestDatastream($datastream);
// TN Datastream.
$datastream = $root_collection->constructDatastream('TN', 'M');
$datastream->label = 'Thumbnail';
$datastream->mimetype = 'image/png';
$datastream->setContentFromFile("$module_path/images/folder.png", FALSE);
$root_collection->ingestDatastream($datastream);
return array(
'islandora' => array(
'title' => 'Islandora',
'objects' => array($root_collection),
),
);
}
/**
* Implements hook_islandora_undeleteable_datastreams().
*/
function islandora_islandora_undeletable_datastreams(array $models) {
return array('DC', 'RELS-EXT');
}
/**
* Ingest the given object.
*
* @param AbstractObject $object
* An ingestable FedoraObject.
*
* @return FedoraObject
* The ingested FedoraObject.
*/
function islandora_add_object(AbstractObject &$object) {
return $object->repository->ingestObject($object);
}
/**
* Creates a new object with the same properties as the old.
*
* @todo Make Tuque objects support cloneing.
*
* @param AbstractObject $object
* An existing or new Fedora Object.
*
* @return AbstractObject
* The new Fedora Object with properties identical to the object given. This
* returned object is not automatically ingested.
*/
function islandora_copy_object(AbstractObject $object) {
$clone = $object->repository->constructObject($object->id);
$object_properties = array(
'state',
'createdDate',
'lastModifiedDate',
'label',
'owner',
'logMessage',
);
// Copy Properties.
foreach ($object_properties as $property) {
if (isset($object->$property)) {
$clone->$property = $object->$property;
}
}
// Copy Datastreams.
foreach ($object as $dsid => $datastream) {
if (empty($clone[$dsid])) {
$clone->ingestDatastream($datastream);
}
else {
// Get the content into a file, and add the file.
$temp_file = drupal_tempnam('temporary://', 'datastream');
$datastream->getContent($temp_file);
$clone[$dsid]->setContentFromFile($temp_file);
drupal_unlink($temp_file);
}
}
return $clone;
}
/**
* Delete's or purges the given object.
*
* @param AbstractObject $object
* An object to delete.
*
* @return bool
* TRUE if successful, FALSE otherwise.
*/
function islandora_delete_object(AbstractObject &$object) {
try {
$object->repository->purgeObject($object->id);
$object = NULL;
return TRUE;
}
catch (Exception $e) {
// Exception message gets logged in Tuque Wrapper.
return FALSE;
}
}
/**
* Delete's or purges the given datastream.
*
* @throws Exception
* Which types are undefined, but more than likely because of the hooks
* there will be several kinds.
*
* @param AbstractDatastream $datastream
* The datastream to delete.
*
* @return bool
* TRUE if successful, FALSE otherwise.
*/
function islandora_delete_datastream(AbstractDatastream &$datastream) {
$object = $datastream->parent;
return $object->purgeDatastream($datastream->id);
}
/**
* Implements hook_cron().
*/
function islandora_cron() {
module_load_include('inc', 'islandora', 'includes/authtokens');
islandora_remove_expired_tokens();
}
/**
* Implements hook_entity_info().
*
* Some boiler-plate for Tokens (the module, not our authentication work-
* around).
*/
function islandora_entity_info() {
$entities = array();
$entities['islandora_object'] = array(
'label' => t('Islandora Object'),
'controller class' => 'IslandoraObjectEntityController',
'fieldable' => FALSE,
'entity keys' => array(
'id' => 'id',
'label' => 'label',
),
);
$entities['islandora_datastream'] = array(
'label' => t('Islandora Datastream'),
'fieldable' => FALSE,
'entity keys' => array(
'id' => 'id',
'label' => 'label',
),
);
return $entities;
}
/**
* Implements hook_entity_property_info().
*
* Details the tokens which will be available on the given object.
*/
function islandora_entity_property_info() {
$info = array();
$object_properties = &$info['islandora_object']['properties'];
$datastream_properties = &$info['islandora_datastream']['properties'];
$object_properties['id'] = array(
'type' => 'text',
'label' => t('ID'),
'description' => t('The identifier of the object.'),
);
$object_properties['label'] = array(
'type' => 'text',
'label' => t('Object Label'),
'description' => t('The label of the object.'),
'setter callback' => 'islandora_entity_set_property',
);
$object_properties['owner'] = array(
'type' => 'text',
'label' => t('Object Owner'),
'description' => t('The name of the owner of the object.'),
'setter callback' => 'islandora_entity_set_property',
);
$object_properties['state'] = array(
'type' => 'text',
'label' => t('Object State'),
'description' => t('An initial representing the state of the object.'),
'setter callback' => 'islandora_entity_set_property',
);
$object_properties['models'] = array(
'type' => 'list<text>',
'label' => t('Content Models'),
'description' => t('The list of content models which the object has.'),
'setter callback' => 'islandora_entity_set_property',
);
$object_properties['createdDate'] = array(
'type' => 'text',
'label' => t('Created Date'),
'description' => t('When the object was created.'),
);
$datastream_properties['id'] = array(
'type' => 'text',
'label' => t('ID'),
'description' => t('The identifier of the datastream.'),
);
$datastream_properties['state'] = array(
'type' => 'text',
'label' => t('Datastream State'),
'description' => t('An initial representing the state of the datastream.'),
'setter callback' => 'islandora_entity_set_property',
);
$datastream_properties['label'] = array(
'type' => 'text',
'label' => t('Datastream Label'),
'description' => t('The label of the datastream.'),
'setter callback' => 'islandora_entity_set_property',
);
$datastream_properties['mimetype'] = array(
'type' => 'text',
'label' => t('MIME type'),
'description' => t('Content type of the datastream.'),
'setter callback' => 'islandora_entity_set_property',
);
$datastream_properties['parent'] = array(
'type' => 'islandora_object',
'label' => t('Object'),
'description' => t('The Tuque object on which this datastream exists.'),
);
$datastream_properties['content'] = array(
'type' => 'text',
'label' => t('Datastream content'),
'description' => t('The contents of the datastream; only useful when the content is textual.'),
'setter callback' => 'islandora_entity_set_property',
);
return $info;
}
/**
* Implements hook_file_mimetype_mapping_alter().
*
* Grab custom Islandora mime type list
* and add any missing ext/mimes to the Drupal mapping
*/
function islandora_file_mimetype_mapping_alter(&$mapping) {
module_load_include('inc', 'islandora', 'includes/mimetype.utils');
$types = islandora_mime_mapping();
$diff = array_diff_key($types, $mapping['extensions']);
foreach ($diff as $ext => $mime) {
$mapping['mimetypes'][] = $mime;
end($mapping['mimetypes']);
$mapping['extensions'][$ext] = key($mapping['mimetypes']);
}
// Get the current XML mapping and unset it so it comes last when we do our
// reverse when getting mimetypes from extensions for use in downloads.
// @see islandora_get_extension_for_mimetype.
$xml_int = $mapping['extensions']['xml'];
unset($mapping['extensions']['xml']);
$mapping['extensions']['xml'] = $xml_int;
}
/**
* Hookable object access callback.
*
* @param string $op
* String identifying an operation to check. Should correspond to a
* permission declared via hook_permission().
* @param AbstractObject $object
* An object to check for permissions.
* @param object $user
* An optional loaded user object. Defaults to the global $user.
*
* @return bool
* TRUE if at least one implementation of hook_islandora_object_access()
* returned TRUE, and no implementation return FALSE; FALSE otherwise.
*/
function islandora_object_access($op, $object, $user = NULL) {
$cache = &drupal_static(__FUNCTION__);
if (!is_object($object)) {
// The object could not be loaded... Presumably, we don't have
// permission.
return FALSE;
}
if ($user === NULL) {
global $user;
}
// Populate the cache on a miss.
if (!isset($cache[$op][$object->id][$user->uid])) {
module_load_include('inc', 'islandora', 'includes/utilities');
$results = islandora_invoke_hook_list('islandora_object_access', $object->models, array(
$op,
$object,
$user,
));
// Nothing returned FALSE, and something returned TRUE.
$cache[$op][$object->id][$user->uid] = (!in_array(FALSE, $results, TRUE) && in_array(TRUE, $results, TRUE));
}
return $cache[$op][$object->id][$user->uid];
}
/**
* Implements hook_islandora_object_access().
*
* Denies according to PID namespace restrictions, then passes or denies
* according to core Drupal permissions according to user_access().
*/
function islandora_islandora_object_access($op, $object, $user) {
module_load_include('inc', 'islandora', 'includes/utilities');
$access = (islandora_namespace_accessible($object->id) && user_access($op, $user));
if (($object->state != 'A') && variable_get('islandora_deny_inactive_and_deleted', FALSE)) {
$access = ($access && user_access(ISLANDORA_ACCESS_INACTIVE_AND_DELETED_OBJECTS, $user));
}
return $access;
}
/**
* Hookable access callback for datastreams.
*
* Positive permissions on object access suggests on the datastream.
*/
function islandora_datastream_access($op, $datastream, $user = NULL) {
$cache = &drupal_static(__FUNCTION__);
if (!is_object($datastream)) {
// The object could not be loaded... Presumably, we don't have
// permission.
return NULL;
}
if ($user === NULL) {
global $user;
}
// Populate the cache on a miss.
if (!isset($cache[$op][$datastream->parent->id][$datastream->id][$user->uid])) {
module_load_include('inc', 'islandora', 'includes/utilities');
$datastream_results = islandora_invoke_hook_list('islandora_datastream_access', $datastream->parent->models, array(
$op,
$datastream,
$user,
));
// The datastream check returned no FALSE, and at least one TRUE.
$cache[$op][$datastream->parent->id][$datastream->id][$user->uid] = (
!in_array(FALSE, $datastream_results, TRUE) && in_array(TRUE, $datastream_results, TRUE)
);
}
return $cache[$op][$datastream->parent->id][$datastream->id][$user->uid];
}
/**
* Implements hook_islandora_basic_collection_get_query_filters().
*/
function islandora_islandora_basic_collection_get_query_filters() {
module_load_include('inc', 'islandora', 'includes/utilities');
$enforced = variable_get('islandora_namespace_restriction_enforced', FALSE);
if ($enforced) {
$namespace_array = islandora_get_allowed_namespaces();
$namespace_sparql = implode('|', $namespace_array);
return array('islandora_namespace_restrictions' => format_string('regex(str(?object), "info:fedora/(!namespaces):")', array('!namespaces' => $namespace_sparql)));
}
}
/**
* Implements hook_islandora_object_ingested().
*
* On object ingestion we call the case of source_dsid being NULL only as
* the islandora_islandora_datastream_ingested hook will handle the cases
* where specific values of source_dsid can occur.
*/
function islandora_islandora_object_ingested(AbstractObject $object) {
module_load_include('inc', 'islandora', 'includes/derivatives');
// Defer derivatives if necessary.
if (islandora_get_defer_derivatives_flag($object)) {
return;
}
islandora_run_derivatives($object, NULL);
islandora_conditionally_clear_cache();
}
/**
* Implements hook_islandora_object_modified().
*/
function islandora_islandora_object_modified(AbstractObject $object) {
islandora_conditionally_clear_cache();
}
/**
* Implements hook_islandora_datastream_ingested().
*
* When a datastream is ingested we filter the derivatives on source_dsid being
* equal to the current ingested datastream's id.
*/
function islandora_islandora_datastream_ingested(AbstractObject $object, AbstractDatastream $datastream) {
module_load_include('inc', 'islandora', 'includes/derivatives');
// Defer derivatives if necessary.
if (islandora_get_defer_derivatives_flag($object)) {
return;
}
islandora_run_derivatives($object, $datastream->id);
islandora_conditionally_clear_cache();
}
/**
* Implements hook_islandora_datastream_modified().
*
* When a datastream is modified we filter the derivatives on source_dsid being
* equal to the current ingested datastream's id. Force is set to TRUE such that
* existing derivatives will be updated to reflect the change in the source.
*/
function islandora_islandora_datastream_modified(AbstractObject $object, AbstractDatastream $datastream, $params) {
module_load_include('inc', 'islandora', 'includes/derivatives');
$params += array(
'dsid' => $datastream->id,
);
$logging_results = islandora_do_derivatives($object, array(
'source_dsid' => $datastream->id,
'force' => TRUE,
'ds_modified_params' => $params,
));
islandora_derivative_logging($logging_results);
islandora_conditionally_clear_cache();
}
/**
* Implements hook_islandora_object_purged().
*/
function islandora_islandora_object_purged($pid) {
islandora_conditionally_clear_cache();
}
/**
* Implements hook_islandora_datastream_purged().
*/
function islandora_islandora_datastream_purged(AbstractObject $object, $dsid) {
islandora_conditionally_clear_cache();
}
/**
* Implements hook_form_simpletest_test_form_alter().
*/
function islandora_form_simpletest_test_form_alter(array &$form) {
module_load_include('inc', 'simpletest', 'simpletest.pages');
module_load_include('inc', 'islandora', 'tests/includes/test_utility_abstraction');
$configuration = IslandoraTestUtilityClass::getTestConfiguration();
$filter_path = $configuration['drupal_filter_file'];
$filter_status = is_writable($filter_path);
if ($filter_status) {
$filter_status_message = theme_image(array('path' => 'misc/watchdog-ok.png', 'attributes' => array())) . " ";
$filter_status_message .= t("Drupal filter at <strong>@filter_path</strong> is writable by the server.", array(
'@filter_path' => $filter_path,
));
}
else {
$filter_status_message = theme_image(array('path' => 'misc/watchdog-error.png', 'attributes' => array())) . " ";
$filter_status_message .= t("Drupal filter at <strong>@filter_path</strong> is not writable by the server. Please make sure your webserver has permission to write to the Drupal filter. If the path given is incorrect, you will need to change it in your server's test config file, located in the Islandora module's 'tests' folder as test_config.ini or default.test_config.ini.", array(
'@filter_path' => $filter_path,
));
}
$form['tests'] = array(
'#type' => 'fieldset',
'#title' => t('Tests'),
'#description' => t("Select the test(s) or test group(s) you would like to run, and click <em>Run tests</em>.<p>NOTE: Tests in groups prefixed with <em>Islandora</em> generally require a configuration file, found in the Islandora module 'tests' folder, as well as the use of the Islandora Drupal filter. Before any tests are run, please ensure that your web server has the appropriate permissions to alter the drupal-filter.xml file in your Fedora config folder. Your original Islandora Drupal filter configuration will NOT be overwritten by tests; HOWEVER, if PHP exits abnormally before the filter is reset, please use the 'Repair Drupal Filter' button below.</p><p><em>Drupal Filter Write Status:</em> !filter_status_message</p>", array(
'!filter_status_message' => $filter_status_message,
)),
);
$form['tests']['table'] = array(
'#theme' => 'simpletest_test_table',
);
// Generate the list of tests arranged by group.
$groups = simpletest_test_get_all();
foreach ($groups as $group => $tests) {
$form['tests']['table'][$group] = array(
'#collapsed' => TRUE,
);
foreach ($tests as $class => $info) {
$form['tests']['table'][$group][$class] = array(
'#type' => 'checkbox',
'#title' => filter_xss($info['name']),
'#description' => filter_xss($info['description']),
);
if (is_subclass_of($class, 'IslandoraWebTestCase', TRUE) && !$filter_status) {
$form['tests']['table'][$group][$class]['#disabled'] = TRUE;
}
}
}
// Operation buttons.
$form['tests']['op'] = array(
'#type' => 'submit',
'#value' => t('Run tests'),
);
$form['reset'] = array(
'#type' => 'fieldset',
'#collapsible' => FALSE,
'#collapsed' => FALSE,
'#title' => t('Repair Islandora Drupal Filter'),
'#description' => t('Attempts to repair the Islandora Drupal filter if a test that alters the Drupal filter has crashed. This is also intended for developers when creating tests built using the IslandoraWebTestCase class.'),
);
$form['reset']['op'] = array(
'#type' => 'submit',
'#value' => t('Repair Drupal Filter'),
'#submit' => array('islandora_repair_drupal_filter'),
);
}
/**
* Removes simpletest entries from the Drupal filter.
*/
function islandora_repair_drupal_filter() {
// Grab the config.
module_load_include('inc', 'islandora', 'tests/utilities/test_utility_abstraction');
try {
$configuration = IslandoraTestUtilityClass::getTestConfiguration();
}
catch (Exception $e) {
drupal_set_message(t("Error parsing test configuration: %e", array('%e' => $e)), 'error');
return FALSE;
}
// Xpath to the filter 'sql' elements.
$drupal_filter_dom = new DOMDocument();
$drupal_filter_dom->loadXML(file_get_contents($configuration['drupal_filter_file']));
$drupal_filter_xpath = new DOMXPath($drupal_filter_dom);
// Blow out the simpletest stuff.
$entries = 0;
foreach ($drupal_filter_xpath->query('//sql') as $sql) {
if (strpos($sql->nodeValue, 'simpletest') !== FALSE) {
$parent = $sql->parentNode;
$root = $parent->parentNode;
$parent->removeChild($sql);
$root->removeChild($parent);
$entries++;
}
}
file_put_contents($configuration['drupal_filter_file'], $drupal_filter_dom->saveXML());
if ($entries == 0) {
drupal_set_message(t("No simpletest entries were found in the Drupal filter."));
}
else {
drupal_set_message(format_plural($entries, "Removed 1 simpletest entry from the Drupal filter.", "Removed @count simpletest entries from the Drupal filter."));
}
}
/**
* Implements hook_islandora_metadata_display_info().
*/
function islandora_islandora_metadata_display_info() {
return array(
'dublin_core' => array(
'label' => t('Dublin Core'),
'description' => t('Dublin Core metadata'),
'metadata callback' => 'islandora_metadata_display_callback',
'description callback' => 'islandora_metadata_description_callback',
),
);
}
/**
* Implements hook_islandora_datastream_access().
*/
function islandora_islandora_datastream_access($op, AbstractDatastream $datastream, $user) {
module_load_include('inc', 'islandora', 'includes/utilities');
$result = islandora_object_access($op, $datastream->parent, $user);
if ($result && $op == ISLANDORA_REGENERATE_DERIVATIVES) {
module_load_include('inc', 'islandora', 'includes/derivatives');
$applicable_hook = FALSE;
$object = $datastream->parent;
$hooks = islandora_invoke_hook_list(ISLANDORA_DERIVATIVE_CREATION_HOOK, $object->models, array($object));
$hooks = islandora_filter_derivatives($hooks, array('force' => TRUE), $object);
foreach ($hooks as $hook) {
if (isset($hook['destination_dsid']) && $hook['destination_dsid'] == $datastream->id &&
(is_null($hook['source_dsid']) || islandora_datastream_access(ISLANDORA_VIEW_OBJECTS, $object[$hook['source_dsid']], $user))) {
$applicable_hook = TRUE;
break;
}
}
if (!$applicable_hook) {
$result = FALSE;
}
}
return $result;
}
/**
* Access for submenu items.
*
* @param string $package_name
* Name of the package
*
* @return bool
* Access granted
*/
function islandora_find_package($package_name) {
$results = system_get_info('module');
$found = FALSE;
foreach ($results as $name => $values) {
if ($values['package'] == $package_name) {
$found = TRUE;
break;
}
}
return $found && user_access('administer site configuration');
}
/**
* Helper function for ingest steps and batches.
*
* When batches within batches are triggered within ingest steps
* the submit handler becomes out of scope. When it becomes time to execute the
* submit the function cannot be found and fails. This pre-submit is to
* get around this problem.
*
* @see https://www.drupal.org/node/2300367
*
* @see https://www.drupal.org/node/1300928
*/
function islandora_ingest_form_pre_submit($form, &$form_state) {
module_load_include('inc', 'islandora', 'includes/ingest.form');
}
/**
* Implements hook_menu_local_tasks_alter().
*/
function islandora_menu_local_tasks_alter(&$data, $router_item, $root_path) {
if (strpos($root_path, 'islandora/object/%') === 0) {
if (isset($data['tabs'][0]['output'])) {
foreach ($data['tabs'][0]['output'] as $key => &$tab) {
if ($tab['#link']['path'] == 'islandora/object/%/print_object') {
if ($root_path == 'islandora/object/%') {
$islandora_path = drupal_get_path('module', 'islandora');
$tab['#prefix'] = '<li class="islandora-print">';
$tab['#suffix'] = '</li>';
$tab['#theme'] = 'link';
$tab['#text'] = theme('image', array(
'path' => "$islandora_path/images/print-icon.png",
'alt' => t('Print Object'),
'attributes' => array(
'id' => 'print_btn',
),
));
$tab['#path'] = "{$router_item['href']}/print_object";
$tab['#options'] = array(
'attributes' => array(),
'html' => TRUE,
);
}
else {
unset($data['tabs'][0]['output'][$key]);
break;
}
}
}
}
}
}
/**
* Implements hook_islandora_object_alter().
*/
function islandora_islandora_object_alter(AbstractObject $object, array &$context) {
// Prevent derivative creation during ingest if var is set.
if ($context['action'] == 'ingest' && variable_get('islandora_defer_derivatives_on_ingest', FALSE)) {
module_load_include('inc', 'islandora', 'includes/derivatives');
islandora_set_defer_derivatives_flag($object);
}
}
/**
* Set property on an entity.
*
* Drupal's usual entity_property_verbatim_set() does not work, as tries to use
* ArrayAccess stuff instead of setting properties directly.
*/
function islandora_entity_set_property(&$data, $name, $value, $langcode) {
if (is_object($data)) {
$data->$name = $value;
}
}
/**
* Conditionally clear cache to alleviate cache thrashing.
*
* If we are responding to form submission or during a batch which ingested,
* modified or purged an object or datastream, we want to be sure to clear the
* cache at the end of the process.
*/
function islandora_conditionally_clear_cache() {
static $clear;
if (!isset($clear)) {
$clear =& drupal_static(__FUNCTION__, FALSE);
}
if ($clear || !variable_get('cache', 0)) {
// Already set, no need to do so again, or page caching is disabled... Let's
// avoid a call to attempt to clear it.
return;
}
$functions = array(
// Object changes in response to a form.
'form_execute_handlers' => 'islandora_cache_clear_all',
// Object changes in response to a batch. Note that this will not match on
// a drush batch, as drush uses a different set of functions to run
// batches. We intentionally do not clear batches in response to drush
// batches, since they are not in response to GUI actions.
'_batch_process' => 'islandora_schedule_cache_clear_for_batch',
);
$options = (version_compare(PHP_VERSION, '5.3.6', '>=') ? DEBUG_BACKTRACE_IGNORE_ARGS & ~DEBUG_BACKTRACE_PROVIDE_OBJECT : FALSE);
foreach (debug_backtrace($options) as $frame) {
$function_name = strtolower($frame['function']);
if (isset($functions[$function_name])) {
$clear = TRUE;
$function = $functions[$function_name];
$function();
return;
}
}
}
/**
* Clear the page and block caches at the end of the request.
*/
function islandora_cache_clear_all() {
// Advanced "static" handling, as this may be called fairly often.
static $clear;
if (isset($clear)) {
$clear =& drupal_static(__FUNCTION__, FALSE);
}
if (!$clear) {
$clear = TRUE;
drupal_register_shutdown_function('cache_clear_all');
}
}
/**
* Set a batch to clear the page and block caches.
*/
function islandora_schedule_cache_clear_for_batch() {
$batch =& batch_get();
static $scheduled;
$scheduled = isset($scheduled) || isset($batch['islandora_cache_clear_scheduled']);
if ($scheduled || !isset($batch['id'])) {
// We do not wish to do anything if we are either already scheduled or the
// batch is not running.
return;
}
$clear_batch = array(
'operations' => array(
array('islandora_cache_clear_all', array()),
),
);
batch_set($clear_batch);
// Set our flag, to avoid setting the batch multiple times during multiple
// iterations/operations of a single batch.
$batch['islandora_cache_clear_scheduled'] = TRUE;
}
/**
* Implements hook_islandora_get_breadcrumb_query_predicates().
*/
function islandora_islandora_get_breadcrumb_query_predicates(AbstractObject $object) {
return array(
'info:fedora/fedora-system:def/relations-external#isPartOf',
'info:fedora/fedora-system:def/relations-external#isMemberOfCollection',
'info:fedora/fedora-system:def/relations-external#isMemberOf',
);
}
/**
* Provides information for the object manage page.
*
* @param AbstractObject $object
* The object being managed.
*
* @return array
* themed output
*/
function islandora_create_manage_overview(AbstractObject $object) {
$output = theme('islandora_object_overview', array('islandora_object' => $object));
return array('cmodels' => $output);
}
/**
* Implements hook_islandora_breadcrumbs_backends().
*/
function islandora_islandora_breadcrumbs_backends() {
return array(
ISLANDORA_BREADCRUMB_LEGACY_BACKEND => array(
'title' => t('Resource Index - Default'),
// Callback not needed as this is our legacy process and the
// default incase anything goes wrong.
),
);
}
/**
* Implements hook_islandora_solution_pack_child_relationships
*/
function islandora_islandora_solution_pack_child_relationships($cmodels) {
// Return empty arrays from core implementation so that these keys always
// exist when the hook is called, even if no module responds.
return array('predicate' => array(), 'prefix' => array());
}
You can’t perform that action at this time.