From d8c8de4dc02e7f579e99e0604a3f2e43103f591b Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Mon, 29 Oct 2012 10:18:53 -0300 Subject: [PATCH 1/4] Alter hook calls and update documentation to reflect it. --- includes/islandora.ingest.inc | 2 +- islandora.api.php | 181 +++++++++++++++++++++------------- islandora.module | 147 +++++++++++++++++++-------- 3 files changed, 219 insertions(+), 111 deletions(-) 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 } From e2ce34ab05c3fbac97e6074a93ae6b27e189f61c Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Mon, 29 Oct 2012 13:05:08 -0300 Subject: [PATCH 2/4] Expand hook documentation and rename hook. --- islandora.api.php | 165 +++++++++++++++++++++++++++++++--------------- islandora.module | 31 ++------- 2 files changed, 118 insertions(+), 78 deletions(-) diff --git a/islandora.api.php b/islandora.api.php index cbe0c3bc..23dac39e 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -6,58 +6,133 @@ */ /** - * Allows modules to add to a repository objects view/edit(/misc) process. + * Generate a repository objects view. * - * 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. The order they are displayed - * is based on the order of the key of the array that each module returns. - * - * "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?) + * If you implement this hook you must also register your module with + * hook_islandora_hook_info(). * * @param type $islandora_object * A Tuque FedoraObject - * @param ... - * A variable list of arguments, as required by the in question hook. + * @param FedoraObject $fedora_object + * A Tuque FedoraObject being operated on. + * @param object $user + * The user accessing the object. + * @param string $page_number + * The page in the content. + * @param string $page_size: The size of the page. + * + * @return array + * An array to merge in. + */ +function hook_islandora_view_object($fedora_object, $user, $page_number, $page_size) {} + +/** + * Alter an object before processing in hook_islandora_view_object(). + * + * @param FedoraObject $fedora_object + * The Tuque FedoraObject being displayed. + */ +function hook_islandora_view_object_alter(&$fedora_object) {} + +/** + * Alter display output after it has been generated. + * + * @param array $arr + * An arr of rendered views. + */ +function hook_islandora_view_object_output_alter(&$arr) {} + +/** + * Generate an object's management display. + * + * If you implement this hook you must also register your module with + * hook_islandora_hook_info(). + * + * @param type $fedora_object + * A Tuque FedoraObject * * @return array * An array to merge in. */ -function hook_HOOK_NAME($islandora_object) {} +function hook_islandora_edit_object($fedora_object) {} /** - * Alter an object before further processing in islandora_invoke(). + * Alter an object before processing in hook_islandora_edit_object(). + * + * @param FedoraObject $fedora_object + * The Tuque FedoraObject to alter. */ -function hook_HOOK_NAME_alter($fedora_object) {} +function hook_islandora_edit_object_alter(&$fedora_object) {} /** - * Allow output of hooks passing through islandora_invoke() to be altered. + * Allow management display output to be altered. + * * @param type $arr * an arr of rendered views */ -function hook_HOOK_NAME_output_alter($arr) {} +function hook_islandora_edit_object_output_alter(&$arr) {} + +/** + * Allows modules to add to an objects ingest process. + * + * If you implement this hook you must also register your module for with + * hook_islandora_hook_info(). + * + * NOTE: This doesn't normally return any output. + * + * @param FedoraObject $fedora_object + * A Tuque FedoraObject. + */ +function hook_islandora_ingest_post_ingest($fedora_object) {} + +/** + * Alter an object before processing in hook_islandora_ingest_post_ingest(). + * + * @param FedoraObject $fedora_object + * A Tuque FedoraObject. + */ +function hook_islandora_ingest_post_ingest_alter(&$fedora_object) {} + +/** + * Allow output of hook_islandora_ingest_post_ingest() be altered. + * + * @param array $arr + * The array of hook output. + */ +function hook_islandora_ingest_post_ingest_output_alter(&$arr) {} + +/** + * Allows modules to add to a repository objects view/edit(/misc) process. + * + * If you implement this hook you must also register your module with + * hook_islandora_hook_info(). + * + * @param FedoraObject $fedora_object + * A Tuque FedoraObject. + * + * @return array|null + * An associative array with 'deleted' mapped to TRUE--indicating that the + * object should just be marked as deleted, instead of actually being + * purged--or NULL/no return if we just need to do something before the + * is purged. + */ +function hook_islandora_pre_purge_object($fedora_object) {} + +/** + * Alter an object before processing in hook_islandora_pre_purge_object_alter(). + * + * @param FedoraObject $fedora_object + * A Tuque FedoraObject. + */ +function hook_islandora_pre_purge_object_alter(&$fedora_object) {} + +/** + * Allow output of hook_islandora_pre_purge_object() to be altered. + * + * @param array $arr + * The array of hook output. + */ +function hook_islandora_pre_purge_object_output_alter(&$arr) {} /** @@ -68,7 +143,7 @@ function hook_HOOK_NAME_output_alter($arr) {} * booleans indicating that the given module's implementation of the hook * should be invoked. */ -function hook_islandora_get_types() { +function hook_islandora_type_info() { $types = array( 'my:coolCModel' => array( 'my_cool_module' => array( @@ -79,22 +154,6 @@ function hook_islandora_get_types() { return $types; } -/** - * Allows modules to define an object edit page by cmodel. - * - * Your module must return TRUE for ISLANDORA_EDIT_HOOK in its - * implementation of hook_islandora_get_types(). - * - * 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_edit_object($islandora_object) {} - /** * Register potential ingest routes. * diff --git a/islandora.module b/islandora.module index 9790fc61..149aafe4 100644 --- a/islandora.module +++ b/islandora.module @@ -254,38 +254,19 @@ function islandora_access_callback($object = NULL, $perm = NULL) { /** * 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($model = NULL) { +function islandora_types() { $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? + $types = module_invoke_all('islandora_type_info'); + drupal_alter('islandora_type_info', $types); } - if ($model !== NULL) { - if (isset($types[$model])) { - return $types[$model]; - } - else { - return array(); - } - } - else { - return $types; - } + return $types; } function islandora_init() { @@ -331,7 +312,7 @@ function islandora_edit_object($object) { } /** - * Invoke a hook registered via islandora_get_types(). + * Invoke a hook registered via hook_islandora_type_info(). * * @param string $hook * The hook to invoke. @@ -351,7 +332,7 @@ function islandora_invoke($hook, $object) { $output = array(); // Get the models... - $supported_models = islandora_get_types(); + $supported_models = islandora_types(); // Filter them down to only the ones explicitly supported. $models = array_intersect(array_keys($supported_models), $object->models); From d945f511da21e96590f305f69252c0f8ebec7ce7 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Mon, 29 Oct 2012 13:14:49 -0300 Subject: [PATCH 3/4] Minor documentation expansion. --- islandora.api.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/islandora.api.php b/islandora.api.php index 23dac39e..30d99248 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -22,7 +22,7 @@ * @param string $page_size: The size of the page. * * @return array - * An array to merge in. + * An array whose values are markup. */ function hook_islandora_view_object($fedora_object, $user, $page_number, $page_size) {} @@ -52,7 +52,7 @@ function hook_islandora_view_object_output_alter(&$arr) {} * A Tuque FedoraObject * * @return array - * An array to merge in. + * An array whose values are markup. */ function hook_islandora_edit_object($fedora_object) {} From 978026b0031ce429080d8e178276edc8eeed4010 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Tue, 30 Oct 2012 17:45:31 -0300 Subject: [PATCH 4/4] Squash hook_islandora_type_info(), in favour of cmodel-prefixed hooks. Many of the Islandora hooks are now invoked once with each content model pid prefixed (after being escaped), in addition to the base hook call. --- includes/islandora.ingest.inc | 111 ++++++++++++++++++++---- islandora.api.php | 112 +++++++++--------------- islandora.module | 159 ++++++++++++++++++---------------- 3 files changed, 223 insertions(+), 159 deletions(-) diff --git a/includes/islandora.ingest.inc b/includes/islandora.ingest.inc index 3e64dbf5..bb2ad31c 100644 --- a/includes/islandora.ingest.inc +++ b/includes/islandora.ingest.inc @@ -2,7 +2,7 @@ /** * @file - * This file contains ingest callback functions + * This file contains ingest callback functions. */ /** @@ -16,23 +16,69 @@ function islandora_ingest_get_information(AbstractFedoraObject $collection_objec } /** - * @TODO: needs documentation + * Get an ingestable object. + * + * @deprecated + * Deprecated in favour of the more flexible + * islandora_ingest_new_object_prepare()--which this function has been made + * to call behind the scenes anyway. + * + * @param array $content_models + * An array of content models to which the new object should subscribe, where + * each content model is described by an associative array containing: + * - pid: The Fedora PID of the content model. + * @param string $collection_pid + * The collection to which the new object should belong. + * @param string $relationship + * The relationship this object will have to the collection. + * @param string $namespace + * The namespace in which the PID for the new object will be created. + * + * @return NewFedoraObject + * A NewFedoraObject which may be adjusted before ingesting. */ function islandora_ingest_get_object($content_models, $collection_pid, $relationship, $namespace) { - module_load_include('inc', 'islandora', 'includes/tuque'); - global $user; - $connection = new IslandoraTuque($user); - $object = $connection->repository->constructObject($namespace); - foreach ($content_models as $content_model) { - $object->relationships->add(FEDORA_MODEL_URI, 'hasModel', $content_model['pid']); + $models = array(); + foreach ($content_models as $relation) { + $models[] = $relation['pid']; } - $object->relationships->add(FEDORA_RELS_EXT_URI, $relationship, $collection_pid); - module_invoke_all('islandora_ingest_pre_ingest', $object, $content_models, $collection_pid); - return $object; + + return islandora_ingest_new_object_prepare($namespace, NULL, array(), $models, array( + array( + 'pid' => $collection_pid, + 'relationship' => $relationship, + ), + ), $collection_pid); } /** - * @TODO: needs documentation + * Prepare an ingestable object. + * + * @param string $namespace + * The namespace in which the PID for the new object will be created. + * @param string $label + * An optional label to apply to the object. + * @param array $datastreams + * A array of datastreams to add, where each datastream definition is an + * associative array containing: + * - dsid: The datastream ID. + * - label: An optional label for the datastream. + * - mimetype: A MIMEtype for the datastream; defaults to text/xml. + * - control_group: One of X, M, R and E; defaults to M. + * - datastream_file: A web-accessible path, for which we try to get an + * absolute path using url(). + * @param array $content_models + * An array of content model PIDs to which the new object should subscribe. + * @param array $relationships + * An array of relationships, where each relationship is an associative array + * containing: + * - relationship: The predicate for the relationship, from the Fedora + * RELS-EXT namespace. + * - pid: The object for the relationship, to which we are creating the + * relationhsip. + * + * @return NewFedoraObject + * An ingestable NewFedoraObject. */ function islandora_ingest_new_object_prepare($namespace = NULL, $label = NULL, $datastreams = array(), $content_models = array(), $relationships = array(), $collection_pid = NULL) { // include Tuque library @@ -86,20 +132,53 @@ function islandora_ingest_new_object_prepare($namespace = NULL, $label = NULL, $ $object->ingestDatastream($datastream); } - module_invoke_all('islandora_ingest_pre_ingest', $object, $content_models, $collection_pid); + foreach (_islandora_build_hook_list('islandora_ingest_pre_ingest', $content_models) as $hook) { + module_invoke_all($hook, $object, $content_models, $collection_pid); + } + return $object; } /** - * @TODO: needs documentation + * Ingest the given object into Fedora. + * + * @param NewFedoraObject $object + * An ingestable FedoraObject. + * + * @return FedoraObject + * The ingested FedoraObject, after running the post ingest hooks. */ function islandora_ingest_add_object(&$object) { $object->repository->ingestObject($object); - islandora_invoke(ISLANDORA_POST_INGEST_HOOK, $object); + + foreach (_islandora_build_hook_list(ISLANDORA_POST_INGEST_HOOK, $object->models) as $hook) { + module_invoke_all($hook, $object); + } + return $object; } - +/** + * Ingest an object. + * + * @param array $object_model + * An associative array containing the necessary parameters to create the + * desired object: + * - pid: The PID with which the object will be created. + * - label: An optional label to apply to the object. + * - datastreams: Same as the "datastreams" array accepted by + * islandora_ingest_new_object_prepare(). + * - cmodel: Either an array of content models as accepted by + * islandora_ingest_new_object_prepare(), or a single content model PID to add + * to the object. + * - parent: Either an array of parents, or a single parent PID to which to + * relate to; uses isMemberOfCollection by default. + * - relationships: An array of relationships as accepted by + * islandora_ingest_new_object_prepare(). + * + * @return FedoraObject + * An FedoraObject which has been ingested into Fedora. + */ function islandora_ingest_new_object($object_model) { // prepare variables // namespace diff --git a/islandora.api.php b/islandora.api.php index 30d99248..dff4c217 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -8,11 +8,6 @@ /** * Generate a repository objects view. * - * If you implement this hook you must also register your module with - * hook_islandora_hook_info(). - * - * @param type $islandora_object - * A Tuque FedoraObject * @param FedoraObject $fedora_object * A Tuque FedoraObject being operated on. * @param object $user @@ -27,27 +22,33 @@ function hook_islandora_view_object($fedora_object, $user, $page_number, $page_size) {} /** - * Alter an object before processing in hook_islandora_view_object(). + * Generate an object's display for the given content model. * - * @param FedoraObject $fedora_object - * The Tuque FedoraObject being displayed. + * Content models PIDs have colons and hyphens changed to underscores, to + * create the hook name. + * + * @param type $fedora_object + * A Tuque FedoraObject + * + * @return array + * An array whose values are markup. */ -function hook_islandora_view_object_alter(&$fedora_object) {} +function hook_CMODEL_PID_islandora_view_object($fedora_object) {} + /** * Alter display output after it has been generated. * + * @param FedoraObject $fedora_object + * A Tuque FedoraObject being operated on. * @param array $arr * An arr of rendered views. */ -function hook_islandora_view_object_output_alter(&$arr) {} +function hook_islandora_view_object_alter(&$fedora_object, &$arr) {} /** * Generate an object's management display. * - * If you implement this hook you must also register your module with - * hook_islandora_hook_info(). - * * @param type $fedora_object * A Tuque FedoraObject * @@ -57,49 +58,41 @@ function hook_islandora_view_object_output_alter(&$arr) {} function hook_islandora_edit_object($fedora_object) {} /** - * Alter an object before processing in hook_islandora_edit_object(). - * - * @param FedoraObject $fedora_object - * The Tuque FedoraObject to alter. + * Generate an object's management display for the given content model. + * + * Content models PIDs have colons and hyphens changed to underscores, to + * create the hook name. + * + * @param type $fedora_object + * A Tuque FedoraObject + * + * @return array + * An array whose values are markup. */ -function hook_islandora_edit_object_alter(&$fedora_object) {} +function hook_CMODEL_PID_islandora_edit_object($fedora_object) {} /** * Allow management display output to be altered. * + * @param type $fedora_object + * A Tuque FedoraObject * @param type $arr * an arr of rendered views */ -function hook_islandora_edit_object_output_alter(&$arr) {} +function hook_islandora_edit_object_alter(&$fedora_object, &$arr) {} /** * Allows modules to add to an objects ingest process. * - * If you implement this hook you must also register your module for with - * hook_islandora_hook_info(). - * - * NOTE: This doesn't normally return any output. - * * @param FedoraObject $fedora_object * A Tuque FedoraObject. */ function hook_islandora_ingest_post_ingest($fedora_object) {} /** - * Alter an object before processing in hook_islandora_ingest_post_ingest(). - * - * @param FedoraObject $fedora_object - * A Tuque FedoraObject. + * Allow modules to add to the ingest process of a specific content model. */ -function hook_islandora_ingest_post_ingest_alter(&$fedora_object) {} - -/** - * Allow output of hook_islandora_ingest_post_ingest() be altered. - * - * @param array $arr - * The array of hook output. - */ -function hook_islandora_ingest_post_ingest_output_alter(&$arr) {} +function hook_CMODEL_PID_islandora_ingest_post_ingest($fedora_object) {} /** * Allows modules to add to a repository objects view/edit(/misc) process. @@ -119,40 +112,11 @@ function hook_islandora_ingest_post_ingest_output_alter(&$arr) {} function hook_islandora_pre_purge_object($fedora_object) {} /** - * Alter an object before processing in hook_islandora_pre_purge_object_alter(). - * - * @param FedoraObject $fedora_object - * A Tuque FedoraObject. - */ -function hook_islandora_pre_purge_object_alter(&$fedora_object) {} - -/** - * Allow output of hook_islandora_pre_purge_object() to be altered. + * Allow modules to react to the purge process of a specific content model. * - * @param array $arr - * The array of hook output. + * @see hook_islandora_pre_purge_object() */ -function hook_islandora_pre_purge_object_output_alter(&$arr) {} - - -/** - * 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_type_info() { - $types = array( - 'my:coolCModel' => array( - 'my_cool_module' => array( - ISLANDORA_VIEW_HOOK => TRUE, - ), - ), - ); - return $types; -} +function hook_CMODEL_PID_islandora_pre_purge_object($fedora_object) {} /** * Register potential ingest routes. @@ -180,6 +144,7 @@ function hook_islandora_edit_datastream_registry($islandora_object, $ds_id) {} /** * Alter an object before it gets used further down the stack. + * * @param type $object * A Tuque FedoraObject */ @@ -189,12 +154,19 @@ function hook_islandora_object_alter($fedora_object) {} * Allow modification of an object before ingesting. * * @param type $islandora_object - * a tuque FedoraObject + * A Tuque FedoraObject * @param array $content_models * @param string $collection_pid */ function hook_islandora_ingest_pre_ingest($islandora_object, $content_models, $collection_pid) {} +/** + * Allow modification of objects of a certain content model before ingesting. + * + * @see hook_islandora_ingest_pre_ingest() + */ +function hook_CMODEL_PID_islandora_ingest_pre_ingest($islandora_object, $content_models, $collection_pid) {} + /** * Allow modules to setup for the purge of a datastream. * diff --git a/islandora.module b/islandora.module index 149aafe4..93f41415 100644 --- a/islandora.module +++ b/islandora.module @@ -251,24 +251,6 @@ function islandora_access_callback($object = NULL, $perm = NULL) { return ($namespace_access && user_access($perm)); } -/** - * Returns an array listing object types. - * - * @return array - * An associative array mapping cmodel pids to modules to a boolean - * indicating if the hook on the given module should be called. - */ -function islandora_types() { - $types = &drupal_static(__FUNCTION__); - - if ($types === NULL) { - $types = module_invoke_all('islandora_type_info'); - drupal_alter('islandora_type_info', $types); - } - - return $types; -} - function islandora_init() { if (path_is_admin(current_path())) { drupal_add_css(drupal_get_path('module', 'islandora') . '/css/islandora.admin.css'); @@ -288,6 +270,52 @@ function islandora_forms($form_id) { return $forms; } +/** + * Escape a Fedora PID to be valid inside of a PHP function name. + * + * Originally intended to allow inclusion of a PID in a module_invoke_all() + * call. + */ +function _islandora_escape_pid_for_function($pid) { + // Apparently, case doesn't matter for function calls in PHP, so let's not + // really worry about changing the case. + return str_replace( + // Any PID characters which are not valid in the name of a PHP function. + array( + ':', + '-', + ), + '_', + $pid + ); +} + +/** + * Build a list of all the hooks to call. + * + * Concatenates the each pid (escaped) to the hook name, for calling in + * module_invoke_all(). + * + * @param string $hook + * A hook to call. + * @param array $pids + * An array of PIDs (probably content models). + * + * @return array + * An array with each PID escaped and concatenated with the base hook name, + * in addition to the base hook name at the end. + */ +function _islandora_build_hook_list($hook, $pids = array()) { + $hooks = array(); + + foreach ($pids as $model) { + $hooks[] = _islandora_escape_pid_for_function($model) . '_' . $hook; + } + $hooks[] = $hook; + + return $hooks; +} + /** * a function to call other modules edit page. If there are not any modules * that handle this function this module will build a default page. @@ -300,64 +328,27 @@ function islandora_edit_object($object) { return drupal_not_found(); } - $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 hook_islandora_type_info(). - * - * @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 + // Accumulate the output. $output = array(); - // Get the models... - $supported_models = islandora_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); - } - } + // Call cmodel oriented variants first. + foreach (_islandora_build_hook_list(ISLANDORA_EDIT_HOOK, $object->models) as $hook) { + $temp = module_invoke_all($hook, $object); + if (!empty($temp)) { + $output = array_merge_recursive($output, $temp); } } + // Add in the default, if we did not get any results. + if (empty($output)) { + $output = _islandora_islandora_edit_object($object); + } + arsort($output); - drupal_alter($hook . '_output', $output); + drupal_alter(ISLANDORA_EDIT_HOOK, $object, $output); - return $output; + return implode('', $output); } /** @@ -382,7 +373,7 @@ function islandora_edit_properties($object_id) { * @param object $fedora_object * A tuque Fedora Object */ -function islandora_islandora_edit_object($fedora_object) { +function _islandora_islandora_edit_object($fedora_object) { $output = theme('islandora_default_edit', array( 'islandora_object' => $fedora_object, )); @@ -416,12 +407,26 @@ function islandora_view_object($fedora_object = NULL) { $page_number = (empty($_GET['page'])) ? '1' : $_GET['page']; $page_size = (empty($_GET['pagesize'])) ? '10' : $_GET['pagesize']; - $output = islandora_invoke(ISLANDORA_VIEW_HOOK, $fedora_object, $user, $page_number, $page_size); + // Accumulate the output. + $output = array(); + + // Call cmodel oriented variants first. + foreach (_islandora_build_hook_list(ISLANDORA_VIEW_HOOK, $fedora_object->models) as $hook) { + $temp = module_invoke_all($hook, $fedora_object, $user, $page_number, $page_size); + if (!empty($temp)) { + $output = array_merge_recursive($output, $temp); + } + } + // Add in the default, if we did not get any results. if (empty($output)) { - $output = islandora_islandora_view_object($fedora_object); + $output = _islandora_islandora_view_object($fedora_object); } + arsort($output); + + drupal_alter(ISLANDORA_VIEW_HOOK, $fedora_object, $output); + return implode('', $output); } @@ -432,7 +437,7 @@ function islandora_view_object($fedora_object = NULL) { * @param string $object_id * @return string */ -function islandora_islandora_view_object($object) { +function _islandora_islandora_view_object($object) { $output = theme('islandora_default', array('islandora_object' => $object)); return array('Default Output' => $output); } @@ -547,7 +552,15 @@ function islandora_object_purge($object_id) { return; } $content_models = $object->models; - $arr = islandora_invoke(ISLANDORA_PRE_PURGE_OBJECT_HOOK, $object); // notify modules of pending deletion + + $arr = array(); + foreach (_islandora_build_hook_list(ISLANDORA_PRE_PURGE_OBJECT_HOOK, $object->models) as $hook) { + $temp = module_invoke_all($hook, $object); + if (!empty($temp)) { + $arr = array_merge_recursive($arr, $temp); + } + } + if (isset($arr['delete']) && $arr['delete']) { try { $object->delete();