From 60b848b9220f1e6490af5bb3118ff23b549e49a4 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 22 Dec 2016 15:22:01 -0400 Subject: [PATCH] Define new function islandora_sort_ordered This function can replace calls to uasort with drupal_sort_weight. This function will return a consistant sort order between PHP5 and PHP7 for elements of the same weight by preserving the order of elements with the same weight. Under both PHP5 and PHP7 the order of elements with the same weight are not guarenteed, and in practice the order of elements returned is different between PHP5 and PHP7. This could cause some issues where the order is changed depending on PHP version. This function gives us the option of a consistant sort order. This pull request also defines some new unit tests for the new function. --- includes/derivatives.inc | 2 +- includes/ingest.form.inc | 4 +- includes/utilities.inc | 38 ++++++++++++ islandora.info | 1 + tests/utilities.test | 131 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 4 deletions(-) create mode 100644 tests/utilities.test diff --git a/includes/derivatives.inc b/includes/derivatives.inc index 9b44b9af..085a1ec6 100644 --- a/includes/derivatives.inc +++ b/includes/derivatives.inc @@ -306,6 +306,6 @@ function islandora_get_derivative_list(AbstractObject $object, &$options) { drupal_alter($hook, $derivatives, $object, $ds_modified_params); } - uasort($derivatives, 'drupal_sort_weight'); + islandora_sort_ordered($derivatives, array('weight')); return islandora_filter_derivatives($derivatives, $options, $object); } diff --git a/includes/ingest.form.inc b/includes/ingest.form.inc index 7fd95f9b..78a2577e 100644 --- a/includes/ingest.form.inc +++ b/includes/ingest.form.inc @@ -882,8 +882,6 @@ function islandora_ingest_form_load_include(array &$form_state) { * * Sorted by weight expected range between -50 to 50. * - * The sort order is undefined for steps which have the same weight. - * * @param array $form_state * The Drupal form state. * @@ -917,7 +915,7 @@ function islandora_ingest_form_get_steps(array &$form_state) { foreach ($steps as $key => &$step) { $step['id'] = $key; } - uasort($steps, 'drupal_sort_weight'); + islandora_sort_ordered($steps, array('weight')); return $steps; } diff --git a/includes/utilities.inc b/includes/utilities.inc index dcbaab02..13f97d21 100644 --- a/includes/utilities.inc +++ b/includes/utilities.inc @@ -966,3 +966,41 @@ function islandora_build_datastream_edit_registry(AbstractDatastream $datastream drupal_alter(ISLANDORA_EDIT_DATASTREAM_REGISTRY_HOOK, $edit_registry, $context); return $edit_registry; } + +/** + * Sorts a structured array by a user selectable element. + * + * This function will preserve the order of elements in the array with the + * same weight. + * + * @param array $array + * The array to be sorted. + * @param array $sort_keys + * An array containing the keys to sort the array by. + */ +function islandora_sort_ordered(&$array, $sort_keys) { + $array_temp = array(); + foreach ($array as $key => $value) { + $weight = $value; + + foreach ($sort_keys as $sort_key) { + if (is_array($weight) && isset($weight[$sort_key])) { + $weight = $weight[$sort_key]; + } + else { + $weight = 0; + break; + } + } + + $array_temp[$weight][$key] = $value; + unset($array[$key]); + } + + ksort($array_temp); + + foreach ($array_temp as $key => $value) { + $array += $value; + unset($array_temp[$key]); + } +} diff --git a/islandora.info b/islandora.info index 55c50359..1e84ce16 100644 --- a/islandora.info +++ b/islandora.info @@ -27,4 +27,5 @@ files[] = tests/datastream_versions.test files[] = tests/datastream_cache.test files[] = tests/derivatives.test files[] = tests/datastream_validator_tests.test +files[] = tests/utilities.test php = 5.3 diff --git a/tests/utilities.test b/tests/utilities.test new file mode 100644 index 00000000..4bbaf3be --- /dev/null +++ b/tests/utilities.test @@ -0,0 +1,131 @@ + 'islandora_sort_ordered()', + 'description' => 'Performs unit tests on islandora_sort_oredered().', + 'group' => 'Islandora', + ); + } + + /** + * Test sort order when sorting by weight. + */ + public function testIslandoraSortOrderedSorting() { + module_load_include('inc', 'islandora', 'includes/utilities'); + + // The order of children with same weight should be preserved. + $element_mixed_weight = array( + 'child5' => array('weight' => 10), + 'child3' => array('weight' => -10), + 'child1' => array(), + 'child4' => array('weight' => 10), + 'child2' => array(), + 'child6' => array('weight' => 10), + 'child9' => array(), + 'child8' => array('weight' => 10), + 'child7' => array(), + ); + + $expected = array( + 'child3' => array('weight' => -10), + 'child1' => array(), + 'child2' => array(), + 'child9' => array(), + 'child7' => array(), + 'child5' => array('weight' => 10), + 'child4' => array('weight' => 10), + 'child6' => array('weight' => 10), + 'child8' => array('weight' => 10), + ); + + islandora_sort_ordered($element_mixed_weight, array('weight')); + + $this->assertEqual($expected, $element_mixed_weight, 'Order of elements with the same weight is preserved.'); + } + + /** + * Make sure numeric keys are preserved. + */ + public function testIslandoraSortPreserveNumeric() { + module_load_include('inc', 'islandora', 'includes/utilities'); + + // The order of children with same weight should be preserved. + $element_mixed_weight = array( + 5 => array('weight' => 10), + 3 => array('weight' => -10), + 1 => array(), + 4 => array('weight' => 10), + 2 => array(), + 6 => array('weight' => 10), + 9 => array(), + 8 => array('weight' => 10), + 7 => array(), + ); + + $expected = array( + 3 => array('weight' => -10), + 1 => array(), + 2 => array(), + 9 => array(), + 7 => array(), + 5 => array('weight' => 10), + 4 => array('weight' => 10), + 6 => array('weight' => 10), + 8 => array('weight' => 10), + ); + + islandora_sort_ordered($element_mixed_weight, array('weight')); + + $this->assertEqual($expected, $element_mixed_weight, 'Numeric keys are preserved while sorting.'); + } + + /** + * Test sort order when sorting by a key in a multidimensional array. + */ + public function testIslandoraSortOrderedMulti() { + module_load_include('inc', 'islandora', 'includes/utilities'); + + // The order of children with same weight should be preserved. + $element_mixed_weight = array( + 'child5' => array('foo' => array('bar' => 10)), + 'child3' => array('foo' => array('bar' => -10)), + 'child1' => array('foo' => 6), + 'child4' => array('foo' => array('bar' => 10)), + 'child2' => array(), + 'child6' => array('foo' => array('bar' => 10)), + 'child9' => array(array('woot')), + 'child8' => array('foo' => array('bar' => 10)), + 'child7' => array(), + ); + + $expected = array( + 'child3' => array('foo' => array('bar' => -10)), + 'child1' => array('foo' => 6), + 'child2' => array(), + 'child9' => array(array('woot')), + 'child7' => array(), + 'child5' => array('foo' => array('bar' => 10)), + 'child4' => array('foo' => array('bar' => 10)), + 'child6' => array('foo' => array('bar' => 10)), + 'child8' => array('foo' => array('bar' => 10)), + ); + + islandora_sort_ordered($element_mixed_weight, array('foo', 'bar')); + + $this->assertEqual($expected, $element_mixed_weight, 'Sorting by multidimensional array works.'); + } +}