1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace App\Lib;
13:
14: use Nette\Utils\Arrays,
15: Nette\Database\SqlLiteral,
16: App\Model\Database,
17: App\Lib\Statics\Cons,
18: App\Interfaces as I;
19:
20: 21: 22: 23: 24: 25: 26: 27:
28: class Tree extends Table implements I\IData, I\ITree {
29:
30:
31: 32:
33: protected $masterNode;
34:
35: 36:
37: protected $rebuildDatabase;
38:
39: 40: 41: 42: 43: 44: 45: 46:
47: public function __construct($tableName, Database $databases, $test = true, $masterNode = NULL) {
48: parent::__construct($tableName, $databases);
49: $this->rebuildDatabase = $databases;
50: $this->masterNode = ($masterNode) ? $masterNode : $this->getMasterNode();
51: $this->setState(
52: !is_null($this->masterNode) &&
53: ((!$test) ? true : (new TreeIntegrity($tableName, $this->rebuildDatabase, false, $this->masterNode))->checkTreeIntegrity())
54: );
55: }
56:
57: 58: 59: 60:
61: public function getData() {
62: return parent::getData()->where('NOT ' . Cons::COLUMN_ID, $this->masterNode->id)->order(Cons::COLUMN_LEFT);
63: }
64:
65: 66: 67: 68:
69: public function getCopy() {
70: return $this->data->createSelectionInstance();
71: }
72:
73: 74: 75: 76:
77: public function getTree() {
78: return $this->getNodeChilds($this->masterNode->id);
79: }
80:
81: 82: 83: 84: 85: 86: 87:
88: public function getTreeNodes($id, $depth = null) {
89: $node = $this->data->get($id);
90: (!is_null($depth)) ? : $depth = $node[Cons::COLUMN_DEPTH] + 1;
91: return $this->getNodeChilds($id)->where(Cons::COLUMN_DEPTH . " ?", $depth);
92: }
93:
94: 95: 96: 97: 98:
99: public function getChildsCount($id) {
100: $node = $this->data->get($id);
101: return (int) ($node[Cons::COLUMN_RIGHT] - $node[Cons::COLUMN_LEFT] - 1) / 2;
102: }
103:
104: 105: 106: 107: 108: 109:
110: public function insert($data) {
111: $parent = NULL;
112: if ($data[Cons::COLUMN_PARENT] !== NULL) {
113: $id = (int) $data[Cons::COLUMN_PARENT];
114: $parent = $this->findById($id);
115: }
116: if (!$parent instanceof \Nette\Database\Table\ActiveRow) {
117: $data[Cons::COLUMN_PARENT] = $this->masterNode->id;
118: $parent = $this->masterNode;
119: }
120: $this->rebuildTreeRight($parent, 2);
121: $data[Cons::COLUMN_PATH] = ($parent[Cons::COLUMN_PATH] === NULL || $parent[Cons::COLUMN_PATH] === '') ?
122: $data[Cons::COLUMN_NAME] : $parent[Cons::COLUMN_PATH] . ' > ' . $data[Cons::COLUMN_NAME];
123: $data[Cons::COLUMN_LEFT] = $parent[Cons::COLUMN_LEFT] + 1;
124: $data[Cons::COLUMN_RIGHT] = $parent[Cons::COLUMN_LEFT] + 2;
125: $data[Cons::COLUMN_DEPTH] = $parent[Cons::COLUMN_DEPTH] + 1;
126: return parent::insert($data);
127: }
128:
129: 130: 131: 132: 133:
134: public function delete($id) {
135: $node = $this->data->get($id);
136: if ($node[Cons::COLUMN_LEFT === $node[Cons::COLUMN_RIGHT] + 1]) {
137: $this->rebuildTreeRight($node, -2);
138: return parent::delete($id);
139: } else {
140: return 0;
141: }
142: }
143:
144: 145: 146: 147: 148: 149:
150: public function update($id, $data = null) {
151: if ($data) {
152: return (parent::update($id, $data)) ? parent::update($id, array(Cons::COLUMN_PATH => $this->getTreeNodePath($id))) : 0;
153: } else {
154: return parent::update($id, array(Cons::COLUMN_PATH => $this->getTreeNodePath($id)));
155: }
156: }
157:
158:
159:
160: 161: 162: 163: 164:
165: protected function getTreeNodePath($id, $path = "") {
166: $row = $this->data->get($id);
167: $selection = $this->getCopy()
168: ->where(Cons::COLUMN_LEFT . ' < ?', $row[Cons::COLUMN_LEFT])
169: ->where(Cons::COLUMN_RIGHT . ' > ?', $row[Cons::COLUMN_RIGHT])
170: ->where(Cons::COLUMN_DEPTH . ' > ?', 0)
171: ->order(Cons::COLUMN_LEFT);
172: Foreach ($selection as $key) {
173: $path.=$key[Cons::COLUMN_NAME] . ' > ';
174: }
175: return $path.=$row[Cons::COLUMN_NAME];
176: }
177:
178:
179:
180: 181: 182: 183: 184:
185: private function rebuildTreeRight($node, $mark) {
186: $this->copy
187: ->where(Cons::COLUMN_LEFT . ' > ?', $node[Cons::COLUMN_LEFT])
188: ->update(array(Cons::COLUMN_LEFT => new SqlLiteral(Cons::COLUMN_LEFT . ' + ' . $mark)))
189: ;
190: $this->copy
191: ->where(Cons::COLUMN_RIGHT . ' >= ?', $node[Cons::COLUMN_LEFT])
192: ->update(array(Cons::COLUMN_RIGHT => new SqlLiteral(Cons::COLUMN_RIGHT . ' + ' . $mark)))
193: ;
194: }
195:
196: 197: 198: 199: 200:
201: private function getNodeChilds($id) {
202: $parent = $this->data->get($id);
203: return $this->getCopy()
204: ->where(Cons::COLUMN_LEFT . ' > ?', $parent[Cons::COLUMN_LEFT])
205: ->where(Cons::COLUMN_RIGHT . ' < ?', $parent[Cons::COLUMN_RIGHT])
206: ->order(Cons::COLUMN_LEFT);
207: }
208:
209: 210: 211: 212: 213:
214: protected function getMasterNode() {
215: return ($this->getCopy()->where(Cons::COLUMN_PARENT, null)->fetch())? : parent::insert(array(Cons::COLUMN_NAME => Cons::ROOT));
216: }
217:
218: }
219: