Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Implemented toplogical sorting for totals

  • Loading branch information...
commit 03226e62fdc943f49dfcb8f8bb03737aca5a58d4 1 parent e0a4fd5
Alexander Menk authored
Showing with 54 additions and 44 deletions.
  1. +54 −44 app/code/core/Mage/Sales/Model/Config/Ordered.php
View
98 app/code/core/Mage/Sales/Model/Config/Ordered.php
@@ -121,6 +121,43 @@ protected function _prepareConfigArray($code, $totalConfig)
return $totalConfig;
}
+
+ /**
+ * Topological sort
+ *
+ * @param $nodeids Node Ids - example: array('subtotal','grand_total');
+ * @param $edges Array of Edges. Each edge is specified as an array with two elements: The source and destination node of the edge
+ * Example: array(array('subtotal','grand_total')); -> subtotal comes before grand_total
+ * @return array|null
+ */
+ public function _topologicalSort($nodeids, $edges) {
+ $L = $S = $nodes = array();
+ foreach($nodeids as $id) {
+ $nodes[$id] = array('in'=>array(), 'out'=>array());
+ foreach($edges as $e) {
+ if ($id==$e[0]) { $nodes[$id]['out'][]=$e[1]; }
+ if ($id==$e[1]) { $nodes[$id]['in'][]=$e[0]; }
+ }
+ }
+ foreach ($nodes as $id=>$n) { if (empty($n['in'])) $S[]=$id; }
+ while ($id = array_shift($S)) {
+ if (!in_array($id, $L)) {
+ $L[] = $id;
+ foreach($nodes[$id]['out'] as $m) {
+ $nodes[$m]['in'] = array_diff($nodes[$m]['in'], array($id));
+ if (empty($nodes[$m]['in'])) { $S[] = $m; }
+ }
+ $nodes[$id]['out'] = array();
+ }
+ }
+ foreach($nodes as $n) {
+ if (!empty($n['in']) or !empty($n['out'])) {
+ return null; // not sortable as graph is cyclic
+ }
+ }
+ return $L;
+ }
+
/**
* Aggregate before/after information from all items and sort totals based on this data
*
@@ -140,36 +177,30 @@ protected function _getSortedCollectorCodes()
$element = current($configArray);
if (isset($element['sort_order'])) {
uasort($configArray, array($this, '_compareSortOrder'));
+ $sortedCollectors = array_keys($configArray);
} else {
- foreach ($configArray as $code => $data) {
+ // prepare data for topological sort
+ $nodes = array_keys($configArray);
+ $edges = array();
+
+ foreach ($configArray as $data) {
+ $_code = $data['_code'];
+ if (!isset($configArray[$_code])) continue;
foreach ($data['before'] as $beforeCode) {
- if (!isset($configArray[$beforeCode])) {
- continue;
- }
- $configArray[$code]['before'] = array_unique(array_merge(
- $configArray[$code]['before'], $configArray[$beforeCode]['before']
- ));
- $configArray[$beforeCode]['after'] = array_merge(
- $configArray[$beforeCode]['after'], array($code), $data['after']
- );
- $configArray[$beforeCode]['after'] = array_unique($configArray[$beforeCode]['after']);
+ if (!isset($configArray[$beforeCode])) continue;
+ $edges[] = array($_code, $beforeCode);
}
foreach ($data['after'] as $afterCode) {
- if (!isset($configArray[$afterCode])) {
- continue;
- }
- $configArray[$code]['after'] = array_unique(array_merge(
- $configArray[$code]['after'], $configArray[$afterCode]['after']
- ));
- $configArray[$afterCode]['before'] = array_merge(
- $configArray[$afterCode]['before'], array($code), $data['before']
- );
- $configArray[$afterCode]['before'] = array_unique($configArray[$afterCode]['before']);
+ if (!isset($configArray[$afterCode])) continue;
+ $edges[] = array($afterCode, $_code);
}
}
- uasort($configArray, array($this, '_compareTotals'));
+ $sortedCollectors = $this->_topologicalSort($nodes, $edges);
+
+ if (is_null($sortedCollectors)) {
+ throw new Mage_Sales_Exception('Total ordering before/after conditions can not be complied with');
+ }
}
- $sortedCollectors = array_keys($configArray);
if (Mage::app()->useCache('config')) {
Mage::app()->saveCache(serialize($sortedCollectors), $this->_collectorsCacheKey, array(
Mage_Core_Model_Config::CACHE_TAG
@@ -196,27 +227,6 @@ protected function _initCollectors()
}
/**
- * Callback that uses after/before for comparison
- *
- * @param array $a
- * @param array $b
- * @return int
- */
- protected function _compareTotals($a, $b)
- {
- $aCode = $a['_code'];
- $bCode = $b['_code'];
- if (in_array($aCode, $b['after']) || in_array($bCode, $a['before'])) {
- $res = -1;
- } elseif (in_array($bCode, $a['after']) || in_array($aCode, $b['before'])) {
- $res = 1;
- } else {
- $res = 0;
- }
- return $res;
- }
-
- /**
* Callback that uses sort_order for comparison
*
* @param array $a

1 comment on commit 03226e6

@mage2-team

Revision 03226e62fdc943f49dfcb8f8bb03737aca5a58d4 duplicates #49, which is supplied with tests and is gonna be accepted.

Please sign in to comment.
Something went wrong with that request. Please try again.