From 08085c005aff72358125f3ce6d81f5934728f3ac Mon Sep 17 00:00:00 2001 From: Bram Goffings Date: Mon, 2 Apr 2012 10:49:14 +0200 Subject: [PATCH] graph --- core/includes/graph.inc | 145 ---------------------------- core/includes/module.inc | 6 +- core/includes/update.inc | 26 +++--- core/lib/Drupal/Component/Graph/Graph.php | 150 +++++++++++++++++++++++++++++ core/modules/simpletest/tests/graph.test | 18 ++-- 5 files changed, 176 insertions(+), 169 deletions(-) delete mode 100644 core/includes/graph.inc create mode 100644 core/lib/Drupal/Component/Graph/Graph.php diff --git a/core/includes/graph.inc b/core/includes/graph.inc deleted file mode 100644 index 9ef86a1..0000000 --- a/core/includes/graph.inc +++ /dev/null @@ -1,145 +0,0 @@ - array(), - // The components of the graph. - 'components' => array(), - ); - // Perform the actual sort. - foreach ($graph as $start => $data) { - _drupal_depth_first_search($graph, $state, $start); - } - - // We do such a numbering that every component starts with 0. This is useful - // for module installs as we can install every 0 weighted module in one - // request, and then every 1 weighted etc. - $component_weights = array(); - - foreach ($state['last_visit_order'] as $vertex) { - $component = $graph[$vertex]['component']; - if (!isset($component_weights[$component])) { - $component_weights[$component] = 0; - } - $graph[$vertex]['weight'] = $component_weights[$component]--; - } -} - -/** - * Performs a depth-first sort on a graph. - * - * @param $graph - * A three dimensional associated graph array. - * @param $state - * An associative array. The key 'last_visit_order' stores a list of the - * vertices visited. The key components stores list of vertices belonging - * to the same the component. - * @param $start - * An arbitrary vertex where we started traversing the graph. - * @param $component - * The component of the last vertex. - * - * @see drupal_depth_first_search() - */ -function _drupal_depth_first_search(&$graph, &$state, $start, &$component = NULL) { - // Assign new component for each new vertex, i.e. when not called recursively. - if (!isset($component)) { - $component = $start; - } - // Nothing to do, if we already visited this vertex. - if (isset($graph[$start]['paths'])) { - return; - } - // Mark $start as visited. - $graph[$start]['paths'] = array(); - - // Assign $start to the current component. - $graph[$start]['component'] = $component; - $state['components'][$component][] = $start; - - // Visit edges of $start. - if (isset($graph[$start]['edges'])) { - foreach ($graph[$start]['edges'] as $end => $v) { - // Mark that $start can reach $end. - $graph[$start]['paths'][$end] = $v; - - if (isset($graph[$end]['component']) && $component != $graph[$end]['component']) { - // This vertex already has a component, use that from now on and - // reassign all the previously explored vertices. - $new_component = $graph[$end]['component']; - foreach ($state['components'][$component] as $vertex) { - $graph[$vertex]['component'] = $new_component; - $state['components'][$new_component][] = $vertex; - } - unset($state['components'][$component]); - $component = $new_component; - } - // Only visit existing vertices. - if (isset($graph[$end])) { - // Visit the connected vertex. - _drupal_depth_first_search($graph, $state, $end, $component); - - // All vertices reachable by $end are also reachable by $start. - $graph[$start]['paths'] += $graph[$end]['paths']; - } - } - } - - // Now that any other subgraph has been explored, add $start to all reverse - // paths. - foreach ($graph[$start]['paths'] as $end => $v) { - if (isset($graph[$end])) { - $graph[$end]['reverse_paths'][$start] = $v; - } - } - - // Record the order of the last visit. This is the reverse of the - // topological order if the graph is acyclic. - $state['last_visit_order'][] = $start; -} diff --git a/core/includes/module.inc b/core/includes/module.inc index df9c138..3c66461 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -5,6 +5,8 @@ * API for loading and interacting with Drupal modules. */ +use Drupal\Component\Graph\Graph; + /** * Load all the modules that have been enabled in the system table. * @@ -240,7 +242,6 @@ function system_list_reset() { * without this module. */ function _module_build_dependencies($files) { - require_once DRUPAL_ROOT . '/core/includes/graph.inc'; foreach ($files as $filename => $file) { $graph[$file->name]['edges'] = array(); if (isset($file->info['dependencies']) && is_array($file->info['dependencies'])) { @@ -250,7 +251,8 @@ function _module_build_dependencies($files) { } } } - drupal_depth_first_search($graph); + $graphObject = new Graph(); + $graphObject->search($graph); foreach ($graph as $module => $data) { $files[$module]->required_by = isset($data['reverse_paths']) ? $data['reverse_paths'] : array(); $files[$module]->requires = isset($data['paths']) ? $data['paths'] : array(); diff --git a/core/includes/update.inc b/core/includes/update.inc index 1660d7d..b0f1a30 100644 --- a/core/includes/update.inc +++ b/core/includes/update.inc @@ -8,6 +8,8 @@ * installation. It is included and used extensively by update.php. */ +use Drupal\Component\Graph\Graph; + /** * Minimum schema version of Drupal 7 required for upgrade to Drupal 8. * @@ -562,7 +564,7 @@ function update_get_update_list() { * * In addition, the returned array also includes detailed information about the * dependency chain for each update, as provided by the depth-first search - * algorithm in drupal_depth_first_search(). + * algorithm in Drupal\Component\Graph\Graph::search(). * * @param $starting_updates * An array whose keys contain the names of modules with updates to be run @@ -575,7 +577,7 @@ function update_get_update_list() { * request, arranged in the order in which the update functions should be * run. (This includes the provided starting update for each module and all * subsequent updates that are available.) The values are themselves arrays - * containing all the keys provided by the drupal_depth_first_search() + * containing all the keys provided by the Drupal\Component\Graph\Graph::search() * algorithm, which encode detailed information about the dependency chain * for this update function (for example: 'paths', 'reverse_paths', 'weight', * and 'component'), as well as the following additional keys: @@ -588,7 +590,7 @@ function update_get_update_list() { * - 'module': The name of the module that this update function belongs to. * - 'number': The number of this update function within that module. * - * @see drupal_depth_first_search() + * @see Drupal\Component\Graph\Graph::search() */ function update_resolve_dependencies($starting_updates) { // Obtain a dependency graph for the requested update functions. @@ -596,8 +598,8 @@ function update_resolve_dependencies($starting_updates) { $graph = update_build_dependency_graph($update_functions); // Perform the depth-first search and sort the results. - require_once DRUPAL_ROOT . '/core/includes/graph.inc'; - drupal_depth_first_search($graph); + $graphObject = new Graph(); + $graphObject->search($graph); uasort($graph, 'drupal_sort_weight'); foreach ($graph as $function => &$data) { @@ -692,18 +694,18 @@ function update_get_update_function_list($starting_updates) { * * @return * A multidimensional array representing the dependency graph, suitable for - * passing in to drupal_depth_first_search(), but with extra information + * passing in to Drupal\Component\Graph\Graph::search(), but with extra information * about each update function also included. Each array key contains the name * of an update function, including all update functions from the provided * list as well as any outside update functions which they directly depend * on. Each value is an associative array containing the following keys: * - 'edges': A representation of any other update functions that immediately - * depend on this one. See drupal_depth_first_search() for more details on - * the format. + * depend on this one. See Drupal\Component\Graph\Graph::search() for more + * details on the format. * - 'module': The name of the module that this update function belongs to. * - 'number': The number of this update function within that module. * - * @see drupal_depth_first_search() + * @see Drupal\Component\Graph\Graph::search() * @see update_resolve_dependencies() */ function update_build_dependency_graph($update_functions) { @@ -851,7 +853,7 @@ function update_retrieve_dependencies() { /** * Updates config with values set on Drupal 7.x - * + * * Provide a generalised method to migrate variables from Drupal 7 to Drupal 8's * configuration management system. * @@ -863,8 +865,8 @@ function update_retrieve_dependencies() { * An array to map new to old configuration naming conventions. Example: * @code * array('new_config' => 'old_config') - * @endcode - * This would update the value for new_config to the value old_config has in + * @endcode + * This would update the value for new_config to the value old_config has in * the variable table. */ function update_variables_to_config($config_name, $variable_map = array()) { diff --git a/core/lib/Drupal/Component/Graph/Graph.php b/core/lib/Drupal/Component/Graph/Graph.php new file mode 100644 index 0000000..7cfded4 --- /dev/null +++ b/core/lib/Drupal/Component/Graph/Graph.php @@ -0,0 +1,150 @@ + array(), + // The components of the graph. + 'components' => array(), + ); + // Perform the actual sort. + foreach ($graph as $start => $data) { + $this->sort($graph, $state, $start); + } + + // We do such a numbering that every component starts with 0. This is useful + // for module installs as we can install every 0 weighted module in one + // request, and then every 1 weighted etc. + $component_weights = array(); + + foreach ($state['last_visit_order'] as $vertex) { + $component = $graph[$vertex]['component']; + if (!isset($component_weights[$component])) { + $component_weights[$component] = 0; + } + $graph[$vertex]['weight'] = $component_weights[$component]--; + } + } + + /** + * Performs a depth-first sort on a graph. + * + * @param $graph + * A three dimensional associated graph array. + * @param $state + * An associative array. The key 'last_visit_order' stores a list of the + * vertices visited. The key components stores list of vertices belonging + * to the same the component. + * @param $start + * An arbitrary vertex where we started traversing the graph. + * @param $component + * The component of the last vertex. + * + * @see Drupal\Component\Graph\Graph::search() + */ + protected function sort(&$graph, &$state, $start, &$component = NULL) { + // Assign new component for each new vertex, i.e. when not called recursively. + if (!isset($component)) { + $component = $start; + } + // Nothing to do, if we already visited this vertex. + if (isset($graph[$start]['paths'])) { + return; + } + // Mark $start as visited. + $graph[$start]['paths'] = array(); + + // Assign $start to the current component. + $graph[$start]['component'] = $component; + $state['components'][$component][] = $start; + + // Visit edges of $start. + if (isset($graph[$start]['edges'])) { + foreach ($graph[$start]['edges'] as $end => $v) { + // Mark that $start can reach $end. + $graph[$start]['paths'][$end] = $v; + + if (isset($graph[$end]['component']) && $component != $graph[$end]['component']) { + // This vertex already has a component, use that from now on and + // reassign all the previously explored vertices. + $new_component = $graph[$end]['component']; + foreach ($state['components'][$component] as $vertex) { + $graph[$vertex]['component'] = $new_component; + $state['components'][$new_component][] = $vertex; + } + unset($state['components'][$component]); + $component = $new_component; + } + // Only visit existing vertices. + if (isset($graph[$end])) { + // Visit the connected vertex. + $this->sort($graph, $state, $end, $component); + + // All vertices reachable by $end are also reachable by $start. + $graph[$start]['paths'] += $graph[$end]['paths']; + } + } + } + + // Now that any other subgraph has been explored, add $start to all reverse + // paths. + foreach ($graph[$start]['paths'] as $end => $v) { + if (isset($graph[$end])) { + $graph[$end]['reverse_paths'][$start] = $v; + } + } + + // Record the order of the last visit. This is the reverse of the + // topological order if the graph is acyclic. + $state['last_visit_order'][] = $start; + } +} diff --git a/core/modules/simpletest/tests/graph.test b/core/modules/simpletest/tests/graph.test index e60cd39..a93cd71 100644 --- a/core/modules/simpletest/tests/graph.test +++ b/core/modules/simpletest/tests/graph.test @@ -5,6 +5,8 @@ * Provides unit tests for graph.inc. */ +use Drupal\Component\Graph\Graph; + /** * Unit tests for the graph handling features. */ @@ -17,11 +19,6 @@ class GraphUnitTest extends DrupalUnitTestCase { ); } - function setUp() { - require_once DRUPAL_ROOT . '/core/includes/graph.inc'; - parent::setUp(); - } - /** * Test depth-first-search features. */ @@ -42,7 +39,8 @@ class GraphUnitTest extends DrupalUnitTestCase { 8 => array(9), 9 => array(), )); - drupal_depth_first_search($graph); + $graphObject = new Graph(); + $graphObject->search($graph); $expected_paths = array( 1 => array(2, 3, 4), @@ -106,7 +104,7 @@ class GraphUnitTest extends DrupalUnitTestCase { * Verify expected paths in a graph. * * @param $graph - * A graph array processed by drupal_depth_first_search(). + * A graph array processed by Drupal\Component\Graph\Graph::search(). * @param $expected_paths * An associative array containing vertices with their expected paths. */ @@ -123,7 +121,7 @@ class GraphUnitTest extends DrupalUnitTestCase { * Verify expected reverse paths in a graph. * * @param $graph - * A graph array processed by drupal_depth_first_search(). + * A graph array processed by Drupal\Component\Graph\Graph::search(). * @param $expected_reverse_paths * An associative array containing vertices with their expected reverse * paths. @@ -141,7 +139,7 @@ class GraphUnitTest extends DrupalUnitTestCase { * Verify expected components in a graph. * * @param $graph - * A graph array processed by drupal_depth_first_search(). + * A graph array processed by Drupal\Component\Graph\Graph::search(). * @param $expected_components * An array containing of components defined as a list of their vertices. */ @@ -162,7 +160,7 @@ class GraphUnitTest extends DrupalUnitTestCase { * Verify expected order in a graph. * * @param $graph - * A graph array processed by drupal_depth_first_search(). + * A graph array processed by Drupal\Component\Graph\Graph::search(). * @param $expected_orders * An array containing lists of vertices in their expected order. */ -- 1.7.5.4