Drupal modules for browsing and managing Fedora-based digital repositories.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

744 lines
26 KiB

<?php
/**
* @file
*
* This file contains all admin and callback functions for solution pack
* management.
*/
/**
* Solution pack admin page callback.
*/
function islandora_solution_packs_admin() {
module_load_include('inc', 'islandora', 'includes/utilities');
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 ' .
'<a href="@config_url" title="Islandora configuration page">Islandora configuration</a> page.',
array('@config_url' => url('admin/islandora/configure')));
drupal_set_message($message, 'error');
}
$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) {
switch ($field) {
case 'title':
$solution_pack_name = $value;
break;
case 'objects':
$objects = $value;
break;
}
}
$form_array = drupal_get_form('islandora_solution_pack_form_' . $solution_pack_module, $solution_pack_module, $solution_pack_name, $objects);
$output .= drupal_render($form_array);
}
return $output;
}
/**
* Solution pack admin page
*/
function islandora_solution_pack_form($form, &$form_state, $solution_pack_module, $solution_pack_name, $objects = array()) {
global $base_url;
$needs_update = FALSE;
$needs_install = FALSE;
$could_not_connect = FALSE;
$form = array();
$form['solution_pack'] = array(
'#type' => 'fieldset',
'#collapsible' => FALSE,
'#collapsed' => FALSE,
'#attributes' => array('class' => array('islandora-solution-pack-fieldset')),
);
// adding values
$form['solution_pack']['solution_pack_module'] = array(
'#type' => 'value',
'#value' => $solution_pack_module,
);
$form['solution_pack']['solution_pack_name'] = array(
'#type' => 'value',
'#value' => $solution_pack_name,
);
$form['solution_pack']['objects'] = array(
'#type' => 'value',
'#value' => $objects,
);
$table_header = array(t('Label'), t('PID'), t('Status'));
$table_rows = array();
foreach ($objects as $object) {
$datastreams = NULL;
if (isset($object['pid'])) {
$pid = $object['pid'];
$table_row = array();
$object_status = islandora_check_object_status($object);
switch ($object_status) {
case 'up_to_date':
$object_status = t('Up-to-date');
break;
case 'missing':
$object_status = t('Missing');
$needs_install = TRUE;
break;
case 'missing_datastream':
$object_status = t('Missing datastream');
$needs_update = TRUE;
break;
case 'out_of_date':
$object_status = t('Out-of-date');
$needs_update = TRUE;
break;
case 'could_not_connect':
$object_status = t('Could not connect');
$could_not_connect = TRUE;
break;
}
if ($needs_install OR $could_not_connect) {
$label = $object['label'] ? $object['label'] : '';
}
else {
$label = $object['label'] ? l($object['label'], $base_url . '/islandora/object/' . $pid) : '';
}
$table_row[] = $label;
$table_row[] = $pid;
$table_row[] = $object_status;
$table_rows[] = $table_row;
}
}
// title
if (!$form_state['submitted']) {
$form['solution_pack']['solution_pack_label'] = array(
'#markup' => filter_xss($solution_pack_name),
'#prefix' => '<h3>',
'#suffix' => '</h3>',
);
$form['solution_pack']['install_status'] = array(
'#markup' => '<strong>' . t('Object status:') . '&nbsp;</strong>',
'#prefix' => '<div class="islandora-solution-pack-install-status">',
'#suffix' => '</div>',
);
if (!$needs_install AND !$needs_update AND !$could_not_connect) {
$form['solution_pack']['install_status']['#markup'] .= ' ' . theme('image', array('path' => 'misc/watchdog-ok.png')) . ' ' . t('All required objects are installed and up-to-date.');
$submit_button_text = t("Force reinstall objects");
}
elseif ($needs_install) {
$form['solution_pack']['install_status']['#markup'] .= ' ' . theme('image', array('path' => 'misc/watchdog-warning.png')) . ' ' . t('Some objects are missing and must be installed. See objects list for details.');
$submit_button_text = t("Install objects");
}
elseif ($needs_update) {
$form['solution_pack']['install_status']['#markup'] .= ' ' . theme('image', array('path' => 'misc/watchdog-warning.png')) . ' ' . t('Some objects must be reinstalled. See objects list for details.');
$submit_button_text = t("Reinstall objects");
}
elseif ($could_not_connect) {
$form['solution_pack']['install_status']['#markup'] .= ' ' . theme('image', array('path' => 'misc/watchdog-error.png')) . ' ' . t('Could not connect to the repository.');
$submit_button_text = '';
}
$form['solution_pack']['table'] = array(
'#type' => 'item',
'#markup' => theme('table', array('header' => $table_header, 'rows' => $table_rows)),
);
}
if (!$could_not_connect) {
$form['solution_pack']['submit'] = array(
'#value' => $submit_button_text,
'#type' => 'submit',
'#name' => $solution_pack_module,
'#attributes' => array('class' => array('islandora-solution-pack-submit')),
'#weight' => 40,
);
$form['solution_pack']['#submit'] = array('islandora_solution_pack_form_submit');
}
return $form;
}
/**
* Submit handler for solution pack form.
*
* @param array $form
* The form submitted.
* @param array_reference $form_state
* The state of the form submited.
*/
function islandora_solution_pack_form_submit($form, &$form_state) {
$solution_pack_module = $form_state['values']['solution_pack_module'];
$solution_pack_name = $form_state['values']['solution_pack_name'];
$objects = $form_state['values']['objects'];
$batch = array(
'title' => t('Installing / updating solution pack objects'),
'file' => drupal_get_path('module', 'islandora') . '/includes/solution_packs.inc',
'operations' => array(),
);
foreach ($objects as $object) {
// Add this object to the batch job queue.
$batch['operations'][] = array('islandora_batch_reingest_object', array($object));
}
batch_set($batch);
// Hook to let solution pack objects be modified.
// Not using module_invoke so solution packs can be expanded by other modules.
module_invoke_all('islandora_postprocess_solution_pack', $solution_pack_module);
}
/**
* Batch reingest object(s)
*
* @param array $object
* @param type $context
* @return type
*/
function islandora_batch_reingest_object($object_model, &$context) {
module_load_include('inc', 'islandora', 'includes/utilities');
global $base_url;
$connection = islandora_get_tuque_connection();
if (!$connection) {
return;
}
if (!empty($object_model) && is_array($object_model)) {
$pid = $object_model['pid'];
if (!islandora_is_valid_pid($pid)) {
return NULL;
}
// purge object
// check if object already exits
$object_query = $connection->api->a->findObjects('query', 'pid=' . $pid);
$reinstall = FALSE;
if (!empty($object_query['results'])) {
$object = islandora_object_load($pid);
if (isset($object)) {
islandora_delete_object($object);
}
$reinstall = TRUE;
}
// build and ingest new object
try {
$object = islandora_solution_pack_add_object($object_model);
$object_name = $object->label;
if ($reinstall) {
drupal_set_message(t('Successfully reinstalled <em>@object_name</em>.', array('@object_name' => $object_name, '@pid' => $pid)));
}
else {
drupal_set_message(t('Successfully installed <em>@object_name</em>.', array('@object_name' => $object_name, '@pid' => $pid)));
}
}
catch (Exception $e) {
drupal_set_message(t('Installation of object @pid failed', array('@pid' => $pid)), 'error');
}
}
}
/**
* Callback function that can be called from the solution pack's hook_install() and hook_uninstall() functions.
*
* @TODO: add documentation
*/
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)) {
module_load_include('module', 'islandora', 'islandora');
module_load_include('inc', 'islandora', 'includes/utilities');
module_load_include('module', $module_name, $module_name);
// set globals
global $base_url;
global $user;
12 years ago
// set variables
$sp_admin = url($base_url . '/admin/islandora/solution_packs');
$config_url = url('admin/islandora/configure');
// get module info
$info_file = drupal_get_path('module', $module_name) . '/' . $module_name . '.info';
$info_array = drupal_parse_info_file($info_file);
$module_label = $info_array['name'];
12 years ago
// check connection
$url = variable_get('islandora_base_url', 'http://localhost:8080/fedora');
$info = islandora_describe_repository($url);
if (!$info) {
// operation
switch ($op) {
case 'install':
12 years ago
drupal_set_message(st('@module_label: Did not install any objects. Could not connect to the repository. Please check the settings on the <a href="@config_url" title="Islandora configuration page">Islandora configuration</a> page and install the required objects manually on the <a href="@sp_url" title="Solution pack admin">solution pack admin</a> page.', array('@module_label' => $module_label, '@config_url' => $config_url, '@sp_url' => $sp_admin)), 'error');
break;
12 years ago
case 'uninstall':
12 years ago
drupal_set_message(st('@module_label: Did not uninstall any objects. Could not connect to the repository. Please check the settings on the <a href="@config_url" title="Islandora configuration page">Islandora configuration</a> page and uninstall the required objects manually if necessary.', array('@module_label' => $module_label, '@config_url' => $config_url)), 'error');
break;
}
return;
}
$connection = islandora_get_tuque_connection();
// get object models
$enabled_solution_packs = module_invoke_all('islandora_required_objects');
$islandora_required_objects = $module_name . '_islandora_required_objects';
$required_objects = $islandora_required_objects();
$objects = $required_objects[$module_name]['objects'];
// loop over object models
foreach ($objects as $object) {
// set variables
$pid = $object['pid'];
$label = isset($object['label']) ? $object['label'] : st('Object');
// check if object already exists
$query = $connection->api->a->findObjects('query', 'pid=' . $pid);
12 years ago
// object url
$object_url = url($base_url . '/islandora/object/' . $pid);
// operation: install or uninstall
switch ($op) {
case 'install':
// if object exists, don't re-ingest
if (!empty($query['results'])) {
// check object status
$object_status = islandora_check_object_status($object);
// set messages
switch ($object_status) {
case 'up_to_date':
12 years ago
drupal_set_message(st('@module_label: did not install <a href="@object_url" title="@pid">@label</a>. The object already exists and is up-to-date.', array('@module_label' => $module_label, '@label' => $label, '@pid' => $pid, '@object_url' => $object_url)));
break;
case 'missing_datastream':
12 years ago
drupal_set_message(st('@module_label: did not install <a href="@object_url" title="@pid">@label</a>. The object already exists but is missing a datastream. Please reinstall the object on the <a href="@sp_admin" title="Solution pack admin page">solution pack admin page</a>.', array('@module_label' => $module_label, '@label' => $label, '@pid' => $pid, '@objecturl' => $object_url, '@sp_admin' => $sp_admin)), 'warning');
break;
case 'out_of_date':
12 years ago
drupal_set_message(st('@module_label: did not install <a href="@object_url" title="@pid">@label</a>. The object already exists but is out-of-date. Please update the object on the <a href="@sp_admin" title="Solution pack admin page">solution pack admin page</a>.', array('@module_label' => $module_label, '@label' => $label, '@pid' => $pid, '@object_url' => $object_url, '@sp_admin' => $sp_admin)), 'warning');
break;
}
}
else {
islandora_solution_pack_add_object($object);
12 years ago
drupal_set_message(st('@module_label: installed <a href="@object_url" title="@pid">@label</a> object.', array('@module_label' => $module_label, '@label' => $label, '@pid' => $pid, '@object_url' => $object_url)));
}
break;
case 'uninstall':
// if object exists, set message
if (!empty($query['results'])) {
$object_url = url($base_url . '/islandora/object/' . $pid);
12 years ago
drupal_set_message(st('@module_label: did not remove <a href="@object_url" title="@pid">@label</a>. It may be used by other sites.', array('@pid' => $pid, '@object_url' => $object_url, '@label' => $label, '@module_label' => $module_label)), 'warning');
}
break;
}
}
}
}
/**
* Function to check the status of an object against an object model array.
*
* @param array $object_model
* an array describing an object
* @return string
* Returns one of the following values:
* up_to_date, missing, missing_datastream or out_of_date
* You can perform an appropriate action based on this value.
* Returns FALSE if the array is empty
*
* @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?
*/
function islandora_check_object_status($object_model = array()) {
if (!empty($object_model)) {
// set variables
$pid = $object_model['pid'];
$object_status = 'up_to_date';
// table row
$table_row = array();
// 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) {
$object_status = 'could_not_connect';
}
else {
// load object
$object = islandora_object_load($pid);
// check if object exists
if (!$object) {
$object_status = 'missing';
}
else {
// 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(
'dsid' => $object_model['dsid'],
'datastream_file' => $object_model['datastream_file'],
'dsversion' => $object_model['dsversion'],
),
);
}
// object defined with multiple datastreams (using an array)
elseif (!empty($object_model['datastreams'])) {
$datastreams = $object_model['datastreams'];
}
if (!empty($datastreams) && is_array($datastreams)) {
// loop over defined datastreams
foreach ($datastreams as $ds) {
$ds_id = $ds['dsid'];
// check if defined datastream exists in the object
if (!$object[$ds_id]) {
$object_status = 'missing_datastream';
break;
}
elseif (isset($ds['dsversion'])) {
// Check if the datastream is versioned and needs updating.
$installed_version = islandora_get_islandora_datastream_version($object, $ds['dsid']);
$available_version = islandora_get_islandora_datastream_version(NULL, NULL, $ds['datastream_file']);
12 years ago
if ($available_version > $installed_version) {
$object_status = 'out_of_date';
break;
}
}
}
}
}
}
return $object_status;
}
else {
return FALSE;
}
}
/**
* 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
* @{
* Helper functions to include viewers for solution packs.
*/
/**
* A form construct to create a viewer selection table.
*
* @param string $variable_id
* The ID of the Drupal variable to save the viewer settings in
* @param string $mimetype
* The table will be populated with viewers supporting this mimetype
* @return
* A form api array which defines a themed table to select a viewer.
*/
function islandora_viewers_form($variable_id = NULL, $mimetype = NULL) {
$form = array();
// get viewers
$viewers = islandora_get_viewers($mimetype);
if (!empty($viewers)) {
// add option for no viewer
$no_viewer = array();
$no_viewer['none'] = array(
'label' => t('None'),
'description' => t('Don\'t use a viewer for this solution pack.'),
);
// merge to viewers array
$viewers = array_merge_recursive($no_viewer, $viewers);
}
// get viewer settings
$viewers_config = variable_get($variable_id, array());
// viewer
$form['viewers'] = array(
'#type' => 'fieldset',
'#title' => t('Viewers'),
'#collapsible' => FALSE,
'#collapsed' => FALSE,
);
if (!empty($viewers)) {
// viewers table
$form['viewers'][$variable_id] = array(
'#type' => 'item',
'#title' => t('Select a viewer'),
'#description' => t('Preferred viewer for your solution pack. These may be provided by third-party modules.'),
// 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(
'#type' => 'hidden',
'#value' => $name,
);
// label
$form['viewers'][$variable_id]['label'][$name] = array(
'#type' => 'item',
'#markup' => $profile['label'],
);
// description
$form['viewers'][$variable_id]['description'][$name] = array(
'#type' => 'item',
'#markup' => $profile['description'],
);
// configuration url
$form['viewers'][$variable_id]['configuration'][$name] = array(
'#type' => 'item',
'#markup' => (isset($profile['configuration']) AND $profile['configuration'] != '') ? l(t('configure'), $profile['configuration']) : '',
);
}
// radios
$form['viewers'][$variable_id]['default'] = array(
'#type' => 'radios',
'#options' => isset($options) ? $options : array(),
'#default_value' => !empty($viewers_config) ? $viewers_config['default'] : 'none',
);
}
else {
// No viewers found
$form['viewers'][$variable_id . '_no_viewers'] = array(
'#markup' => t('No viewers detected.'),
);
// remove viewers variable
variable_del($variable_id);
}
return $form;
}
/**
* Returns all defined viewers.
*
* @param string $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');
// filter viewers by mimetype
foreach ($defined_viewers as $key => $value) {
if (in_array($mimetype, $value['mimetype']) OR $mimetype == NULL) {
$viewers[$key] = $value;
}
}
if (!empty($viewers)) {
return $viewers;
}
return FALSE;
}
/**
* Theme function for the admin primary display table
*
* @param type $variables
* render element: $form
* Contains the form array
* @return
* rendered form element
*
* @see islandora_large_image_admin()
*/
function theme_islandora_viewers_table($variables) {
// set form
$form = $variables['form'];
$rows = array();
foreach ($form['name'] as $key => $element) {
// Do not take form control structures.
if (is_array($element) && element_child($key)) {
// set rows
$row = array();
$row[] = array('data' => drupal_render($form['default'][$key]));
$row[] = array('data' => drupal_render($form['label'][$key]));
$row[] = array('data' => drupal_render($form['description'][$key]));
$row[] = array('data' => drupal_render($form['configuration'][$key]));
// add to rows
$rows[] = array('data' => $row);
}
}
// Individual table headers.
// default | label | description | configuration
$header = array();
$header[] = array('data' => t('Default'));
$header[] = array('data' => t('Label'));
$header[] = array('data' => t('Description'));
$header[] = array('data' => t('Configuration'));
// render form
$output = '';
$output .= theme('table', array('header' => $header, 'rows' => $rows, 'attributes' => array('id' => 'islandora-viewers-table')));
$output .= drupal_render_children($form);
return $output;
}
/**
* Gather information and return a rendered viewer
*
* @param array/string $params
* Array or string with data the module needs in order to render a full viewer
* @param string $variable_id
* The id of the Drupal variable the viewer settings are saved in
* @return
* The callback to the viewer module. Returns a rendered viewer. Returns FALSE
* if no viewer is set.
*/
function islandora_get_viewer($params = NULL, $variable_id = NULL) {
// get viewer from settings
$settings = variable_get($variable_id, array());
// make sure a viewer is set
if (!empty($settings) AND $settings['default'] !== 'none') {
// get callback function
$viewer_id = islandora_get_viewer_id($variable_id);
if ($viewer_id AND $params !== NULL) {
$callback = islandora_get_viewer_callback($viewer_id);
// call callback function
return $callback($params);
}
}
return NULL;
}
/**
* Get id of the enabled viewer.
*
* @param string $variable_id
* The id of the Drupal variable the viewer settings are saved in
* @return
* The enabled viewer id. Returns FALSE if no viewer config is set.
*/
function islandora_get_viewer_id($variable_id) {
$viewers_config = variable_get($variable_id, array());
if (!empty($viewers_config)) {
return $viewers_config['default'];
}
return FALSE;
}
/**
* Get callback function for a viewer.
*
* @param string $viewer_id
* The ID of a viewer
* @return
* The callback function as a string as defined by the viewer.
*/
function islandora_get_viewer_callback($viewer_id = NULL) {
if ($viewer_id !== NULL) {
$viewers = module_invoke_all('islandora_viewer_info');
if (isset($viewers[$viewer_id]['callback'])) {
return $viewers[$viewer_id]['callback'];
}
}
return FALSE;
}
/**
* @} End of "defgroup viewer-functions".
*/