/vendor/magento/framework/Data/Tree/Db.php

https://gitlab.com/yousafsyed/easternglamor · PHP · 364 lines · 208 code · 39 blank · 117 comment · 12 complexity · e559669c0cca19f272e7f9d14f94cb49 MD5 · raw file

  1. <?php
  2. /**
  3. * Copyright © 2016 Magento. All rights reserved.
  4. * See COPYING.txt for license details.
  5. */
  6. namespace Magento\Framework\Data\Tree;
  7. /**
  8. * Data DB tree
  9. *
  10. * Data model:
  11. * id | pid | level | order
  12. *
  13. * @author Magento Core Team <core@magentocommerce.com>
  14. */
  15. class Db extends \Magento\Framework\Data\Tree
  16. {
  17. const ID_FIELD = 'id';
  18. const PARENT_FIELD = 'parent';
  19. const LEVEL_FIELD = 'level';
  20. const ORDER_FIELD = 'order';
  21. /**
  22. * DB connection
  23. *
  24. * @var \Magento\Framework\DB\Adapter\AdapterInterface
  25. */
  26. protected $_conn;
  27. /**
  28. * Data table name
  29. *
  30. * @var string
  31. */
  32. protected $_table;
  33. /**
  34. * SQL select object
  35. *
  36. * @var \Magento\Framework\DB\Select
  37. */
  38. protected $_select;
  39. /**
  40. * Tree structure field name: _idField
  41. *
  42. * @var string
  43. */
  44. protected $_idField;
  45. /**
  46. * Tree structure field name: _parentField
  47. *
  48. * @var string
  49. */
  50. protected $_parentField;
  51. /**
  52. * Tree structure field name: _levelField
  53. *
  54. * @var string
  55. */
  56. protected $_levelField;
  57. /**
  58. * Tree structure field name: _orderField
  59. *
  60. * @var string
  61. */
  62. protected $_orderField;
  63. /**
  64. * Db tree constructor
  65. *
  66. * $fields = array(
  67. * \Magento\Framework\Data\Tree\Db::ID_FIELD => string,
  68. * \Magento\Framework\Data\Tree\Db::PARENT_FIELD => string,
  69. * \Magento\Framework\Data\Tree\Db::LEVEL_FIELD => string
  70. * \Magento\Framework\Data\Tree\Db::ORDER_FIELD => string
  71. * )
  72. *
  73. * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
  74. * @param string $table
  75. * @param array $fields
  76. * @throws \Exception
  77. */
  78. public function __construct(\Magento\Framework\DB\Adapter\AdapterInterface $connection, $table, $fields)
  79. {
  80. parent::__construct();
  81. if (!$connection) {
  82. throw new \Exception('Wrong "$connection" parametr');
  83. }
  84. $this->_conn = $connection;
  85. $this->_table = $table;
  86. if (!isset(
  87. $fields[self::ID_FIELD]
  88. ) || !isset(
  89. $fields[self::PARENT_FIELD]
  90. ) || !isset(
  91. $fields[self::LEVEL_FIELD]
  92. ) || !isset(
  93. $fields[self::ORDER_FIELD]
  94. )
  95. ) {
  96. throw new \Exception('"$fields" tree configuratin array');
  97. }
  98. $this->_idField = $fields[self::ID_FIELD];
  99. $this->_parentField = $fields[self::PARENT_FIELD];
  100. $this->_levelField = $fields[self::LEVEL_FIELD];
  101. $this->_orderField = $fields[self::ORDER_FIELD];
  102. $this->_select = $this->_conn->select();
  103. $this->_select->from($this->_table, array_values($fields));
  104. }
  105. /**
  106. * @return \Magento\Framework\DB\Select
  107. */
  108. public function getDbSelect()
  109. {
  110. return $this->_select;
  111. }
  112. /**
  113. * @param \Magento\Framework\DB\Select $select
  114. * @return void
  115. */
  116. public function setDbSelect($select)
  117. {
  118. $this->_select = $select;
  119. }
  120. /**
  121. * Load tree
  122. *
  123. * @param int|Node $parentNode
  124. * @param int $recursionLevel recursion level
  125. * @return $this
  126. * @throws \Exception
  127. */
  128. public function load($parentNode = null, $recursionLevel = 100)
  129. {
  130. if ($parentNode === null) {
  131. $this->_loadFullTree();
  132. return $this;
  133. } elseif ($parentNode instanceof Node) {
  134. $parentId = $parentNode->getId();
  135. } elseif (is_numeric($parentNode)) {
  136. $parentId = $parentNode;
  137. $parentNode = null;
  138. } else {
  139. throw new \Exception('root node id is not defined');
  140. }
  141. $select = clone $this->_select;
  142. $select->order($this->_table . '.' . $this->_orderField . ' ASC');
  143. $condition = $this->_conn->quoteInto("{$this->_table}.{$this->_parentField}=?", $parentId);
  144. $select->where($condition);
  145. $arrNodes = $this->_conn->fetchAll($select);
  146. foreach ($arrNodes as $nodeInfo) {
  147. $node = new Node($nodeInfo, $this->_idField, $this, $parentNode);
  148. $this->addNode($node, $parentNode);
  149. if ($recursionLevel) {
  150. $node->loadChildren($recursionLevel - 1);
  151. }
  152. }
  153. return $this;
  154. }
  155. /**
  156. * @param mixed $nodeId
  157. * @return Node
  158. */
  159. public function loadNode($nodeId)
  160. {
  161. $select = clone $this->_select;
  162. $condition = $this->_conn->quoteInto("{$this->_table}.{$this->_idField}=?", $nodeId);
  163. $select->where($condition);
  164. $node = new Node($this->_conn->fetchRow($select), $this->_idField, $this);
  165. $this->addNode($node);
  166. return $node;
  167. }
  168. /**
  169. * @param Node $data
  170. * @param Node $parentNode
  171. * @param Node $prevNode
  172. * @return Node
  173. */
  174. public function appendChild($data, $parentNode, $prevNode = null)
  175. {
  176. $orderSelect = $this->_conn->select();
  177. $orderSelect->from(
  178. $this->_table,
  179. new \Zend_Db_Expr('MAX(' . $this->_conn->quoteIdentifier($this->_orderField) . ')')
  180. )->where(
  181. $this->_conn->quoteIdentifier($this->_parentField) . '=' . $parentNode->getId()
  182. );
  183. $order = $this->_conn->fetchOne($orderSelect);
  184. $data[$this->_parentField] = $parentNode->getId();
  185. $data[$this->_levelField] = $parentNode->getData($this->_levelField) + 1;
  186. $data[$this->_orderField] = $order + 1;
  187. $this->_conn->insert($this->_table, $data);
  188. $data[$this->_idField] = $this->_conn->lastInsertId();
  189. return parent::appendChild($data, $parentNode, $prevNode);
  190. }
  191. /**
  192. * Move tree node
  193. *
  194. * @param Node $node
  195. * @param Node $parentNode
  196. * @param Node $prevNode
  197. * @return void
  198. * @throws \Exception
  199. */
  200. public function moveNodeTo($node, $parentNode, $prevNode = null)
  201. {
  202. $data = [];
  203. $data[$this->_parentField] = $parentNode->getId();
  204. $data[$this->_levelField] = $parentNode->getData($this->_levelField) + 1;
  205. // New node order
  206. if ($prevNode === null || $prevNode->getData($this->_orderField) === null) {
  207. $data[$this->_orderField] = 1;
  208. } else {
  209. $data[$this->_orderField] = $prevNode->getData($this->_orderField) + 1;
  210. }
  211. $condition = $this->_conn->quoteInto("{$this->_idField}=?", $node->getId());
  212. // For reorder new node branch
  213. $dataReorderNew = [
  214. $this->_orderField => new \Zend_Db_Expr($this->_conn->quoteIdentifier($this->_orderField) . '+1'),
  215. ];
  216. $conditionReorderNew = $this->_conn->quoteIdentifier(
  217. $this->_parentField
  218. ) . '=' . $parentNode->getId() . ' AND ' . $this->_conn->quoteIdentifier(
  219. $this->_orderField
  220. ) . '>=' . $data[$this->_orderField];
  221. // For reorder old node branch
  222. $dataReorderOld = [
  223. $this->_orderField => new \Zend_Db_Expr($this->_conn->quoteIdentifier($this->_orderField) . '-1'),
  224. ];
  225. $conditionReorderOld = $this->_conn->quoteIdentifier(
  226. $this->_parentField
  227. ) . '=' . $node->getData(
  228. $this->_parentField
  229. ) . ' AND ' . $this->_conn->quoteIdentifier(
  230. $this->_orderField
  231. ) . '>' . $node->getData(
  232. $this->_orderField
  233. );
  234. $this->_conn->beginTransaction();
  235. try {
  236. // Prepare new node branch
  237. $this->_conn->update($this->_table, $dataReorderNew, $conditionReorderNew);
  238. // Move node
  239. $this->_conn->update($this->_table, $data, $condition);
  240. // Update old node branch
  241. $this->_conn->update($this->_table, $dataReorderOld, $conditionReorderOld);
  242. $this->_updateChildLevels($node->getId(), $data[$this->_levelField]);
  243. $this->_conn->commit();
  244. } catch (\Exception $e) {
  245. $this->_conn->rollBack();
  246. throw new \Exception('Can\'t move tree node');
  247. }
  248. }
  249. /**
  250. * @param mixed $parentId
  251. * @param int $parentLevel
  252. * @return $this
  253. */
  254. protected function _updateChildLevels($parentId, $parentLevel)
  255. {
  256. $select = $this->_conn->select()->from(
  257. $this->_table,
  258. $this->_idField
  259. )->where(
  260. $this->_parentField . '=?',
  261. $parentId
  262. );
  263. $ids = $this->_conn->fetchCol($select);
  264. if (!empty($ids)) {
  265. $this->_conn->update(
  266. $this->_table,
  267. [$this->_levelField => $parentLevel + 1],
  268. $this->_conn->quoteInto($this->_idField . ' IN (?)', $ids)
  269. );
  270. foreach ($ids as $id) {
  271. $this->_updateChildLevels($id, $parentLevel + 1);
  272. }
  273. }
  274. return $this;
  275. }
  276. /**
  277. * @return $this
  278. */
  279. protected function _loadFullTree()
  280. {
  281. $select = clone $this->_select;
  282. $select->order($this->_table . '.' . $this->_levelField)->order($this->_table . '.' . $this->_orderField);
  283. $arrNodes = $this->_conn->fetchAll($select);
  284. foreach ($arrNodes as $nodeInfo) {
  285. $node = new Node($nodeInfo, $this->_idField, $this);
  286. $parentNode = $this->getNodeById($nodeInfo[$this->_parentField]);
  287. $this->addNode($node, $parentNode);
  288. }
  289. return $this;
  290. }
  291. /**
  292. * @param Node $node
  293. * @return $this
  294. * @throws \Exception
  295. */
  296. public function removeNode($node)
  297. {
  298. // For reorder old node branch
  299. $dataReorderOld = [
  300. $this->_orderField => new \Zend_Db_Expr($this->_conn->quoteIdentifier($this->_orderField) . '-1'),
  301. ];
  302. $conditionReorderOld = $this->_conn->quoteIdentifier(
  303. $this->_parentField
  304. ) . '=' . $node->getData(
  305. $this->_parentField
  306. ) . ' AND ' . $this->_conn->quoteIdentifier(
  307. $this->_orderField
  308. ) . '>' . $node->getData(
  309. $this->_orderField
  310. );
  311. $this->_conn->beginTransaction();
  312. try {
  313. $condition = $this->_conn->quoteInto("{$this->_idField}=?", $node->getId());
  314. $this->_conn->delete($this->_table, $condition);
  315. // Update old node branch
  316. $this->_conn->update($this->_table, $dataReorderOld, $conditionReorderOld);
  317. $this->_conn->commit();
  318. } catch (\Exception $e) {
  319. $this->_conn->rollBack();
  320. throw new \Exception('Can\'t remove tree node');
  321. }
  322. parent::removeNode($node);
  323. return $this;
  324. }
  325. }