diff --git a/includes/islandora.ingest.inc b/includes/islandora.ingest.inc index a9869ed1..3e64dbf5 100644 --- a/includes/islandora.ingest.inc +++ b/includes/islandora.ingest.inc @@ -95,7 +95,7 @@ function islandora_ingest_new_object_prepare($namespace = NULL, $label = NULL, $ */ function islandora_ingest_add_object(&$object) { $object->repository->ingestObject($object); - module_invoke_all('islandora_ingest_post_ingest', $object); + islandora_invoke(ISLANDORA_POST_INGEST_HOOK, $object); return $object; } diff --git a/islandora.api.php b/islandora.api.php index 49be904d..cbe0c3bc 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -6,116 +6,128 @@ */ /** - * remove a datastream from a repository object - * @param object $fedora_object - * tuque FedoraObject - * @param string $datastream_id - */ -function hook_islandora_purge_datastream($fedora_object, $datastream_id) {} - -/** + * Allows modules to add to a repository objects view/edit(/misc) process. * - * @param type $object - * tuque FedoraObject - */ -function hook_islandora_purge_object($islandora_object) {} - -/** - * allows modules to add to a repository objects display. If you implement this - * hook you should also register your module for view with the get types hook. + * If you implement this hook you must also register your module for view + * with the hook_islandora_get_types(). * - * islandora gets all displays back in an array and iterates over them. the order - * they are displayed is based on the order of the key of the array that each - * module returns. + * Islandora gets all displays back in an array. The order they are displayed + * is based on the order of the key of the array that each module returns. * - * your module may also want to register a varible that says whether or not it - * should be part of the default display. Modules can also add secondary tabs as - * a way to add there output to an islandora display. the basic image module has - * samples of both (the secondary tabs examples are commented out) + * "HOOK_NAME" reflects those provided by the islandora_get_types() function, + * and these functions should be called via islandora_invoke(). There are a + * number of these hooks defined at the top of islandora.module, including: + * - ISLANDORA_VIEW_HOOK: Invoked in islandora_view_object(); returns an array + * containing string values, and whose keys will be used for sorting. + * Takes four parameters: + * - fedora_object: A Tuque FedoraObject being operated on. + * - user: The user accessing the object. + * - page_number: The page in the content. + * - page_size: The size o the page. + * - ISLANDORA_EDIT_HOOK: Invoked in islandora_edit_object(); returns an array + * containing string values, whose keys will be used for sorting. + * Takes one parameter: + * - fedora_object: A Tuque FedoraObject being operated on. + * - ISLANDORA_POST_INGEST_HOOK: Invoked in islandora_ingest_add_object(); no + * return. Probably want to use this to add additional datastreams, or + * or perhap remove some. Takes one parameter: + * - The object in question. + * - ISLANDORA_PRE_PURGE_OBJECT_HOOK: Invoked in islandora_object_purge(); can + * return an associative array of with the key "delete" mapped to TRUE, + * which will cause the object to be marked "deleted" instead of actually + * purging the object. (This should be verirfied?) * * @param type $islandora_object - * tuque FedoraObject - */ -function hook_islandora_view_object($islandora_object) {} - -/** - * returns an array listing object types provided by sub modules - * Ex. array($types['islandora:collectionCModel'][ISLANDORA_VIEW_HOOK] = variable_get('islandora_basic_collection_use_for_default_tab', TRUE); - * $types['islandora:collectionCModel'][ISLANDORA_EDIT_HOOK] = FALSE; + * A Tuque FedoraObject + * @param ... + * A variable list of arguments, as required by the in question hook. * * @return array + * An array to merge in. */ -function hook_islandora_get_types() {} +function hook_HOOK_NAME($islandora_object) {} /** - * allows modules to define an object edit page by cmodel - * - * your module should return true for ISLANDORA_EDIT_HOOK in its get_types function - * - * islandora provides a default implementation that should work for most use cases - * @param string $islandora_object - * @return string - * + * Alter an object before further processing in islandora_invoke(). */ -function hook_islandora_edit_object($islandora_object) {} +function hook_HOOK_NAME_alter($fedora_object) {} /** - * allows modules to alter the fedora object before it is pass through the edit - * hooks - * @param type $islandora_object - * a tugue FedoraObject + * Allow output of hooks passing through islandora_invoke() to be altered. + * @param type $arr + * an arr of rendered views */ -function hook_islandora_edit_object_alter($islandora_object) {} +function hook_HOOK_NAME_output_alter($arr) {} /** - * creates and populates a php Fedora object. + * Get an array of object types provided by other modules. + * + * @return array + * An associative array mapping cmodel PIDs to module names to hooks to + * booleans indicating that the given module's implementation of the hook + * should be invoked. */ -function hook_islandora_preingest_alter() {} +function hook_islandora_get_types() { + $types = array( + 'my:coolCModel' => array( + 'my_cool_module' => array( + ISLANDORA_VIEW_HOOK => TRUE, + ), + ), + ); + return $types; +} /** - * modules can implement this hook to add or remove datastreams after an - * object has been ingested. + * Allows modules to define an object edit page by cmodel. * - * Each module should check for the newly ingested repository objects content - * model to make sure it is a type of object they want to act on. + * Your module must return TRUE for ISLANDORA_EDIT_HOOK in its + * implementation of hook_islandora_get_types(). * - * @param type $islandora_object - * tugue FeodoraObject + * Islandora provides a default implementation that should work for most use + * cases. + * + * @param object $islandora_object + * A Tuque FedoraObject to be edited. + * @return array + * An array of strings containing markup, which will be imploded together. */ -function hook_islandora_postingest($islandora_object) {} +function hook_islandora_edit_object($islandora_object) {} /** - * Register potential ingest routes. Implementations should return an array containing possible routes. - * Ex. array( - * array('name' => t('Ingest Route Name'), 'url' => 'ingest_route/url', 'weight' => 0), - * ); + * Register potential ingest routes. + * + * Implementations should return an array containing possible routes. */ -function hook_islandora_ingest_registry($collection_object) {} +function hook_islandora_ingest_registry($collection_object) { + $reg = array( + array( + 'name' => t('Ingest Route Name'), + 'url' => 'ingest_route/url', + 'weight' => 0, + ), + ); + return $reg +} /** * Register a datastream edit route/form. + * * @param $islandora_object * @param $ds_id */ function hook_islandora_edit_datastream_registry($islandora_object, $ds_id) {} /** - * alter an object before it gets used further down the stack + * Alter an object before it gets used further down the stack. * @param type $object - * a tuque FedoraObject + * A Tuque FedoraObject */ function hook_islandora_object_alter($fedora_object) {} /** - * insert or remove rendered elements by implementing this function - * in your module - * @param type $arr - * an arr of rendered views - */ -function hook_islandora_display_alter($arr) {} - -/** + * Allow modification of an object before ingesting. * * @param type $islandora_object * a tuque FedoraObject @@ -123,3 +135,32 @@ function hook_islandora_display_alter($arr) {} * @param string $collection_pid */ function hook_islandora_ingest_pre_ingest($islandora_object, $content_models, $collection_pid) {} + +/** + * Allow modules to setup for the purge of a datastream. + * + * @param object $datastream + * A Tuque FedoraDatastream object. + */ +function hook_islandora_pre_purge_datastream($datastream) {} + +/** + * Allow modules to react after a datastream is purged. + * + * @param object $object + * A Tuque FedoraObject. + * @param string $dsid + * A id of the former datastream. + */ +function hook_islandora_post_purge_datastream($object, $dsid) {} + +/** + * Allow modules to react post-purge. + * + * @param string $object_id + * The former object's PID. + * @param array $content_models + * An array containing the models to which the former object. + */ +function hook_islandora_post_purge_object($object_id, $content_models) {} + diff --git a/islandora.module b/islandora.module index 1845eeb4..9790fc61 100644 --- a/islandora.module +++ b/islandora.module @@ -31,9 +31,11 @@ define('FEDORA_PURGE', 'delete fedora objects and datastreams'); define('FEDORA_MODIFY_STATE', 'modify fedora state'); define('FEDORA_MANAGE', 'manage fedora items'); -// hooks +// Hooks define('ISLANDORA_VIEW_HOOK', 'islandora_view_object'); define('ISLANDORA_EDIT_HOOK', 'islandora_edit_object'); +define('ISLANDORA_POST_INGEST_HOOK', 'islandora_ingest_post_ingest'); +define('ISLANDORA_PRE_PURGE_OBJECT_HOOK', 'islandora_pre_purge_object'); /** * Implements hook_menu(). @@ -250,11 +252,40 @@ function islandora_access_callback($object = NULL, $perm = NULL) { } /** - * returns an array listing object types provided by sub modules + * Returns an array listing object types. + * + * @param string $model + * A string representing a short content model URI, to only get the relevant + * elements. + * * @return array + * An associative array mapping cmodel pids to modules to a boolean + * indicating if the hook on the given module should be called. + * + * @todo + * Rename this function and the hook, as it now has a wider usage. */ -function islandora_get_types() { - return module_invoke_all('islandora_get_types'); +function islandora_get_types($model = NULL) { + $types = &drupal_static(__FUNCTION__); + + if ($types === NULL) { + $types = module_invoke_all('islandora_get_types'); + drupal_alter('islandora_get_types', $types); + + // TODO: Add in the defaults, where there's no view or edit? + } + + if ($model !== NULL) { + if (isset($types[$model])) { + return $types[$model]; + } + else { + return array(); + } + } + else { + return $types; + } } function islandora_init() { @@ -287,13 +318,64 @@ function islandora_edit_object($object) { if (!$object) { return drupal_not_found(); } - drupal_alter('islandora_edit_object', $object); - $arr = module_invoke_all('islandora_edit_object', $object); - $output = ""; - foreach ($arr as $key => $value) { - $output .= $value; //if we have multiple modules handle one cmodel we need to iterate over multiple + + $output = islandora_invoke(ISLANDORA_EDIT_HOOK, $object); + + // Add in the default, if we did not get any results. + if (empty($output)) { + $output = islandora_islandora_edit_object($object); } + //we could do another module invoke all here to build the edit tab with a default implemented in this module? + return implode('', $output); +} + +/** + * Invoke a hook registered via islandora_get_types(). + * + * @param string $hook + * The hook to invoke. + * @param object $object + * The object to be affected by the hook. + * @param ... + * An optional variable list of arguments. + * + * @return array + * The array of results. + */ +function islandora_invoke($hook, $object) { + // Allow altering of the object, before processing. + drupal_alter($hook, $object); + + // Accumulate the output + $output = array(); + + // Get the models... + $supported_models = islandora_get_types(); + + // Filter them down to only the ones explicitly supported. + $models = array_intersect(array_keys($supported_models), $object->models); + + // And actually call out to accumulate the output for each model. + foreach($models as $model) { + foreach ($supported_models[$model] as $module => $hooks) { + if (isset($hooks[$hook]) && $hooks[$hook]) { + $args = func_get_args(); + + // Add the module into the list of args, and call module_invoke. + array_unshift($args, $module); + $return = call_user_func_array('module_invoke', $args); + if (is_array($return)) { + $output = array_merge_recursive($output, $return); + } + } + } + } + + arsort($output); + + drupal_alter($hook . '_output', $output); + return $output; } @@ -314,20 +396,16 @@ function islandora_edit_properties($object_id) { } /** - * builds a default page for the edit tab + * Builds a default page for the edit tab. * * @param object $fedora_object * A tuque Fedora Object */ function islandora_islandora_edit_object($fedora_object) { - $supported_models = islandora_get_types(); - $output = ""; - foreach ($fedora_object->models as $model) { - if (isset($supported_models[$model][ISLANDORA_EDIT_HOOK]) && $supported_models[$model][ISLANDORA_EDIT_HOOK] == TRUE) {//another module is handling the view - return; - } - } - $output = theme('islandora_default_edit', array('islandora_object' => $fedora_object)); + $output = theme('islandora_default_edit', array( + 'islandora_object' => $fedora_object, + )); + return array('Default Edit output' => $output); } @@ -357,20 +435,13 @@ function islandora_view_object($fedora_object = NULL) { $page_number = (empty($_GET['page'])) ? '1' : $_GET['page']; $page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize']; - drupal_alter('islandora_object', $fedora_object); //modify object if required before it is passed along - $arr = module_invoke_all('islandora_view_object', $fedora_object, $user, $page_number, $page_size); //allow submodules to decide how to handle content base on object type - if (empty($arr)) { - //TODO: make sure we iterate over the array as they will be more then one cmodel per object - drupal_set_message(t('there was an error loading the view for islandora object %s', array('%s' => $object_id)), 'error'); - return ""; - } - arsort($arr); - drupal_alter('islandora_display', $arr); - $output = ""; - foreach ($arr as $key => $value) { - $output .= $value; //if we have multiple modules handle one cmodel we need to iterate over multiple + $output = islandora_invoke(ISLANDORA_VIEW_HOOK, $fedora_object, $user, $page_number, $page_size); + + if (empty($output)) { + $output = islandora_islandora_view_object($fedora_object); } - return $output; + + return implode('', $output); } /** @@ -381,13 +452,6 @@ function islandora_view_object($fedora_object = NULL) { * @return string */ function islandora_islandora_view_object($object) { - $supported_models = islandora_get_types(); - $output = ""; - foreach ($object->models as $model) { - if (isset($supported_models[$model][ISLANDORA_VIEW_HOOK]) && (boolean) $supported_models[$model][ISLANDORA_VIEW_HOOK] === TRUE) {//another module is handling the view - return; - } - } $output = theme('islandora_default', array('islandora_object' => $object)); return array('Default Output' => $output); } @@ -459,7 +523,7 @@ function islandora_permission() { */ function islandora_object_load($object_id) { module_load_include('inc', 'islandora', 'includes/tuque'); - static $islandora_tuque = NULL; + $islandora_tuque = &drupal_static(__FUNCTION__); if (!$islandora_tuque) { $islandora_tuque = new IslandoraTuque(); @@ -471,6 +535,8 @@ function islandora_object_load($object_id) { } catch (Exception $e) { return NULL; } + + drupal_alter('islandora_object', $fedora_object); return $fedora_object; } else { @@ -500,7 +566,7 @@ function islandora_object_purge($object_id) { return; } $content_models = $object->models; - $arr = module_invoke_all('islandora_pre_purge_object', $object); // notify modules of pending deletion + $arr = islandora_invoke(ISLANDORA_PRE_PURGE_OBJECT_HOOK, $object); // notify modules of pending deletion if (isset($arr['delete']) && $arr['delete']) { try { $object->delete(); @@ -517,6 +583,7 @@ function islandora_object_purge($object_id) { return ""; } } + module_invoke_all('islandora_post_purge_object', $object_id, $content_models); // notify modules post deletion }