From 978026b0031ce429080d8e178276edc8eeed4010 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Tue, 30 Oct 2012 17:45:31 -0300 Subject: [PATCH] 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();