From 980b7eebda6be3073ba7b2e5b6fcb2480bc48382 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Thu, 6 Dec 2012 10:59:34 -0400 Subject: [PATCH 1/3] Rebuild list of steps with every request. ... This should allow steps to be added/omitted in a more flexible manner. --- includes/ingest.form.inc | 190 ++++++++++++++++++++++++++++++--------- 1 file changed, 148 insertions(+), 42 deletions(-) diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index ad4fc308..94d692e8 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -24,7 +24,7 @@ * - label: The initial label for the object. Defaults to "New Object". * - collections: An array of collection PIDs, to which the new object should * be related. - * - models: An array of content model PIDs, to which the new object should + * - models: An array of content model PIDs, to which the new object might * subscribe * * @return array @@ -32,7 +32,10 @@ */ function islandora_ingest_form(array $form, array &$form_state, array $configuration) { islandora_ingest_form_init_form_state($form_state, $configuration); - return islandora_ingest_form_execute_step($form, $form_state); + + $form = islandora_ingest_form_execute_step($form, $form_state); + + return $form; } /** @@ -49,12 +52,6 @@ function islandora_ingest_form(array $form, array &$form_state, array $configura function islandora_ingest_form_init_form_state(array &$form_state, array $configuration) { // First time initialization of storage. islandora_ingest_form_init_form_state_storage($form_state, $configuration); - $steps = &islandora_ingest_form_get_steps($form_state); - // Always re-sort the steps just incase any build/submit handlers have - // appended new steps. - usort($steps, 'drupal_sort_weight'); - // Load any required files for the current step. - islandora_ingest_form_step_form_load_include($form_state); } /** @@ -67,8 +64,8 @@ function islandora_ingest_form_init_form_state(array &$form_state, array $config * executed. */ function islandora_ingest_form_init_form_state_storage(array &$form_state, array $configuration) { - module_load_include('inc', 'islandora', 'includes/utilities'); if (empty($form_state['islandora'])) { + module_load_include('inc', 'islandora', 'includes/utilities'); // Use ID if given. $id = isset($configuration['id']) ? $configuration['id'] : NULL; // Use namespace if ID not given. @@ -78,12 +75,40 @@ function islandora_ingest_form_init_form_state_storage(array &$form_state, array $relationships = empty($configuration['collections']) ? array() : array_map($relationship_map, $configuration['collections']); $object = islandora_prepare_new_object($namespace, $label, array(), array(), $relationships); $form_state['islandora'] = array( - 'step' => 0, - 'steps' => islandora_ingest_get_steps($configuration), + 'step_id' => NULL, 'objects' => array($object), - 'configuration' => $configuration + 'configuration' => $configuration, + 'step_storage' => array(), ); } + + $form_state['islandora']['steps'] = islandora_ingest_get_steps($form_state); + + if ($form_state['islandora']['step_id'] === NULL || !array_key_exists( + $form_state['islandora']['step_id'], $form_state['islandora']['steps'])) { + reset($form_state['islandora']['steps']); + $form_state['islandora']['step_id'] = key($form_state['islandora']['steps']); + } +} + +/** + * Build a list of steps given only configuration. + * + * XXX: This is used to give an indication of whether there are any steps for a + * given list of content models. + * + * @param array $configuration + * The list of key/value pairs of configuration. + */ +function islandora_ingest_get_approximate_steps(array $configuration) { + $fake_form_state = array( + 'islandora' => array( + 'configuration' => $configuration, + ), + ); + $steps = islandora_ingest_get_steps($fake_form_state); + drupal_static_reset('islandora_ingest_get_steps'); + return $steps; } /** @@ -99,7 +124,11 @@ function islandora_ingest_form_init_form_state_storage(array &$form_state, array * The form definition of the current step. */ function islandora_ingest_form_execute_step(array $form, array &$form_state) { + // Load any required files for the current step. + islandora_ingest_form_step_form_load_include($form_state); + $step_info = islandora_ingest_form_get_step_info($form_state); + switch ($step_info['type']) { case 'form': $args = array($form, &$form_state); @@ -127,7 +156,8 @@ function islandora_ingest_form_execute_step(array $form, array &$form_state) { * The stepified drupal form definition for the given step. */ function islandora_ingest_form_stepify(array $form, array &$form_state, array $step_info) { - $step = islandora_ingest_form_get_step($form_state); + $step = islandora_ingest_form_get_step_number($form_state); + $first_step = $step > 0; $last_step = $step == (islandora_ingest_form_get_step_count($form_state) - 1); $form['prev'] = $first_step ? islandora_ingest_form_previous_button() : NULL; @@ -158,6 +188,15 @@ function islandora_ingest_form_previous_button() { ); } +function islandora_ingest_form_get_step_number($form_state, $step_id = NULL) { + if ($step_id === NULL) { + $step_id = islandora_ingest_form_get_step_id($form_state); + } + + $steps = array_flip(array_keys(islandora_ingest_form_get_steps($form_state))); + return $steps[$step_id]; +} + /** * The submit handler for the ingest form previous button. * @@ -171,12 +210,11 @@ function islandora_ingest_form_previous_button() { * The drupal form state. */ function islandora_ingest_form_previous_submit(array $form, array &$form_state) { - $step = &islandora_ingest_form_get_step($form_state); - $step_info = &islandora_ingest_form_get_step_info($form_state, $step); - $step_info['values'] = $form_state['values']; - $step--; - $step_info = &islandora_ingest_form_get_step_info($form_state, $step); - $form_state['values'] = isset($step_info['values']) ? $step_info['values'] : NULL; + $step = islandora_ingest_form_get_step_number($form_state); + islandora_ingest_form_stash_info($form_state); + $step = max(array($step - 1, 0)) ; + $form_state['islandora']['step_id'] = islandora_ingest_form_get_step_id($form_state, $step); + islandora_ingest_form_grab_info($form_state); $form_state['rebuild'] = TRUE; } @@ -216,15 +254,38 @@ function islandora_ingest_form_next_button(array $step_info) { * The drupal form state. */ function islandora_ingest_form_next_submit(array $form, array &$form_state) { - $step = &islandora_ingest_form_get_step($form_state); - $step_info = &islandora_ingest_form_get_step_info($form_state, $step); - $step_info['values'] = $form_state['values']; - $step++; - $step_info = &islandora_ingest_form_get_step_info($form_state, $step); - $form_state['values'] = isset($step_info['values']) ? $step_info['values'] : array(); + $step = islandora_ingest_form_get_step_number($form_state); + islandora_ingest_form_stash_info($form_state); + $step = min(array($step + 1, islandora_ingest_form_get_step_count($form_state))) ; + $form_state['islandora']['step_id'] = islandora_ingest_form_get_step_id($form_state, $step); + islandora_ingest_form_grab_info($form_state); $form_state['rebuild'] = TRUE; } +/** + * Push current info into the current step's storage. + */ +function islandora_ingest_form_stash_info(array &$form_state) { + $storage = &islandora_ingest_form_get_step_storage($form_state); + $storage['values'] = $form_state['values']; + $storage['configuration'] = $form_state['islandora']['configuration']; + unset($form_state['values']); +} + +/** + * Pops the info for the given step from storage into the form_state. + */ +function islandora_ingest_form_grab_info(array &$form_state) { + $storage = islandora_ingest_form_get_step_storage($form_state); + $form_state['values'] = isset($storage['values'])?$storage['values']:array(); + $form_state['islandora']['configuration'] = array_merge( + $form_state['islandora']['configuration'], + isset($storage['configuration'])? + $storage['configuration']: + array() + ); +} + /** * Defines the ingest button for the ingest form. * @@ -280,7 +341,7 @@ function islandora_ingest_form_submit(array $form, array &$form_state) { * @return array * The configuration used to generate the multi-page ingest forms. */ -function islandora_ingest_form_get_configuration(array $form_state) { +function &islandora_ingest_form_get_configuration(array $form_state) { return $form_state['islandora']['configuration']; } @@ -311,7 +372,7 @@ function &islandora_ingest_form_get_objects(array $form_state) { * @param array $form_state * The drupal form state. * - * @return array + * @return NewFedoraObject * Returns the 'current' object in the array of NewFedoraObjects, generally * this is only used when there is one object in the list of objects. */ @@ -326,11 +387,17 @@ function islandora_ingest_form_get_object(array $form_state) { * @param array $form_state * The drupal form state. * - * @return int + * @return string * The current step index. */ -function &islandora_ingest_form_get_step(array &$form_state) { - return $form_state['islandora']['step']; +function islandora_ingest_form_get_step_id(array &$form_state, $step_number = NULL) { + if ($step_number === NULL) { + return $form_state['islandora']['step_id']; + } + else { + $steps = array_keys(islandora_ingest_form_get_steps($form_state)); + return $steps[$step_number]; + } } /** @@ -346,7 +413,7 @@ function &islandora_ingest_form_get_step(array &$form_state) { * The step info of the requested step if found, NULL otherwise. */ function &islandora_ingest_form_get_step_info(array &$form_state, $step = NULL) { - $step = isset($step) ? $step : islandora_ingest_form_get_step($form_state); + $step = isset($step) ? $step : islandora_ingest_form_get_step_id($form_state); $steps = &islandora_ingest_form_get_steps($form_state); if (!empty($steps[$step])) { return $steps[$step]; @@ -355,6 +422,21 @@ function &islandora_ingest_form_get_step_info(array &$form_state, $step = NULL) return NULL; } +/** + * Get general storage for the given step. (or the current step) + */ +function &islandora_ingest_form_get_step_storage(array &$form_state, $step_id = NULL) { + if ($step_id === NULL) { + $step_id = islandora_ingest_form_get_step_id($form_state); + } + + if (!isset($form_state['islandora']['step_storage'][$step_id])) { + $form_state['islandora']['step_storage'][$step_id] = array(); + } + + return $form_state['islandora']['step_storage'][$step_id]; +} + /** * Get a reference to the steps stored in the form state. * @@ -407,22 +489,46 @@ function islandora_ingest_form_get_step_count(array $form_state) { * * The sort order is undefined for steps which have the same weight. * - * @param array $configuration - * The configuration options used to build the multi-paged ingest process. + * @param array $form_state + * All available form_state options used to build the multi-paged ingest process. * * @return array - * The initial list of sorted ingest steps as defined by all implementers + * The list of sorted ingest steps as defined by all implementers * of ISLANDORA_INGEST_STEP_HOOK. */ -function islandora_ingest_get_steps(array $configuration) { +function &islandora_ingest_get_steps(array &$form_state) { module_load_include('inc', 'islandora', 'includes/utilities'); - $steps = array(); - $models = isset($configuration['models']) ? $configuration['models'] : array(); - foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $models) as $hook) { - $steps = array_merge($steps, module_invoke_all($hook, $configuration)); + $steps = &drupal_static(__FUNCTION__); + + if (!isset($steps)) { + $steps = array(); + $configuration = islandora_ingest_form_get_configuration($form_state); + $models = array(); + if (isset($configuration['selected_models'])) { + $models = $configuration['selected_models']; + } + elseif (isset($configuration['models'])) { + $models = $configuration['models']; + } + + foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $models) as $hook) { + // Need to pass by ref... But don't really want an alter. + foreach (module_implements($hook) as $module) { + $function = $module . '_' . $hook; + $steps = array_merge($steps, (array)$function($form_state)); + } + } + + // Remove NULL values. + $steps = array_filter($steps); + uasort($steps, 'drupal_sort_weight'); + foreach (islandora_build_hook_list(ISLANDORA_INGEST_STEP_HOOK, $models) as $hook) { + $form_state_copy = $form_state; + drupal_alter($hook, $steps, $form_state_copy); + } + + uasort($steps, 'drupal_sort_weight'); } - // Remove NULL values. - $steps = array_filter($steps); - usort($steps, 'drupal_sort_weight'); + return $steps; } From f93e35fe87956ceb8cd75ce8ce032bd1fffbe9f4 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Thu, 6 Dec 2012 11:43:40 -0400 Subject: [PATCH 2/3] Update documentation. --- islandora.api.php | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/islandora.api.php b/islandora.api.php index 337814fa..f017f937 100644 --- a/islandora.api.php +++ b/islandora.api.php @@ -226,9 +226,14 @@ function hook_islandora_undeletable_datastreams(array $models) {} /** * Define steps used in the islandora_ingest_form() ingest process. * + * @param array $form_state + * An array containing the form_state, on which infomation from step storage + * might be extracted. Note that the + * * @return array - * An array of associative arrays which define each step in the ingest - * process. Steps are defined by by a number of properties (keys) including: + * An associative array of associative arrays which define each step in the + * ingest process. Each step should consist of a unique name mapped to an + * array of properties (keys) including: * - type: The type of step. Currently, only "form" is implemented. * - weight: The "weight" of this step--heavier(/"larger") values sink to the * end of the process while smaller(/"lighter") values are executed first. @@ -240,9 +245,9 @@ function hook_islandora_undeletable_datastreams(array $models) {} * - file: A file to include (relative to the module's path, including the * file's extension). */ -function hook_islandora_ingest_steps(array $configuration) { +function hook_islandora_ingest_steps(array $form_state) { return array( - array( + 'my_cool_step_definition' => array( 'type' => 'form', 'weight' => 1, 'form_id' => 'my_cool_form', @@ -253,6 +258,11 @@ function hook_islandora_ingest_steps(array $configuration) { /** * Content model specific version of hook_islandora_ingest_steps(). * + * XXX: Content models are not selected in a generic manner. Currently, this + * gets called for every content model in the "configuration", yet the + * configuration never changes. We should determine a consistent way to bind + * content models, so as to consistently be able to build steps. + * * @see hook_islandora_ingest_steps() */ -function hook_CMODEL_PID_islandora_ingest_steps(array $configuration) {} +function hook_CMODEL_PID_islandora_ingest_steps(array $form_state) {} From edd8b9eda02014ec5bd23afb8a89294a469cb495 Mon Sep 17 00:00:00 2001 From: Adam Vessey Date: Thu, 6 Dec 2012 15:51:29 -0400 Subject: [PATCH 3/3] Fix off-by-one error. --- includes/ingest.form.inc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 94d692e8..34089f7b 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -256,7 +256,7 @@ function islandora_ingest_form_next_button(array $step_info) { function islandora_ingest_form_next_submit(array $form, array &$form_state) { $step = islandora_ingest_form_get_step_number($form_state); islandora_ingest_form_stash_info($form_state); - $step = min(array($step + 1, islandora_ingest_form_get_step_count($form_state))) ; + $step = min(array($step + 1, islandora_ingest_form_get_step_count($form_state) - 1)) ; $form_state['islandora']['step_id'] = islandora_ingest_form_get_step_id($form_state, $step); islandora_ingest_form_grab_info($form_state); $form_state['rebuild'] = TRUE;