Joostina CMS / CMF v2.* API
  • Docs
  • Package
  • Class
  • Tree
  • Todo
Overview

Packages

  • Components
    • Acls
      • Models
        • Admin
        • Site
    • BlogCategory
      • Models
        • Admin
        • Site
    • Blogs
      • Controllers
        • Admin
        • Site
      • Helpers
      • Models
        • Admin
        • Site
    • Coder
      • Controllers
        • Admin
      • Models
        • Admin
    • Comments
      • Controllers
        • Admin
        • Site
      • Helpers
      • Models
        • Admin
        • Site
    • CommentsCounter
      • Models
        • Admin
        • Site
    • Mainpage
      • Controllers
        • Site
    • News
      • Controllers
        • Admin
        • Site
      • Helpers
      • Models
        • Admin
        • Site
    • Pages
      • Controllers
        • Admin
        • Site
      • Models
        • Site
    • Search
      • Controllers
        • Site
    • Site
      • Controllers
        • Admin
        • Site
    • Sitemap
      • Controllers
        • Admin
        • Site
      • Models
        • Admin
        • Site
    • Test
      • Controllers
        • Site
    • Torrents
      • Controllers
        • Site
    • Users
      • Controllers
        • Admin
        • Site
      • Models
        • Admin
        • Site
  • Compression
  • Core
    • Libraries
      • Arhive
      • Array
      • Attached
      • Autoadmin
      • Autoloader
      • Benchmark
      • Breadcrumbs
      • Cache
      • Config
      • Cookie
      • Csrf
      • Database
        • Drivers
          • Interfaces
      • Datetime
      • Debug
      • Editor
      • Events
      • File
      • Filter
      • Flashmessage
      • Folder
      • Hit
      • Html
      • Image
      • Inflector
      • Inputfilter
      • Libraries
      • Mail
      • Module
      • Nestedset
      • Pager
      • Pages
      • Params
      • Randomizer
      • Request
      • RobotLoader
      • Route
      • Security
      • Session
      • Static
      • String
      • Text
      • Trash
      • Validate
  • Email
  • Extra
    • Libraries
      • Basket
  • Joostina
    • Controller
    • Core
    • Document
  • JSMin
  • Libraries
    • Extra
      • Basket
        • Models
          • Site
  • None
  • Plugins
    • Autoadmin
    • Editor
    • Sitemap
  • SimpleMail
  • Vendors
    • Libraries
      • Email

Classes

  • helperAcl
  • joosAdminToolbarButtons
  • joosAdminView
  • joosAdminViewToolbarEdit
  • joosAdminViewToolbarListing
  • joosAutoadminHTML
  • joosTemplater
  • joosValidateHelper
  • modelAdminCoder_Faker
  • moduleActions
  • moduleActionsLogin
  • moduleActionsMenu
  • moduleActionsNews
  • moduleActionsTest
  • Route
  • rulesValidation
  • TreeBuilder

Interfaces

  • joosAutoadminPluginsEdit
  • joosAutoadminPluginsTable

Exceptions

  • joosAutoadminClassPlugionNotFoundException
  • joosAutoadminFilePluginNotFoundException
  • joosAutoloaderClassNotFoundException
  • joosAutoloaderFileNotFoundException
  • joosAutoloaderOnStartFileNotFoundException
  • joosCacheException
  • joosCoreException
  • joosDatabaseException
  • joosException
  • joosFileLibrariesException
  • joosFolderLibrariesException
  • joosImageLibrariesException
  • joosModulesException
  • joosSimpleMailException
  • joosUploadLibrariesException
  • joosUserException
  • JSMinException

Functions

  • navigation_ul_li_recurse
  • quoted_printable_encode
  1: <?php defined('_JOOS_CORE') or exit();
  2: 
  3: /**
  4:  * Работа с вложенными категориями и деревьями в базе данных
  5:  *
  6:  * @version    1.0
  7:  * @package    Core\Libraries
  8:  * @subpackage Nestedset
  9:  * @category   Libraries
 10:  * @author     Joostina Team <info@joostina.ru>
 11:  * @copyright  (C) 2007-2012 Joostina Team
 12:  * @license    MIT License http://www.opensource.org/licenses/mit-license.php
 13:  * Информация об авторах и лицензиях стороннего кода в составе Joostina CMS: docs/copyrights
 14:  *
 15:  * */
 16: class joosNestedSet extends joosModel
 17: {
 18:     /**
 19:      * Уникальный идентификатор узла
 20:      *
 21:      * @var int
 22:      */
 23:     public $id;
 24: 
 25:     /**
 26:      * Левый ключ узла
 27:      *
 28:      * @var int
 29:      */
 30:     public $lft;
 31: 
 32:     /**
 33:      * Правый ключ узла
 34:      *
 35:      * @var int
 36:      */
 37:     public $rgt;
 38: 
 39:     /**
 40:      * Уровень узла
 41:      *
 42:      * @var int
 43:      */
 44:     public $level;
 45: 
 46:     /**
 47:      * ID родительского узла
 48:      *
 49:      * @var int
 50:      */
 51:     public $parent_id;
 52:     public $moved;
 53: 
 54:     /**
 55:      * Имя узла
 56:      *
 57:      * @var str
 58:      */
 59:     public $name;
 60: 
 61:     /**
 62:      * Компонент
 63:      *
 64:      * @var str
 65:      */
 66:     public $group;
 67: 
 68:     /**
 69:      * Ссылка
 70:      *
 71:      * @var str
 72:      */
 73:     public $slug;
 74: 
 75:     /**
 76:      * Database Table Vars
 77:      *
 78:      * @var     array
 79:      */
 80:     private $params = array();
 81: 
 82:     /**
 83:      * Error Messages
 84:      *
 85:      * @var array
 86:      */
 87:     private $errors = array();
 88: 
 89:     /**
 90:      * Constructor set up Vars
 91:      *
 92:      * @param object $db     Object of mysqli-Connection
 93:      * @param array  $params Array with Database-Table Vars
 94:      *
 95:      * @return void
 96:      */
 97:     public function __construct($params)
 98:     {
 99:         parent::__construct($params['table'], 'id');
100: 
101:         $this->params = array('nid' => 'id', 'l' => 'lft', 'r' => 'rgt', 'mov' => 'moved', 'name' => 'name');
102:     }
103: 
104:     /**
105:      * Создание корневого узла, если он не существует
106:      *
107:      * @param string $nodeName Имя узла
108:      *
109:      * @return boolean True or False
110:      */
111:     public function insert_root_node($nodeName)
112:     {
113:         //проверяем, не существует ли уже корневой узел
114:         //если существует - прекрашаем выполнение
115:         if ($this->check_root_node() === true) {
116:             $error = 'Корневой узел уже существует. NestedSet::insert_root_node ("' . $nodeName . '")';
117:             $this->_set_error($error);
118: 
119:             return false;
120:         }
121: 
122:         $this->name = 'root';
123:         $this->lft = 1;
124:         $this->rgt = 2;
125:         $this->level = 0;
126: 
127:         if ($this->store()) {
128:             $error = 'Ошибка запроса к БД. NestedSet::insert_root_node ("' . $nodeName . '")';
129:             $this->_set_error($error);
130: 
131:             return false;
132:         }
133: 
134:         return true;
135:     }
136: 
137:     /**
138:      * Создание/обновление узла
139:      *
140:      * @param array  $data   массив свойств название поля=>значение поля для заполнения свойств модели
141:      * @param string $ignore название аттрибута для игнорирования
142:      *
143:      * @return boolean True or False
144:      */
145:     public function save(array $source, $ignore = '')
146:     {
147:         //Получаем информацию о родительском узле
148:         $parent = new self(array('table' => $this->_tbl));
149: 
150:         if (!$parent->load($source['parent_id'])) {
151:             $error = 'Родительский узел не найден ("' . $source['parent_id'] . '")';
152:             $this->_set_error($error);
153: 
154:             return false;
155:         }
156: 
157:         //TODO: здесь можно добавить проверку на то, сменился ли родитель и делать пересчет узла только в случаем смены
158:         $sql = 'UPDATE ' . $this->_tbl . ' SET `rgt` = `rgt` + 2  WHERE `rgt` >= ' . $parent->rgt;
159:         $this->_db->set_query($sql)->query();
160: 
161:         $sql = 'UPDATE ' . $this->_tbl . ' SET `lft` = `lft` + 2  WHERE `lft` > ' . $parent->rgt;
162:         $this->_db->set_query($sql)->query();
163: 
164:         $this->lft = $parent->rgt;
165:         $this->rgt = $parent->rgt + 1;
166:         $this->level = $parent->level + 1;
167:         $this->parent_id = $parent->id;
168: 
169:         parent::save($source, $ignore);
170: 
171:         return true;
172:     }
173: 
174:     /**
175:      * Удаление узла и всех его потомков (удаление ветви)
176:      *
177:      * @param integer $id Id узла
178:      *
179:      * @return boolean True or False
180:      */
181:     public function delete_branch($id)
182:     {
183:         $branch = clone $this;
184: 
185:         if (!$branch->load($id)) {
186:             $error = 'Требуемый узел не найден';
187:             $this->_set_error($error);
188: 
189:             return false;
190:         }
191: 
192:         //Удаление ветки
193:         $branch->delete_list(array('where' => 'lft BETWEEN ' . $branch->lft . ' AND ' . $branch->rgt));
194: 
195:         //Обновление последующих узлов
196:         $sql = "UPDATE $this->_tbl SET lft = lft - ROUND(($branch->rgt - $branch->lft + 1)) WHERE lft > $branch->rgt";
197:         $this->_db->set_query($sql)->query();
198: 
199:         //Обновление родительской ветки
200:         $sql = "UPDATE $this->_tbl SET rgt = rgt - ROUND(($branch->rgt - $branch->lft + 1)) WHERE rgt > $branch->rgt";
201:         $this->_db->set_query($sql)->query();
202: 
203:         return true;
204:     }
205: 
206:     /**
207:      * Удаление одиночного узла
208:      *
209:      * @param integer $id Id узла
210:      *
211:      * @return boolean True or False
212:      */
213:     public function delete_node($id)
214:     {
215:         $node = clone $this;
216: 
217:         if (!$node->load($id)) {
218:             $error = 'Требуемый узел не найден';
219:             $this->_set_error($error);
220: 
221:             return false;
222:         }
223: 
224:         $sql = "DELETE FROM $this->_tbl WHERE lft = $node->lft";
225:         $this->_db->set_query($sql)->query();
226: 
227:         $sql = "UPDATE $this->_tbl SET lft = lft - 1, rgt = rgt - 1 WHERE lft BETWEEN $node->lft AND $node->rgt";
228:         $this->_db->set_query($sql)->query();
229: 
230:         $sql = "UPDATE $this->_tbl SET lft = lft - 2 WHERE lft > $node->rgt";
231:         $this->_db->set_query($sql)->query();
232: 
233:         $sql = "UPDATE $this->_tbl SET rgt = rgt - 2 WHERE rgt > $node->rgt";
234:         $this->_db->set_query($sql)->query();
235: 
236:         return true;
237:     }
238: 
239:     /**
240:      * Узел/ветка влево (перемещение "вверх" в пределах уровня)
241:      *
242:      * @param integer $id Id узла
243:      *
244:      * @return boolean True or False
245:      */
246:     public function move_lft($id)
247:     {
248:         $node = clone $this;
249: 
250:         if (!$node->load($id)) {
251:             $error = 'Требуемый узел не найден';
252:             $this->_set_error($error);
253: 
254:             return false;
255:         }
256: 
257:         $a_lft = $node->lft;
258:         $a_rgt = $node->rgt;
259: 
260:         if (!$b_id = $this->_get_id($a_lft - 1, 'r')) {
261:             $error = 'Родственный узел слева не найден. NestedSet::move_lft (' . $id . ')';
262:             $this->_set_error($error);
263: 
264:             return false;
265:         }
266: 
267:         if (!$b = $this->_get_node($b_id)) {
268:             $error = 'Родственный узел слева не найден. NestedSet::move_lft (' . $id . ')';
269:             $this->_set_error($error);
270: 
271:             return false;
272:         }
273: 
274:         $b_lft = $b['lft'];
275:         $b_rgt = $b['rgt'];
276: 
277:         $diffRgt = $a_rgt - $b_rgt;
278:         $diffLft = $a_lft - $b_lft;
279: 
280:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
281:         $this->_db->set_query($sql)->query();
282: 
283:         $sql = sprintf('UPDATE `%1$s` SET `%3$s` = `%3$s` + %5$d,`%4$s` = `%4$s` + %5$d,`%2$s` = %12$d WHERE `%4$s` BETWEEN %9$d AND %10$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
284:         $this->_db->set_query($sql)->query();
285: 
286:         $sql = sprintf('UPDATE `%1$s` SET `%3$s` = `%3$s` - %6$d,`%4$s` = `%4$s` - %6$d WHERE `%4$s` BETWEEN %7$d AND %8$d AND `%2$s` = %11$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
287:         $this->_db->set_query($sql)->query();
288: 
289:         $sql = sprintf('UPDATE `%1$s` SET`%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'rgt', 'lft', (int) $diffRgt, (int) $diffLft, (int) $a_lft, (int) $a_rgt, (int) $b_lft, (int) $b_rgt, 0, 1);
290:         $this->_db->set_query($sql)->query();
291: 
292:         return true;
293:     }
294: 
295:     /**
296:      * Узел/ветка вправо (перемещение "вниз" в пределах уровня)
297:      *
298:      * @param integer $nodeId Id узла
299:      *
300:      * @return boolean True or False
301:      */
302:     public function move_rgt($nodeId)
303:     {
304:         $nodeLevel = $this->_get_node_level($nodeId);
305: 
306:         if ($nodeLevel == 0) {
307:             $error = 'Это корневой узел, его нельзя перемещать. NestedSet::move_rgt (' . $nodeId . ' ' . $nodeLevel . ')';
308:             $this->_set_error($error);
309: 
310:             return false;
311:         }
312: 
313:         $a = $this->_get_node($nodeId);
314:         $a_lft = $a['lft'];
315:         $a_rgt = $a['rgt'];
316: 
317:         if (!$b_id = $this->_get_id($a_rgt + 1, 'l')) {
318:             $error = 'Родственный узел справа не найден. NestedSet::move_rgt (' . $nodeId . ')';
319:             $this->_set_error($error);
320: 
321:             return false;
322:         }
323: 
324:         if (!$b = $this->_get_node($b_id)) {
325:             $error = 'Родственный узел справа не найден. NestedSet::move_rgt (' . $nodeId . ')';
326:             $this->_set_error($error);
327: 
328:             return false;
329:         }
330: 
331:         $b_lft = $b['lft'];
332:         $b_rgt = $b['rgt'];
333: 
334:         $diffRgt = $b_rgt - $a_rgt;
335:         $diffLft = $b_lft - $a_lft;
336: 
337:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
338:         $this->_db->set_query($sql)->query();
339: 
340:         $sql = sprintf('UPDATE `%1$s` SET `%4$s` = `%4$s` - %5$d, `%3$s` = `%3$s` - %5$d, `%2$s` = %12$d WHERE `%3$s` BETWEEN %7$d AND %8$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
341:         $this->_db->set_query($sql)->query();
342: 
343:         $sql = sprintf('UPDATE `%1$s` SET `%4$s` = `%4$s` + %6$d, `%3$s` = `%3$s` + %6$d WHERE `%3$s` BETWEEN %9$d AND %10$d AND `%2$s` = %11$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
344:         $this->_db->set_query($sql)->query();
345: 
346:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = %11$d WHERE `%2$s` <> %11$d', $this->_tbl, $this->params['mov'], 'lft', 'rgt', (int) $diffLft, (int) $diffRgt, (int) $b_lft, (int) $b_rgt, (int) $a_lft, (int) $a_rgt, 0, 1);
347:         $this->_db->set_query($sql)->query();
348: 
349:         return true;
350:     }
351: 
352:     /**
353:      * Узел/ветка вверх (перемещение на уровень вверх)
354:      *
355:      * @param integer $nodeId Id узла
356:      *
357:      * @return boolean True or False
358:      */
359:     public function move_up($nodeId)
360:     {
361:         $nodeLevel = $this->_get_node_level($nodeId);
362: 
363:         //echo 'Уровень узла: '.$nodeLevel;
364: 
365:         if ($nodeLevel == 0) {
366:             $error = 'Это корневой узел, его нельзя перемещать. NestedSet::move_up (' . $nodeId . ')';
367:             $this->_set_error($error);
368: 
369:             return false;
370:         }
371: 
372:         if ($nodeLevel == 1) {
373:             $error = 'Родственный узел справа не найден. NestedSet::move_up (' . $nodeId . ')';
374:             $this->_set_error($error);
375: 
376:             return false;
377:         }
378: 
379:         do {
380:             if (!$moved = $this->move_rgt($nodeId)) {
381:                 break;
382:             }
383:         } while ($moved === true);
384: 
385:         $a = $this->_get_node($nodeId);
386:         $a_lft = $a['lft'];
387:         $a_rgt = $a['rgt'];
388: 
389:         if (!$b_id = $this->_get_id($a_rgt + 1, 'r')) {
390:             $error = 'На корневной уровень нельзя переместиться. NestedSet::move_up (' . $nodeId . ')';
391:             $this->_set_error($error);
392: 
393:             return false;
394:         }
395: 
396:         if (!$b = $this->_get_node($b_id)) {
397:             $error = 'На корневной уровень нельзя переместиться. NestedSet::move_up (' . $nodeId . ')';
398:             $this->_set_error($error);
399: 
400:             return false;
401:         }
402: 
403:         //$b_lft = $b['lft'];
404:         //$b_rgt = $b['rgt'];
405: 
406:         $nodeWidth = $a_rgt - $a_lft + 1;
407: 
408:         //узел и дочерние узлы
409:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` + %9$d,`%3$s` = `%3$s` + %9$d, level = level - 1  WHERE `%3$s`BETWEEN %5$d AND %6$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
410:         $this->_db->set_query($sql)->query();
411: 
412:         //родительский узел
413:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` - %7$d WHERE `%4$s` = %8$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
414:         $this->_db->set_query($sql)->query();
415: 
416:         //меняем parent_id у перемещаемого узла
417:         $a = $this->_get_node($nodeId);
418:         $p_id = $this->get_parent($a)->id;
419:         $sql = "UPDATE $this->_tbl SET parent_id = $p_id  WHERE id = " . $nodeId;
420:         $this->_db->set_query($sql)->query();
421: 
422:         return true;
423:     }
424: 
425:     public function get_parent($child)
426:     {
427:         $sql = "SELECT * FROM  $this->_tbl WHERE lft <= {$child['lft']} AND rgt >= {$child['rgt']} AND level = {$child['level']} - 1 ORDER BY lft";
428: 
429:         $result = null;
430:         $this->_db->set_query($sql)->load_object($result);
431: 
432:         return $result;
433:     }
434: 
435:     /**
436:      * Узел/ветка вниз (перемещение на уровень вниз)
437:      *
438:      * @param integer $nodeId Id узла
439:      *
440:      * @return boolean True or False
441:      */
442:     public function move_down($nodeId)
443:     {
444:         $nodeLevel = $this->_get_node_level($nodeId);
445: 
446:         if ($nodeLevel == 1) {
447:             $error = 'Это корневой узел, его нельзя перемещать. NestedSet::move_down (' . $nodeId . ')';
448:             $this->_set_error($error);
449: 
450:             return false;
451:         }
452: 
453:         $a = $this->_get_node($nodeId);
454:         $a_lft = $a['lft'];
455:         $a_rgt = $a['rgt'];
456: 
457:         if (!$b_id = $this->_get_id($a_lft - 1, 'r')) {
458:             $error = 'Родственный узел слева не найден. NestedSet::move_down (' . $nodeId . ')';
459:             $this->_set_error($error);
460: 
461:             return false;
462:         }
463:         if (!$b = $this->_get_node($b_id)) {
464:             $error = 'Родственный узел слева не найден. NestedSet::move_down (' . $nodeId . ')';
465:             $this->_set_error($error);
466: 
467:             return false;
468:         }
469: 
470:         //$b_lft = $b['lft'];
471:         //$b_rgt = $b['rgt'];
472: 
473:         $nodeWidth = $a_rgt - $a_lft + 1;
474: 
475:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` - %9$d, `%3$s` = `%3$s` - %9$d, level = level + 1  WHERE `%3$s` BETWEEN %5$d AND %6$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
476:         $this->_db->set_query($sql)->query();
477: 
478:         $sql = sprintf('UPDATE `%1$s` SET parent_id = %8$d  WHERE id = ' . $nodeId, $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
479:         $this->_db->set_query($sql)->query();
480: 
481:         $sql = sprintf('UPDATE `%1$s` SET `%2$s` = `%2$s` + %7$d WHERE `%4$s` = %8$d', $this->_tbl, 'rgt', 'lft', $this->params['nid'], (int) $a_lft, (int) $a_rgt, (int) $nodeWidth, (int) $b_id, 1);
482:         $this->_db->set_query($sql)->query();
483: 
484:         //меняем parent_id у перемещаемого узла
485:         $a = $this->_get_node($nodeId);
486:         $p_id = $this->get_parent($a)->id;
487:         $sql = "UPDATE $this->_tbl SET parent_id = $p_id  WHERE id = " . $nodeId;
488:         $this->_db->set_query($sql)->query();
489: 
490:         return true;
491:     }
492: 
493:     /**
494:      * Проверка на существование корневого узла
495:      *
496:      * @return boolean True or False
497:      */
498:     public function check_root_node()
499:     {
500:         $sql = sprintf('SELECT `%1$s` FROM `%2$s` WHERE `%3$s` = %4$d', $this->params['nid'], $this->_tbl, 'lft', 1);
501:         $this->_db->set_query($sql);
502: 
503:         if (!$result = $this->_db->query()) {
504:             $error = 'Ошибка запроса к БД. NestedSet::check_root_node ()';
505:             $this->_set_error($error);
506: 
507:             return false;
508:         }
509: 
510:         if (!$result->num_rows) {
511:             $error = 'Корневой узел не найден. NestedSet::check_root_node ()';
512:             $this->_set_error($error);
513: 
514:             return false;
515:         }
516: 
517:         return true;
518:     }
519: 
520:     /**
521:      * Проверка на существвоание ошибок
522:      *
523:      * @return boolean True or False
524:      */
525:     public function is_error()
526:     {
527:         return (empty($this->errors)) ? false : true;
528:     }
529: 
530:     /**
531:      * Возвращает текст ошибки
532:      *
533:      * @return mixed array         array Error Messages or null
534:      */
535:     public function get_errors()
536:     {
537:         return (true === $this->is_error()) ? $this->errors : null;
538:     }
539: 
540:     /**
541:      * Получение полного дерево в виде массива
542:      *
543:      * @return mixed Возвращает массив или False
544:      */
545:     public function get_full_tree_extended()
546:     {
547:         $where_group = $this->group ? ' AND n.group = "' . $this->group . '" ' : '';
548: 
549:         $sql = sprintf('SELECT
550:                             `%1$s`.*, round((`%1$s`.`%4$s` - `%1$s`.`%3$s` - %8$d) / %9$d, %7$d) AS childs,
551:                             n.level AS level,
552:                             ((min(`%2$s`.`%4$s`) - `%1$s`.`%4$s` - (`%1$s`.`%3$s` > %8$d)) / %9$d) > %7$d AS lower,
553:                             (((`%1$s`.`%3$s` - max(`%2$s`.`%3$s`) > %8$d))) AS upper
554:                         FROM `%5$s` `%1$s`, `%5$s` `%2$s`
555:                         WHERE
556:                             `%1$s`.`%3$s` BETWEEN `%2$s`.`%3$s`
557:                             AND `%2$s`.`%4$s` AND ( `%2$s`.`%6$s` != `%1$s`.`%6$s` OR `%1$s`.`%3$s` = %8$d )
558:                             ' . $where_group . '
559:                         GROUP BY `%1$s`.`%6$s`
560:                         ORDER BY `%1$s`.`%3$s`', 'n', 'p', 'lft', 'rgt', $this->_tbl, $this->params['nid'], 0, 1, 2);
561: 
562:         $this->_db->set_query($sql);
563: 
564:         return $this->_db->load_assoc_list();
565:     }
566: 
567:     /**
568:      * Получение полного дерево в виде массива
569:      *
570:      * @return mixed Возвращает массив или False
571:      */
572:     public function get_full_tree_simple()
573:     {
574:         $where_group = $this->group ? ' WHERE `group` = "' . $this->group . '" ' : '';
575: 
576:         $this->_db->set_query("SELECT * FROM $this->_tbl $where_group ORDER BY lft ASC");
577: 
578:         $result = $this->_db->load_assoc_list('id');
579: 
580:         return $result ? $result : array();
581:     }
582: 
583:     /**
584:      * Выбор ветки
585:      *
586:      * @param integer $lft Левая граница корня ветки
587:      * @param integer $rgt Правая граница корня ветки
588:      *
589:      * @return mixed Возвращает ассоциативный массив
590:      */
591:     public function get_branch($lft, $rgt, $object_list = false)
592:     {
593:         $this->_db->set_query("SELECT *, round((rgt - lft - 1) / 2, 0) AS childs_count FROM $this->_tbl WHERE lft >= $lft AND rgt <= $rgt ORDER BY lft");
594: 
595:         return $object_list ? $this->_db->load_object_list('id') : $this->_db->load_assoc_list('id');
596: 
597:         //return $result ? $result : array();
598:     }
599: 
600:     /**
601:      * Выбор подчиненных категорий
602:      *
603:      * @param integer $id ID родителя
604:      *
605:      * @return mixed Возвращает ассоциативный массив
606:      */
607:     public function get_children($id, $object_list = false)
608:     {
609:         $this->_db->set_query("SELECT * FROM $this->_tbl WHERE parent_id = $id  ORDER BY lft");
610: 
611:         return $object_list ? $this->_db->load_object_list('id') : $this->_db->load_assoc_list('id');
612: 
613:         //return $result ? $result : array();
614:     }
615: 
616:     /**
617:      * Получение пути от корня до требуемого узла
618:      *
619:      * @param integer $nodeId Id узла
620:      *
621:      * @return mixed массив или False
622:      */
623:     public function get_path_from_root($nodeId, $object_list = false)
624:     {
625:         $sql = "SELECT p.*
626:             FROM $this->_tbl AS n, $this->_tbl AS p
627:             WHERE p.lft <= n.lft AND p.rgt >= n.rgt AND n." . $this->params['nid'] . " = " . (int) $nodeId . "
628:             ORDER BY p.lft";
629: 
630:         return $object_list ? $this->_db->set_query($sql)->load_object_list() : $this->_db->set_query($sql)->load_assoc_list('id');
631:     }
632: 
633:     /**
634:      * Получение ID узла по значению его левой или правой границы
635:      *
636:      * @param integer $directionValue Значение левой или правой границы
637:      * @param string  $direction      Граница: левая или правая
638:      *
639:      * @return mixed integer Id узла или  False
640:      */
641:     private function _get_id($directionValue, $direction)
642:     {
643:         $sql = sprintf('SELECT `%1$s` FROM `%2$s` WHERE `%3$s` = %4$d', $this->params['nid'], $this->_tbl, $this->params[$direction], (int) $directionValue);
644:         $this->_db->set_query($sql);
645: 
646:         if (!$result = $this->_db->query()) {
647:             $error = 'Ошибка запроса к БД. NestedSet::_get_id()';
648:             $this->_set_error($error);
649: 
650:             return false;
651:         }
652: 
653:         if (!$result->num_rows) {
654:             $error = 'Невозможно получить информацию по предоставленным данным. NestedSet::_get_id()';
655:             $this->_set_error($error);
656: 
657:             return false;
658:         }
659: 
660:         $row = $result->fetch_assoc();
661: 
662:         return $row[$this->params['nid']];
663:     }
664: 
665:     /**
666:      * Получение массива со следующими данными: ID узла, значение левой и правой границы узла
667:      *
668:      * @param integer $nodeId Id узла
669:      *
670:      * @return mixed Массив с данными или False
671:      */
672:     private function _get_node($nodeId)
673:     {
674:         $sql = sprintf('SELECT `%1$s`,`%2$s`,`%3$s`, level FROM `%4$s` WHERE `%1$s` = %5$d', $this->params['nid'], 'lft', 'rgt', $this->_tbl, (int) $nodeId);
675:         $this->_db->set_query($sql);
676: 
677:         if (!$result = $this->_db->query()) {
678:             $error = 'Ошибка запроса к БД. NestedSet::_get_node()';
679:             $this->_set_error($error);
680: 
681:             return false;
682:         }
683: 
684:         if (!$result->num_rows) {
685:             $error = 'Требуемый узел не найден. NestedSet::_get_node()';
686:             $this->_set_error($error);
687: 
688:             return false;
689:         }
690: 
691:         $row = $result->fetch_assoc();
692: 
693:         return $row;
694:     }
695: 
696:     /**
697:      * Определение уровня узла
698:      *
699:      * @param integer $nodeId Id узла
700:      *
701:      * @return mixed integer     Уровень узла (0 = Root) или False
702:      */
703:     private function _get_node_level($nodeId)
704:     {
705:         /*
706:           $sql = sprintf('
707:           SELECT COUNT(*) AS `level`
708:           FROM `%3$s` `%2$s`,`%3$s` `%1$s`
709:           WHERE `%1$s`.`%5$s` BETWEEN `%2$s`.`%5$s` AND `%2$s`.`%6$s`
710:           GROUP BY `%1$s`.`%5$s`
711:           ORDER BY ABS(`%1$s`.`%4$s` - %7$d)', 'n', 'p', $this->_tbl, $this->params['nid'], 'lft', 'rgt', (int) $nodeId);
712:           $this->_db->set_query($sql);
713: 
714:           if (!$result = $this->_db->query()) {
715:           $error = 'Ошибка запроса к БД. NestedSet::_get_node_level()';
716:           $this->_set_error($error);
717: 
718:           return false;
719:           }
720: 
721:           if (!$result->num_rows) {
722:           $error = 'Требуемый узел не найден. NestedSet::_get_node_level()';
723:           $this->_set_error($error);
724: 
725:           return false;
726:           }
727: 
728:           $row = $result->fetch_assoc();
729: 
730:           return $row['level'];
731:          */
732: 
733:         $query = 'SELECT level FROM `' . $this->_tbl . '` WHERE `' . $this->_tbl . '`.`' . $this->params['nid'] . '` = ' . (int) $nodeId;
734:         if (!$result = $this->_db->set_query($query)->load_result()) {
735:             return false;
736:         }
737: 
738:         return $result;
739:     }
740: 
741:     /**
742:      * Получение общего количества узлов
743:      *
744:      * @return mixed integer Количество или boolean False
745:      */
746:     private function _count_nodes()
747:     {
748:         $sql = sprintf('SELECT COUNT(`%1$s`) FROM `%2$s` AS `count`', $this->params['nid'], $this->_tbl);
749:         $this->_db->set_query($sql);
750: 
751:         if (!$result = $this->_db->query()) {
752:             $error = 'Ошибка запроса к БД. NestedSet::_count_nodes()';
753:             $this->_set_error($error);
754: 
755:             return false;
756:         }
757: 
758:         if (!$result->num_rows) {
759:             $error = 'Узлы не найдены. NestedSet::_count_nodes()';
760:             $this->_set_error($error);
761: 
762:             return false;
763:         }
764: 
765:         $row = $result->fetch_assoc();
766: 
767:         return $row['count'];
768:     }
769: 
770:     /**
771:      * SСохранение ошибки в массив с ошибками
772:      *
773:      * @param string $error Текст ошибки
774:      *
775:      * @return void
776:      */
777:     private function _set_error($error)
778:     {
779:         $this->errors[] = $error;
780:     }
781: 
782: }
783: 
784: class TreeBuilder
785: {
786:     public $items = array();
787:     public $children = array();
788: 
789:     public function __construct($items)
790:     {
791:         $this->items = $items;
792:         $this->children = array();
793: 
794:         foreach ($items as $v) {
795:             $list = isset($this->children[$v->parent_id]) ? $this->children[$v->parent_id] : array();
796:             array_push($list, $v);
797:             $this->children[$v->parent_id] = $list;
798:         }
799: 
800:         //_xdump($this->children);
801:     }
802: 
803:     public function build_tree($id, $list = array(), $maxlevel = 9999, $level = 0)
804:     {
805:         if (isset($this->children[$id]) && $level <= $maxlevel) {
806:             $i = 1;
807: 
808:             foreach ($this->children[$id] as $v) {
809:                 $id = $v->id;
810: 
811:                 if (isset($this->children[$id])) {
812:                     $list[$id] = $v;
813:                     $list[$id]->children = $this->children[$id];
814:                     $list = $this->build_tree($id, $list, $maxlevel, $level + 1);
815:                 } else {
816:                     //$list[$id]->children = 0;
817:                 }
818: 
819:                 //$list[$id]->children = isset($this->children[$id]) ? $this->children[$id] : 0;
820:                 //$list = $this->build_tree($id, $list, $maxlevel, $level + 1);
821:                 $i++;
822:             }
823: 
824:             //unset($this->children[$id]);
825:         }
826: 
827:         //_xdump($list);
828: 
829:         return $list;
830:     }
831: 
832: }
833: 
Joostina CMS / CMF v2.* API API documentation generated by ApiGen 2.6.1 – Template adapted by @olvlv and Joostina Team