123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- <?php
- /**
- * Copyright © Magento, Inc. All rights reserved.
- * See COPYING.txt for license details.
- */
- namespace Magento\Framework\Data\Tree;
- use Magento\Framework\DB\Select;
- /**
- * Data DB tree
- *
- * Data model:
- * id | path | order
- *
- * @author Magento Core Team <core@magentocommerce.com>
- */
- class Dbp extends \Magento\Framework\Data\Tree
- {
- const ID_FIELD = 'id';
- const PATH_FIELD = 'path';
- const ORDER_FIELD = 'order';
- const LEVEL_FIELD = 'level';
- /**
- * DB connection
- *
- * @var \Magento\Framework\DB\Adapter\AdapterInterface
- */
- protected $_conn;
- /**
- * Data table name
- *
- * @var string
- */
- protected $_table;
- /**
- * Indicates if loaded
- *
- * @var bool
- */
- protected $_loaded = false;
- /**
- * SQL select object
- *
- * @var \Magento\Framework\DB\Select
- */
- protected $_select;
- /**
- * Tree structure field: id
- *
- * @var string
- */
- protected $_idField;
- /**
- * Tree structure field: path
- *
- * @var string
- */
- protected $_pathField;
- /**
- * Tree structure field: order
- *
- * @var string
- */
- protected $_orderField;
- /**
- * Tree structure field: level
- *
- * @var string
- */
- protected $_levelField;
- /**
- * Db tree constructor
- *
- * $fields = array(
- * \Magento\Framework\Data\Tree\Dbp::ID_FIELD => string,
- * \Magento\Framework\Data\Tree\Dbp::PATH_FIELD => string,
- * \Magento\Framework\Data\Tree\Dbp::ORDER_FIELD => string
- * \Magento\Framework\Data\Tree\Dbp::LEVEL_FIELD => string
- * )
- *
- * @param \Magento\Framework\DB\Adapter\AdapterInterface $connection
- * @param string $table
- * @param array $fields
- * @throws \Exception
- */
- public function __construct(\Magento\Framework\DB\Adapter\AdapterInterface $connection, $table, $fields)
- {
- parent::__construct();
- if (!$connection) {
- throw new \Exception('Wrong "$connection" parametr');
- }
- $this->_conn = $connection;
- $this->_table = $table;
- if (!isset(
- $fields[self::ID_FIELD]
- ) || !isset(
- $fields[self::PATH_FIELD]
- ) || !isset(
- $fields[self::LEVEL_FIELD]
- ) || !isset(
- $fields[self::ORDER_FIELD]
- )
- ) {
- throw new \Exception('"$fields" tree configuratin array');
- }
- $this->_idField = $fields[self::ID_FIELD];
- $this->_pathField = $fields[self::PATH_FIELD];
- $this->_orderField = $fields[self::ORDER_FIELD];
- $this->_levelField = $fields[self::LEVEL_FIELD];
- $this->_select = $this->_conn->select();
- $this->_select->from($this->_table);
- }
- /**
- * Retrieve current select object
- *
- * @return Select
- */
- public function getDbSelect()
- {
- return $this->_select;
- }
- /**
- * Set Select object
- *
- * @param Select $select
- * @return void
- */
- public function setDbSelect($select)
- {
- $this->_select = $select;
- }
- /**
- * Load tree
- *
- * @param int|Node|string $parentNode
- * @param int $recursionLevel
- * @return $this
- */
- public function load($parentNode = null, $recursionLevel = 0)
- {
- if (!$this->_loaded) {
- $startLevel = 1;
- $parentPath = '';
- if ($parentNode instanceof Node) {
- $parentPath = $parentNode->getData($this->_pathField);
- $startLevel = $parentNode->getData($this->_levelField);
- } elseif (is_numeric($parentNode)) {
- $select = $this->_conn->select()
- ->from($this->_table, [$this->_pathField, $this->_levelField])
- ->where("{$this->_idField} = ?", $parentNode);
- $parent = $this->_conn->fetchRow($select);
- $startLevel = $parent[$this->_levelField];
- $parentPath = $parent[$this->_pathField];
- $parentNode = null;
- } elseif (is_string($parentNode)) {
- $parentPath = $parentNode;
- $startLevel = count(explode(',', $parentPath)) - 1;
- $parentNode = null;
- }
- $select = clone $this->_select;
- $select->order($this->_table . '.' . $this->_orderField . ' ASC');
- if ($parentPath) {
- $pathField = $this->_conn->quoteIdentifier([$this->_table, $this->_pathField]);
- $select->where("{$pathField} LIKE ?", "{$parentPath}/%");
- }
- if ($recursionLevel != 0) {
- $levelField = $this->_conn->quoteIdentifier([$this->_table, $this->_levelField]);
- $select->where("{$levelField} <= ?", $startLevel + $recursionLevel);
- }
- $arrNodes = $this->_conn->fetchAll($select);
- $childrenItems = [];
- foreach ($arrNodes as $nodeInfo) {
- $pathToParent = explode('/', $nodeInfo[$this->_pathField]);
- array_pop($pathToParent);
- $pathToParent = implode('/', $pathToParent);
- $childrenItems[$pathToParent][] = $nodeInfo;
- }
- $this->addChildNodes($childrenItems, $parentPath, $parentNode);
- $this->_loaded = true;
- }
- return $this;
- }
- /**
- * Add child nodes
- *
- * @param array $children
- * @param string $path
- * @param Node $parentNode
- * @param int $level
- * @return void
- */
- public function addChildNodes($children, $path, $parentNode, $level = 0)
- {
- if (isset($children[$path])) {
- foreach ($children[$path] as $child) {
- $nodeId = isset($child[$this->_idField]) ? $child[$this->_idField] : false;
- if ($parentNode && $nodeId && ($node = $parentNode->getChildren()->searchById($nodeId))) {
- $node->addData($child);
- } else {
- $node = new Node($child, $this->_idField, $this, $parentNode);
- }
- //$node->setLevel(count(explode('/', $node->getData($this->_pathField)))-1);
- $node->setLevel($node->getData($this->_levelField));
- $node->setPathId($node->getData($this->_pathField));
- $this->addNode($node, $parentNode);
- if ($path) {
- $childrenPath = explode('/', $path);
- } else {
- $childrenPath = [];
- }
- $childrenPath[] = $node->getId();
- $childrenPath = implode('/', $childrenPath);
- $this->addChildNodes($children, $childrenPath, $node, $level + 1);
- }
- }
- }
- /**
- * Load node
- *
- * @param int|string $nodeId
- * @return Node
- */
- public function loadNode($nodeId)
- {
- $select = clone $this->_select;
- if (is_numeric($nodeId)) {
- $condField = $this->_conn->quoteIdentifier([$this->_table, $this->_idField]);
- } else {
- $condField = $this->_conn->quoteIdentifier([$this->_table, $this->_pathField]);
- }
- $select->where("{$condField} = ?", $nodeId);
- $node = new Node($this->_conn->fetchRow($select), $this->_idField, $this);
- $this->addNode($node);
- return $node;
- }
- /**
- * Get children
- *
- * @param Node $node
- * @param bool $recursive
- * @param array $result
- * @return array
- */
- public function getChildren($node, $recursive = true, $result = [])
- {
- if (is_numeric($node)) {
- $node = $this->getNodeById($node);
- }
- if (!$node) {
- return $result;
- }
- foreach ($node->getChildren() as $child) {
- if ($recursive) {
- if ($child->getChildren()) {
- $result = $this->getChildren($child, $recursive, $result);
- }
- }
- $result[] = $child->getId();
- }
- return $result;
- }
- /**
- * Move tree node
- *
- * @param Node $node
- * @param Node $newParent
- * @param Node $prevNode
- * @return void
- * @throws \Exception
- * @todo Use adapter for generate conditions
- */
- public function move($node, $newParent, $prevNode = null)
- {
- $position = 1;
- $oldPath = $node->getData($this->_pathField);
- $newPath = $newParent->getData($this->_pathField);
- $newPath = $newPath . '/' . $node->getId();
- $oldPathLength = strlen($oldPath);
- $newLevel = $newParent->getLevel() + 1;
- $levelDisposition = $newLevel - $node->getLevel();
- $data = [
- $this->_levelField => new \Zend_Db_Expr("{$this->_levelField} + '{$levelDisposition}'"),
- $this->_pathField => new \Zend_Db_Expr(
- "CONCAT('{$newPath}', RIGHT({$this->_pathField}, LENGTH({$this->_pathField}) - {$oldPathLength}))"
- ),
- ];
- $condition = $this->_conn->quoteInto("{$this->_pathField} REGEXP ?", "^{$oldPath}(/|\$)");
- $this->_conn->beginTransaction();
- $reorderData = [$this->_orderField => new \Zend_Db_Expr("{$this->_orderField} + 1")];
- try {
- if ($prevNode && $prevNode->getId()) {
- $reorderCondition = "{$this->_orderField} > {$prevNode->getData($this->_orderField)}";
- $position = $prevNode->getData($this->_orderField) + 1;
- } else {
- $reorderCondition = $this->_conn->quoteInto(
- "{$this->_pathField} REGEXP ?",
- "^{$newParent->getData($this->_pathField)}/[0-9]+\$"
- );
- $select = $this->_conn->select()->from(
- $this->_table,
- new \Zend_Db_Expr("MIN({$this->_orderField})")
- )->where(
- $reorderCondition
- );
- $position = (int)$this->_conn->fetchOne($select);
- }
- $this->_conn->update($this->_table, $reorderData, $reorderCondition);
- $this->_conn->update($this->_table, $data, $condition);
- $this->_conn->update(
- $this->_table,
- [$this->_orderField => $position, $this->_levelField => $newLevel],
- $this->_conn->quoteInto("{$this->_idField} = ?", $node->getId())
- );
- $this->_conn->commit();
- } catch (\Exception $e) {
- $this->_conn->rollBack();
- throw new \Exception("Can't move tree node due to error: " . $e->getMessage());
- }
- }
- /**
- * Load ensured nodes
- *
- * @param object $category
- * @param Node $rootNode
- * @return void
- */
- public function loadEnsuredNodes($category, $rootNode)
- {
- $pathIds = $category->getPathIds();
- $rootNodeId = $rootNode->getId();
- $rootNodePath = $rootNode->getData($this->_pathField);
- $select = clone $this->_select;
- $select->order($this->_table . '.' . $this->_orderField . ' ASC');
- if ($pathIds) {
- $condition = $this->_conn->quoteInto("{$this->_table}.{$this->_idField} in (?)", $pathIds);
- $select->where($condition);
- }
- $arrNodes = $this->_conn->fetchAll($select);
- if ($arrNodes) {
- $childrenItems = [];
- foreach ($arrNodes as $nodeInfo) {
- $nodeId = $nodeInfo[$this->_idField];
- if ($nodeId <= $rootNodeId) {
- continue;
- }
- $pathToParent = explode('/', $nodeInfo[$this->_pathField]);
- array_pop($pathToParent);
- $pathToParent = implode('/', $pathToParent);
- $childrenItems[$pathToParent][] = $nodeInfo;
- }
- $this->_addChildNodes($childrenItems, $rootNodePath, $rootNode, true);
- }
- }
- /**
- * Add child nodes
- *
- * @param array $children
- * @param string $path
- * @param Node $parentNode
- * @param bool $withChildren
- * @param int $level
- * @return void
- */
- protected function _addChildNodes($children, $path, $parentNode, $withChildren = false, $level = 0)
- {
- if (isset($children[$path])) {
- foreach ($children[$path] as $child) {
- $nodeId = isset($child[$this->_idField]) ? $child[$this->_idField] : false;
- if ($parentNode && $nodeId && ($node = $parentNode->getChildren()->searchById($nodeId))) {
- $node->addData($child);
- } else {
- $node = new Node($child, $this->_idField, $this, $parentNode);
- $node->setLevel($node->getData($this->_levelField));
- $node->setPathId($node->getData($this->_pathField));
- $this->addNode($node, $parentNode);
- }
- if ($withChildren) {
- $this->_loaded = false;
- $node->loadChildren(1);
- $this->_loaded = false;
- }
- if ($path) {
- $childrenPath = explode('/', $path);
- } else {
- $childrenPath = [];
- }
- $childrenPath[] = $node->getId();
- $childrenPath = implode('/', $childrenPath);
- $this->_addChildNodes($children, $childrenPath, $node, $withChildren, $level + 1);
- }
- }
- }
- }
|