public function testSort()
 {
     $graph = new Structures_Graph();
     $name1 = 'node1';
     $node1 = new Structures_Graph_Node();
     $node1->setData($name1);
     $graph->addNode($node1);
     $name11 = 'node11';
     $node11 = new Structures_Graph_Node();
     $node11->setData($name11);
     $graph->addNode($node11);
     $node1->connectTo($node11);
     $name12 = 'node12';
     $node12 = new Structures_Graph_Node();
     $node12->setData($name12);
     $graph->addNode($node12);
     $node1->connectTo($node12);
     $name121 = 'node121';
     $node121 = new Structures_Graph_Node();
     $node121->setData($name121);
     $graph->addNode($node121);
     $node12->connectTo($node121);
     $name2 = 'node2';
     $node2 = new Structures_Graph_Node();
     $node2->setData($name2);
     $graph->addNode($node2);
     $name21 = 'node21';
     $node21 = new Structures_Graph_Node();
     $node21->setData($name21);
     $graph->addNode($node21);
     $node2->connectTo($node21);
     $nodes = Structures_Graph_Manipulator_TopologicalSorter::sort($graph);
     $this->assertCount(2, $nodes[0]);
     $this->assertEquals('node1', $nodes[0][0]->getData());
     $this->assertEquals('node2', $nodes[0][1]->getData());
     $this->assertCount(3, $nodes[1]);
     $this->assertEquals('node11', $nodes[1][0]->getData());
     $this->assertEquals('node12', $nodes[1][1]->getData());
     $this->assertEquals('node21', $nodes[1][2]->getData());
     $this->assertCount(1, $nodes[2]);
     $this->assertEquals('node121', $nodes[2][0]->getData());
 }
Beispiel #2
0
 /**
  * Sort a list of arrays of array(downloaded packagefilename) by dependency.
  *
  * This uses the topological sort method from graph theory, and the
  * Structures_Graph package to properly sort dependencies for installation.
  * @param array an array of downloaded PEAR_Downloader_Packages
  * @return array array of array(packagefilename, package.xml contents)
  */
 function sortPackagesForInstall(&$packages)
 {
     require_once 'Structures/Graph.php';
     require_once 'Structures/Graph/Node.php';
     require_once 'Structures/Graph/Manipulator/TopologicalSorter.php';
     $depgraph = new Structures_Graph(true);
     $nodes = array();
     $reg =& $this->config->getRegistry();
     foreach ($packages as $i => $package) {
         $pname = $reg->parsedPackageNameToString(array('channel' => $package->getChannel(), 'package' => strtolower($package->getPackage())));
         $nodes[$pname] = new Structures_Graph_Node();
         $nodes[$pname]->setData($packages[$i]);
         $depgraph->addNode($nodes[$pname]);
     }
     $deplinks = array();
     foreach ($nodes as $package => $node) {
         $pf =& $node->getData();
         $pdeps = $pf->getDeps(true);
         if (!$pdeps) {
             continue;
         }
         if ($pf->getPackagexmlVersion() == '1.0') {
             foreach ($pdeps as $dep) {
                 if ($dep['type'] != 'pkg' || isset($dep['optional']) && $dep['optional'] == 'yes') {
                     continue;
                 }
                 $dname = $reg->parsedPackageNameToString(array('channel' => 'pear.php.net', 'package' => strtolower($dep['name'])));
                 if (isset($nodes[$dname])) {
                     if (!isset($deplinks[$dname])) {
                         $deplinks[$dname] = array();
                     }
                     $deplinks[$dname][$package] = 1;
                     // dependency is in installed packages
                     continue;
                 }
                 $dname = $reg->parsedPackageNameToString(array('channel' => 'pecl.php.net', 'package' => strtolower($dep['name'])));
                 if (isset($nodes[$dname])) {
                     if (!isset($deplinks[$dname])) {
                         $deplinks[$dname] = array();
                     }
                     $deplinks[$dname][$package] = 1;
                     // dependency is in installed packages
                     continue;
                 }
             }
         } else {
             // the only ordering we care about is:
             // 1) subpackages must be installed before packages that depend on them
             // 2) required deps must be installed before packages that depend on them
             if (isset($pdeps['required']['subpackage'])) {
                 $t = $pdeps['required']['subpackage'];
                 if (!isset($t[0])) {
                     $t = array($t);
                 }
                 $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
             }
             if (isset($pdeps['group'])) {
                 if (!isset($pdeps['group'][0])) {
                     $pdeps['group'] = array($pdeps['group']);
                 }
                 foreach ($pdeps['group'] as $group) {
                     if (isset($group['subpackage'])) {
                         $t = $group['subpackage'];
                         if (!isset($t[0])) {
                             $t = array($t);
                         }
                         $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
                     }
                 }
             }
             if (isset($pdeps['optional']['subpackage'])) {
                 $t = $pdeps['optional']['subpackage'];
                 if (!isset($t[0])) {
                     $t = array($t);
                 }
                 $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
             }
             if (isset($pdeps['required']['package'])) {
                 $t = $pdeps['required']['package'];
                 if (!isset($t[0])) {
                     $t = array($t);
                 }
                 $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
             }
             if (isset($pdeps['group'])) {
                 if (!isset($pdeps['group'][0])) {
                     $pdeps['group'] = array($pdeps['group']);
                 }
                 foreach ($pdeps['group'] as $group) {
                     if (isset($group['package'])) {
                         $t = $group['package'];
                         if (!isset($t[0])) {
                             $t = array($t);
                         }
                         $this->_setupGraph($t, $reg, $deplinks, $nodes, $package);
                     }
                 }
             }
         }
     }
     $this->_detectDepCycle($deplinks);
     foreach ($deplinks as $dependent => $parents) {
         foreach ($parents as $parent => $unused) {
             $nodes[$dependent]->connectTo($nodes[$parent]);
         }
     }
     $installOrder = Structures_Graph_Manipulator_TopologicalSorter::sort($depgraph);
     $ret = array();
     for ($i = 0, $count = count($installOrder); $i < $count; $i++) {
         foreach ($installOrder[$i] as $index => $sortedpackage) {
             $data =& $installOrder[$i][$index]->getData();
             $ret[] =& $nodes[$reg->parsedPackageNameToString(array('channel' => $data->getChannel(), 'package' => strtolower($data->getPackage())))]->getData();
         }
     }
     $packages = $ret;
     return;
 }
 /**
  *
  * sort returns the graph's nodes, sorted by topological order. 
  * 
  * The result is an array with 
  * as many entries as topological levels. Each entry in this array is an array of nodes within
  * the given topological level.
  *
  * @return	array	 The graph's nodes, sorted by topological order.
  * @access	public
  */
 function sort(&$graph)
 {
     // We only sort graphs
     if (!is_a($graph, 'Structures_Graph')) {
         return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an object that is not a Structures_Graph', STRUCTURES_GRAPH_ERROR_GENERIC);
     }
     if (!Structures_Graph_Manipulator_AcyclicTest::isAcyclic($graph)) {
         return Pear::raiseError('Structures_Graph_Manipulator_TopologicalSorter::sort received an graph that has cycles', STRUCTURES_GRAPH_ERROR_GENERIC);
     }
     Structures_Graph_Manipulator_TopologicalSorter::_sort($graph);
     $result = array();
     // Fill out result array
     $nodes =& $graph->getNodes();
     $nodeKeys = array_keys($nodes);
     foreach ($nodeKeys as $key) {
         if (!array_key_exists($nodes[$key]->getMetadata('topological-sort-level'), $result)) {
             $result[$nodes[$key]->getMetadata('topological-sort-level')] = array();
         }
         $result[$nodes[$key]->getMetadata('topological-sort-level')][] =& $nodes[$key];
         $nodes[$key]->unsetMetadata('topological-sort-level');
     }
     return $result;
 }
Beispiel #4
0
 /**
  * Retorna el orden hacia adelante en el cual se deben sincronizar las tablas
  * El orden predeterminado es el orden topologico de las tablas
  * @return array Arreglo id_tabla => toba_datos_tabla
  */
 function orden_sincronizacion()
 {
     if ($this->_info_estructura['sinc_orden_automatico']) {
         //-- Se construye el orden topológico
         $sorter = new Structures_Graph_Manipulator_TopologicalSorter();
         $deps = $this->get_tablas_activas();
         $rel = $this->get_relaciones_activas();
         $grafo = self::grafo_relaciones($deps, $rel);
         $parciales = $sorter->sort($grafo);
         $ordenes = array();
         for ($i = 0; $i < count($parciales); $i++) {
             for ($j = 0; $j < count($parciales[$i]); $j++) {
                 $ordenes[] = $parciales[$i][$j]->getData();
             }
         }
         $tablas = array();
         foreach ($ordenes as $orden) {
             $tablas[$orden['identificador']] = $this->_dependencias[$orden['identificador']];
         }
         return $tablas;
     } else {
         //-- Se toma el orden natural en el cual se definieron las tablas
         $ordenes = $this->get_tablas_activas();
         $tablas = array();
         foreach ($ordenes as $orden) {
             $tablas[$orden['identificador']] = $this->_dependencias[$orden['identificador']];
         }
         return $tablas;
     }
 }