PageRenderTime 50ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/Varien/Data/Tree/Db.php

https://bitbucket.org/acidel/buykoala
PHP | 305 lines | 181 code | 34 blank | 90 comment | 9 complexity | 6009de172c7e1f0f67e9f6bff1fa4ec5 MD5 | raw file
  1. <?php
  2. /**
  3. * Magento
  4. *
  5. * NOTICE OF LICENSE
  6. *
  7. * This source file is subject to the Open Software License (OSL 3.0)
  8. * that is bundled with this package in the file LICENSE.txt.
  9. * It is also available through the world-wide-web at this URL:
  10. * http://opensource.org/licenses/osl-3.0.php
  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) 2008 Irubin Consulting Inc. DBA Varien (http://www.varien.com)
  24. * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
  25. */
  26. /**
  27. * Data DB tree
  28. *
  29. * Data model:
  30. * id | pid | level | order
  31. *
  32. * @category Varien
  33. * @package Varien_Data
  34. * @author Magento Core Team <core@magentocommerce.com>
  35. */
  36. class Varien_Data_Tree_Db extends Varien_Data_Tree
  37. {
  38. const ID_FIELD = 'id';
  39. const PARENT_FIELD = 'parent';
  40. const LEVEL_FIELD = 'level';
  41. const ORDER_FIELD = 'order';
  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. /**
  55. * SQL select object
  56. *
  57. * @var Zend_Db_Select
  58. */
  59. protected $_select;
  60. /**
  61. * Tree ctructure field names
  62. *
  63. * @var string
  64. */
  65. protected $_idField;
  66. protected $_parentField;
  67. protected $_levelField;
  68. protected $_orderField;
  69. /**
  70. * Db tree constructor
  71. *
  72. * $fields = array(
  73. * Varien_Data_Tree_Db::ID_FIELD => string,
  74. * Varien_Data_Tree_Db::PARENT_FIELD => string,
  75. * Varien_Data_Tree_Db::LEVEL_FIELD => string
  76. * Varien_Data_Tree_Db::ORDER_FIELD => string
  77. * )
  78. *
  79. * @param Zend_Db_Adapter_Abstract $connection
  80. * @param string $table
  81. * @param array $fields
  82. */
  83. public function __construct($connection, $table, $fields)
  84. {
  85. parent::__construct();
  86. if (!$connection) {
  87. throw new Exception('Wrong "$connection" parametr');
  88. }
  89. $this->_conn = $connection;
  90. $this->_table = $table;
  91. if (!isset($fields[self::ID_FIELD]) ||
  92. !isset($fields[self::PARENT_FIELD]) ||
  93. !isset($fields[self::LEVEL_FIELD]) ||
  94. !isset($fields[self::ORDER_FIELD])) {
  95. throw new Exception('"$fields" tree configuratin array');
  96. }
  97. $this->_idField = $fields[self::ID_FIELD];
  98. $this->_parentField = $fields[self::PARENT_FIELD];
  99. $this->_levelField = $fields[self::LEVEL_FIELD];
  100. $this->_orderField = $fields[self::ORDER_FIELD];
  101. $this->_select = $this->_conn->select();
  102. $this->_select->from($this->_table, array_values($fields));
  103. }
  104. public function getDbSelect()
  105. {
  106. return $this->_select;
  107. }
  108. public function setDbSelect($select)
  109. {
  110. $this->_select = $select;
  111. }
  112. /**
  113. * Load tree
  114. *
  115. * @param int || Varien_Data_Tree_Node $parentNode
  116. * @param int $recursionLevel recursion level
  117. * @return this
  118. */
  119. public function load($parentNode=null, $recursionLevel=100)
  120. {
  121. if (is_null($parentNode)) {
  122. $this->_loadFullTree();
  123. return $this;
  124. }
  125. elseif ($parentNode instanceof Varien_Data_Tree_Node) {
  126. $parentId = $parentNode->getId();
  127. }
  128. elseif (is_numeric($parentNode)) {
  129. $parentId = $parentNode;
  130. $parentNode = null;
  131. }
  132. else {
  133. throw new Exception('root node id is not defined');
  134. }
  135. $select = clone $this->_select;
  136. $select->order($this->_table.'.'.$this->_orderField . ' ASC');
  137. $condition = $this->_conn->quoteInto("$this->_table.$this->_parentField=?", $parentId);
  138. $select->where($condition);
  139. $arrNodes = $this->_conn->fetchAll($select);
  140. foreach ($arrNodes as $nodeInfo) {
  141. $node = new Varien_Data_Tree_Node($nodeInfo, $this->_idField, $this, $parentNode);
  142. $this->addNode($node, $parentNode);
  143. if ($recursionLevel) {
  144. $node->loadChildren($recursionLevel-1);
  145. }
  146. }
  147. return $this;
  148. }
  149. public function loadNode($nodeId)
  150. {
  151. $select = clone $this->_select;
  152. $condition = $this->_conn->quoteInto("$this->_table.$this->_idField=?", $nodeId);
  153. $select->where($condition);
  154. $node = new Varien_Data_Tree_Node($this->_conn->fetchRow($select), $this->_idField, $this);
  155. $this->addNode($node);
  156. return $node;
  157. }
  158. public function appendChild($data=array(), $parentNode, $prevNode=null)
  159. {
  160. $orderSelect = $this->_conn->select();
  161. $orderSelect->from($this->_table, new Zend_Db_Expr('MAX('.$this->_conn->quoteIdentifier($this->_orderField).')'))
  162. ->where($this->_conn->quoteIdentifier($this->_parentField).'='.$parentNode->getId());
  163. $order = $this->_conn->fetchOne($orderSelect);
  164. $data[$this->_parentField] = $parentNode->getId();
  165. $data[$this->_levelField] = $parentNode->getData($this->_levelField)+1;
  166. $data[$this->_orderField] = $order+1;
  167. $this->_conn->insert($this->_table, $data);
  168. $data[$this->_idField] = $this->_conn->lastInsertId();
  169. return parent::appendChild($data, $parentNode, $prevNode);
  170. }
  171. /**
  172. * Move tree node
  173. *
  174. * @param Varien_Data_Tree_Node $node
  175. * @param Varien_Data_Tree_Node $parentNode
  176. * @param Varien_Data_Tree_Node $prevNode
  177. */
  178. public function moveNodeTo($node, $parentNode, $prevNode=null)
  179. {
  180. $data = array();
  181. $data[$this->_parentField] = $parentNode->getId();
  182. $data[$this->_levelField] = $parentNode->getData($this->_levelField)+1;
  183. // New node order
  184. if (is_null($prevNode) || is_null($prevNode->getData($this->_orderField))) {
  185. $data[$this->_orderField] = 1;
  186. }
  187. else {
  188. $data[$this->_orderField] = $prevNode->getData($this->_orderField)+1;
  189. }
  190. $condition = $this->_conn->quoteInto("$this->_idField=?", $node->getId());
  191. // For reorder new node branch
  192. $dataReorderNew = array(
  193. $this->_orderField => new Zend_Db_Expr($this->_conn->quoteIdentifier($this->_orderField).'+1')
  194. );
  195. $conditionReorderNew = $this->_conn->quoteIdentifier($this->_parentField).'='.$parentNode->getId().
  196. ' AND '.$this->_conn->quoteIdentifier($this->_orderField).'>='. $data[$this->_orderField];
  197. // For reorder old node branch
  198. $dataReorderOld = array(
  199. $this->_orderField => new Zend_Db_Expr($this->_conn->quoteIdentifier($this->_orderField).'-1')
  200. );
  201. $conditionReorderOld = $this->_conn->quoteIdentifier($this->_parentField).'='.$node->getData($this->_parentField).
  202. ' AND '.$this->_conn->quoteIdentifier($this->_orderField).'>'.$node->getData($this->_orderField);
  203. $this->_conn->beginTransaction();
  204. try {
  205. // Prepare new node branch
  206. $this->_conn->update($this->_table, $dataReorderNew, $conditionReorderNew);
  207. // Move node
  208. $this->_conn->update($this->_table, $data, $condition);
  209. // Update old node branch
  210. $this->_conn->update($this->_table, $dataReorderOld, $conditionReorderOld);
  211. $this->_updateChildLevels($node->getId(), $data[$this->_levelField]);
  212. $this->_conn->commit();
  213. }
  214. catch (Exception $e){
  215. $this->_conn->rollBack();
  216. throw new Exception('Can\'t move tree node');
  217. }
  218. }
  219. protected function _updateChildLevels($parentId, $parentLevel)
  220. {
  221. $select = $this->_conn->select()
  222. ->from($this->_table, $this->_idField)
  223. ->where($this->_parentField.'=?', $parentId);
  224. $ids = $this->_conn->fetchCol($select);
  225. if (!empty($ids)) {
  226. $this->_conn->update($this->_table,
  227. array($this->_levelField=>$parentLevel+1),
  228. $this->_conn->quoteInto($this->_idField.' IN (?)', $ids));
  229. foreach ($ids as $id) {
  230. $this->_updateChildLevels($id, $parentLevel+1);
  231. }
  232. }
  233. return $this;
  234. }
  235. protected function _loadFullTree()
  236. {
  237. $select = clone $this->_select;
  238. $select->order($this->_table . '.' . $this->_levelField)
  239. ->order($this->_table.'.'.$this->_orderField);
  240. $arrNodes = $this->_conn->fetchAll($select);
  241. foreach ($arrNodes as $nodeInfo) {
  242. $node = new Varien_Data_Tree_Node($nodeInfo, $this->_idField, $this);
  243. $parentNode = $this->getNodeById($nodeInfo[$this->_parentField]);
  244. $this->addNode($node, $parentNode);
  245. }
  246. return $this;
  247. }
  248. public function removeNode($node)
  249. {
  250. // For reorder old node branch
  251. $dataReorderOld = array(
  252. $this->_orderField => new Zend_Db_Expr($this->_conn->quoteIdentifier($this->_orderField).'-1')
  253. );
  254. $conditionReorderOld = $this->_conn->quoteIdentifier($this->_parentField).'='.$node->getData($this->_parentField).
  255. ' AND '.$this->_conn->quoteIdentifier($this->_orderField).'>'.$node->getData($this->_orderField);
  256. $this->_conn->beginTransaction();
  257. try {
  258. $condition = $this->_conn->quoteInto("$this->_idField=?", $node->getId());
  259. $this->_conn->delete($this->_table, $condition);
  260. // Update old node branch
  261. $this->_conn->update($this->_table, $dataReorderOld, $conditionReorderOld);
  262. $this->_conn->commit();
  263. }
  264. catch (Exception $e){
  265. $this->_conn->rollBack();
  266. throw new Exception('Can\'t remove tree node');
  267. }
  268. parent::removeNode($node);
  269. return $this;
  270. }
  271. }