PageRenderTime 45ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/includes/src/Varien/Data/Tree/Dbp.php

https://bitbucket.org/kdms/sh-magento
PHP | 394 lines | 248 code | 47 blank | 99 comment | 27 complexity | d516db509492f88688ee0f8adc778be7 MD5 | raw file
  1. <?php
  2. /**
  3. * Magento Enterprise Edition
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Magento Enterprise Edition License
  8. * that is bundled with this package in the file LICENSE_EE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://www.magentocommerce.com/license/enterprise-edition
  11. * If you did not receive a copy of the license and are unable to
  12. * obtain it through the world-wide-web, please send an email
  13. * to license@magentocommerce.com so we can send you a copy immediately.
  14. *
  15. * DISCLAIMER
  16. *
  17. * Do not edit or add to this file if you wish to upgrade Magento to newer
  18. * versions in the future. If you wish to customize Magento for your
  19. * needs please refer to http://www.magentocommerce.com for more information.
  20. *
  21. * @category Varien
  22. * @package Varien_Data
  23. * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
  24. * @license http://www.magentocommerce.com/license/enterprise-edition
  25. */
  26. /**
  27. * Data DB tree
  28. *
  29. * Data model:
  30. * id | path | order
  31. *
  32. * @category Varien
  33. * @package Varien_Data
  34. * @author Magento Core Team <core@magentocommerce.com>
  35. */
  36. class Varien_Data_Tree_Dbp extends Varien_Data_Tree
  37. {
  38. const ID_FIELD = 'id';
  39. const PATH_FIELD = 'path';
  40. const ORDER_FIELD = 'order';
  41. const LEVEL_FIELD = 'level';
  42. /**
  43. * DB connection
  44. *
  45. * @var Zend_Db_Adapter_Abstract
  46. */
  47. protected $_conn;
  48. /**
  49. * Data table name
  50. *
  51. * @var string
  52. */
  53. protected $_table;
  54. protected $_loaded = false;
  55. /**
  56. * SQL select object
  57. *
  58. * @var Zend_Db_Select
  59. */
  60. protected $_select;
  61. /**
  62. * Tree ctructure field names
  63. *
  64. * @var string
  65. */
  66. protected $_idField;
  67. protected $_pathField;
  68. protected $_orderField;
  69. protected $_levelField;
  70. /**
  71. * Db tree constructor
  72. *
  73. * $fields = array(
  74. * Varien_Data_Tree_Dbp::ID_FIELD => string,
  75. * Varien_Data_Tree_Dbp::PATH_FIELD => string,
  76. * Varien_Data_Tree_Dbp::ORDER_FIELD => string
  77. * Varien_Data_Tree_Dbp::LEVEL_FIELD => string
  78. * )
  79. *
  80. * @param Zend_Db_Adapter_Abstract $connection
  81. * @param string $table
  82. * @param array $fields
  83. */
  84. public function __construct($connection, $table, $fields)
  85. {
  86. parent::__construct();
  87. if (!$connection) {
  88. throw new Exception('Wrong "$connection" parametr');
  89. }
  90. $this->_conn = $connection;
  91. $this->_table = $table;
  92. if (!isset($fields[self::ID_FIELD]) ||
  93. !isset($fields[self::PATH_FIELD]) ||
  94. !isset($fields[self::LEVEL_FIELD]) ||
  95. !isset($fields[self::ORDER_FIELD])) {
  96. throw new Exception('"$fields" tree configuratin array');
  97. }
  98. $this->_idField = $fields[self::ID_FIELD];
  99. $this->_pathField = $fields[self::PATH_FIELD];
  100. $this->_orderField = $fields[self::ORDER_FIELD];
  101. $this->_levelField = $fields[self::LEVEL_FIELD];
  102. $this->_select = $this->_conn->select();
  103. $this->_select->from($this->_table);
  104. }
  105. /**
  106. * Retrieve current select object
  107. *
  108. * @return Varien_Db_Select
  109. */
  110. public function getDbSelect()
  111. {
  112. return $this->_select;
  113. }
  114. /**
  115. * Set Select object
  116. *
  117. * @param Varien_Db_Select $select
  118. */
  119. public function setDbSelect($select)
  120. {
  121. $this->_select = $select;
  122. }
  123. /**
  124. * Load tree
  125. *
  126. * @param int|Varien_Data_Tree_Node $parentNode
  127. * @return Varien_Data_Tree_Dbp
  128. */
  129. public function load($parentNode=null, $recursionLevel = 0)
  130. {
  131. if (!$this->_loaded) {
  132. $startLevel = 1;
  133. $parentPath = '';
  134. if ($parentNode instanceof Varien_Data_Tree_Node) {
  135. $parentPath = $parentNode->getData($this->_pathField);
  136. $startLevel = $parentNode->getData($this->_levelField);
  137. } else if (is_numeric($parentNode)) {
  138. $select = $this->_conn->select()
  139. ->from($this->_table, array($this->_pathField, $this->_levelField))
  140. ->where("{$this->_idField} = ?", $parentNode);
  141. $parent = $this->_conn->fetchRow($select);
  142. $startLevel = $parent[$this->_levelField];
  143. $parentPath = $parent[$this->_pathField];
  144. $parentNode = null;
  145. } else if (is_string($parentNode)) {
  146. $parentPath = $parentNode;
  147. $startLevel = count(explode($parentPath))-1;
  148. $parentNode = null;
  149. }
  150. $select = clone $this->_select;
  151. $select->order($this->_table . '.' . $this->_orderField . ' ASC');
  152. if ($parentPath) {
  153. $pathField = $this->_conn->quoteIdentifier(array($this->_table, $this->_pathField));
  154. $select->where("{$pathField} LIKE ?", "{$parentPath}/%");
  155. }
  156. if ($recursionLevel != 0) {
  157. $levelField = $this->_conn->quoteIdentifier(array($this->_table, $this->_levelField));
  158. $select->where("{$levelField} <= ?", $startLevel + $recursionLevel);
  159. }
  160. $arrNodes = $this->_conn->fetchAll($select);
  161. $childrenItems = array();
  162. foreach ($arrNodes as $nodeInfo) {
  163. $pathToParent = explode('/', $nodeInfo[$this->_pathField]);
  164. array_pop($pathToParent);
  165. $pathToParent = implode('/', $pathToParent);
  166. $childrenItems[$pathToParent][] = $nodeInfo;
  167. }
  168. $this->addChildNodes($childrenItems, $parentPath, $parentNode);
  169. $this->_loaded = true;
  170. }
  171. return $this;
  172. }
  173. public function addChildNodes($children, $path, $parentNode, $level = 0)
  174. {
  175. if (isset($children[$path])) {
  176. foreach ($children[$path] as $child) {
  177. $nodeId = isset($child[$this->_idField])?$child[$this->_idField]:false;
  178. if ($parentNode && $nodeId && $node = $parentNode->getChildren()->searchById($nodeId)) {
  179. $node->addData($child);
  180. } else {
  181. $node = new Varien_Data_Tree_Node($child, $this->_idField, $this, $parentNode);
  182. }
  183. //$node->setLevel(count(explode('/', $node->getData($this->_pathField)))-1);
  184. $node->setLevel($node->getData($this->_levelField));
  185. $node->setPathId($node->getData($this->_pathField));
  186. $this->addNode($node, $parentNode);
  187. if ($path) {
  188. $childrenPath = explode('/', $path);
  189. } else {
  190. $childrenPath = array();
  191. }
  192. $childrenPath[] = $node->getId();
  193. $childrenPath = implode('/', $childrenPath);
  194. $this->addChildNodes($children, $childrenPath, $node, $level+1);
  195. }
  196. }
  197. }
  198. /**
  199. * Enter description here...
  200. *
  201. * @param int|string $nodeId
  202. * @return Varien_Data_Tree_Node
  203. */
  204. public function loadNode($nodeId)
  205. {
  206. $select = clone $this->_select;
  207. if (is_numeric($nodeId)) {
  208. $condField = $this->_conn->quoteIdentifier(array($this->_table, $this->_idField));
  209. } else {
  210. $condField = $this->_conn->quoteIdentifier(array($this->_table, $this->_pathField));
  211. }
  212. $select->where("{$condField} = ?", $nodeId);
  213. $node = new Varien_Data_Tree_Node($this->_conn->fetchRow($select), $this->_idField, $this);
  214. $this->addNode($node);
  215. return $node;
  216. }
  217. public function getChildren($node, $recursive = true, $result = array()) {
  218. if (is_numeric($node)) {
  219. $node = $this->getNodeById($node);
  220. }
  221. if (!$node) {
  222. return $result;
  223. }
  224. foreach ($node->getChildren() as $child) {
  225. if ($recursive) {
  226. if ($child->getChildren()) {
  227. $result = $this->getChildren($child, $recursive, $result);
  228. }
  229. }
  230. $result[] = $child->getId();
  231. }
  232. return $result;
  233. }
  234. /**
  235. * Move tree node
  236. *
  237. * @todo Use adapter for generate conditions
  238. * @param Varien_Data_Tree_Node $node
  239. * @param Varien_Data_Tree_Node $newParent
  240. * @param Varien_Data_Tree_Node $prevNode
  241. */
  242. public function move($node, $newParent, $prevNode = null)
  243. {
  244. $position = 1;
  245. $oldPath = $node->getData($this->_pathField);
  246. $newPath = $newParent->getData($this->_pathField);
  247. $newPath = $newPath . '/' . $node->getId();
  248. $oldPathLength = strlen($oldPath);
  249. $newLevel = $newParent->getLevel()+1;
  250. $levelDisposition = $newLevel-$node->getLevel();
  251. $data = array(
  252. $this->_levelField => new Zend_Db_Expr("{$this->_levelField} + '{$levelDisposition}'"),
  253. $this->_pathField => new Zend_Db_Expr("CONCAT('$newPath', RIGHT($this->_pathField, LENGTH($this->_pathField) - {$oldPathLength}))")
  254. );
  255. $condition = $this->_conn->quoteInto("$this->_pathField REGEXP ?", "^$oldPath(/|$)");
  256. $this->_conn->beginTransaction();
  257. $reorderData = array($this->_orderField => new Zend_Db_Expr("$this->_orderField + 1"));
  258. try {
  259. if ($prevNode && $prevNode->getId()) {
  260. $reorderCondition = "{$this->_orderField} > {$prevNode->getData($this->_orderField)}";
  261. $position = $prevNode->getData($this->_orderField) + 1;
  262. } else {
  263. $reorderCondition = $this->_conn->quoteInto("{$this->_pathField} REGEXP ?", "^{$newParent->getData($this->_pathField)}/[0-9]+$");
  264. $select = $this->_conn->select()
  265. ->from($this->_table, new Zend_Db_Expr("MIN({$this->_orderField})"))
  266. ->where($reorderCondition);
  267. $position = (int) $this->_conn->fetchOne($select);
  268. }
  269. $this->_conn->update($this->_table, $reorderData, $reorderCondition);
  270. $this->_conn->update($this->_table, $data, $condition);
  271. $this->_conn->update($this->_table, array($this->_orderField => $position, $this->_levelField=>$newLevel),
  272. $this->_conn->quoteInto("{$this->_idField} = ?", $node->getId())
  273. );
  274. $this->_conn->commit();
  275. } catch (Exception $e){
  276. $this->_conn->rollBack();
  277. throw new Exception("Can't move tree node due to error: " . $e->getMessage());
  278. }
  279. }
  280. public function loadEnsuredNodes($category, $rootNode)
  281. {
  282. $pathIds = $category->getPathIds();
  283. $rootNodeId = $rootNode->getId();
  284. $rootNodePath = $rootNode->getData($this->_pathField);
  285. $select = clone $this->_select;
  286. $select->order($this->_table.'.'.$this->_orderField . ' ASC');
  287. if ($pathIds) {
  288. $condition = $this->_conn->quoteInto("$this->_table.$this->_idField in (?)", $pathIds);
  289. $select->where($condition);
  290. }
  291. $arrNodes = $this->_conn->fetchAll($select);
  292. if ($arrNodes) {
  293. $childrenItems = array();
  294. foreach ($arrNodes as $nodeInfo) {
  295. $nodeId = $nodeInfo[$this->_idField];
  296. if ($nodeId<=$rootNodeId) {
  297. continue;
  298. }
  299. $pathToParent = explode('/', $nodeInfo[$this->_pathField]);
  300. array_pop($pathToParent);
  301. $pathToParent = implode('/', $pathToParent);
  302. $childrenItems[$pathToParent][] = $nodeInfo;
  303. }
  304. $this->_addChildNodes($childrenItems, $rootNodePath, $rootNode, true);
  305. }
  306. }
  307. protected function _addChildNodes($children, $path, $parentNode, $withChildren=false, $level = 0)
  308. {
  309. if (isset($children[$path])) {
  310. foreach ($children[$path] as $child) {
  311. $nodeId = isset($child[$this->_idField])?$child[$this->_idField]:false;
  312. if ($parentNode && $nodeId && $node = $parentNode->getChildren()->searchById($nodeId)) {
  313. $node->addData($child);
  314. } else {
  315. $node = new Varien_Data_Tree_Node($child, $this->_idField, $this, $parentNode);
  316. $node->setLevel($node->getData($this->_levelField));
  317. $node->setPathId($node->getData($this->_pathField));
  318. $this->addNode($node, $parentNode);
  319. }
  320. if ($withChildren) {
  321. $this->_loaded = false;
  322. $node->loadChildren(1);
  323. $this->_loaded = false;
  324. }
  325. if ($path) {
  326. $childrenPath = explode('/', $path);
  327. } else {
  328. $childrenPath = array();
  329. }
  330. $childrenPath[] = $node->getId();
  331. $childrenPath = implode('/', $childrenPath);
  332. $this->_addChildNodes($children, $childrenPath, $node, $withChildren, $level+1);
  333. }
  334. }
  335. }
  336. }