0 Пользователей и 1 Гость просматривают эту тему.
  • 21 Ответов
  • 2028 Просмотров
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Это не расширение Joomla, конечно, но, тем не менее, авторское решение форумчанина форумчан!
Часто бывает надо получить из таблицы связей категорий вида «id_категории - id_родительской» - массив с деревом всех подкатегорий.
Это бывает актуально как для всех категорий (целое дерево), так и для отдельных категорий (одна из веток) - все её подкатегории, всех уровней.
В общем, оформил в виде класса. И потом коллективно переделали/доработали.
После определения класса достаточно двух строчек кода, чтобы получить нужное дерево или ветку  ;)

Работает быстро за счёт того, что, в отличие от некоторых других решений, делает всего 1 sql запрос.
Один раз получает таблицу связей, а потом на её основе строит нужное дерево.

В метод getTable заложил реализацию для категорий VirtueMart. Как понимаете, несложной адаптацией запроса можно использовать это с любым расширением, использующим хранение связей категории в виде «id_категории - id_родительской».
Кроме того, при создании объекта класса можно просто передать результаты запроса к своей таблице в параметре, тогда он не будет выполнять свой внутренний запрос.

Пример использования:
Код
$tree = new JFTree();

// дочерние для cat_id=55, включая её id
$sub_cat_list_string = $tree->get_children_list_string(55);

// родители для 367 (в виде массива), не включая её id
$parent_list_array = $tree->get_parents_list(367, false);

unset($tree);
Согласитесь, удобно )

Так вот, код класса (сложенный совместными усилиями):

Код
<?php

/**
 * JFTree
 * build categories tree
 *
 * @authors joomlaforum.ru
 * @return subcategories tree all levels
 *
 * @example of usage:
 * $tree = new JFTree(); // tree object for DB query results from function getTable()
 * $a = new JFTree($results_db_query_loadObjectList); // tree object for custom DB query results with parent_id, child_id
 * $b = $tree->get_branch(); // tree with children of root category
 * $c = $tree->get_branch(55); // tree with children of category id=55
 * $d = $tree->get_children_list(); // list (array) with all children of root category
 * $e = $tree->get_children_list(55); // list (array) with all children of category id 55 and itself id
 * $f = $tree->get_children_list(55, false); // list (array) with all children of category id 55 (without itself id)
 * $g = $tree->get_children_list_string(55); // comma-separated list with all children of category id 55 and itself id
 * $h = $tree->get_children_list_string(55, false); // comma-separated list with all children of category id 55 *
 * NEW get_parents_list & get_parents_list_string
 * $i = $tree->get_subcats_lists_for_all_cats(); // array with all cat_id in indexes and subcats lists in values
 * unset($tree);
 */
class JFTree
{
    public $tree = array();
    public $parents = array();
   
    function __construct($table = array())
    {
        if (empty($tree)) {
            if (empty($table)) $table = $this->getTable();
            foreach ($table as $item) {
                if (empty($item->parent_id)) $item->parent_id = 0; // may be NULL and other
                if (!isset($this->tree[$item->parent_id])) $this->tree[$item->parent_id] = array();
                if (!isset($this->tree[$item->child_id])) $this->tree[$item->child_id] = array();
                $this->tree[$item->parent_id][$item->child_id] = & $this->tree[$item->child_id];
                if (!isset($this->parents[$item->parent_id])) $this->parents[$item->parent_id] = array();
                if (!isset($this->parents[$item->child_id])) $this->parents[$item->child_id] = array();
                $this->parents[$item->child_id][$item->parent_id] = & $this->parents[$item->parent_id];
            }
        }
    }
   
    private function getTable()
    {
        $db = JFactory::getDbo();
        $query = '
            SELECT category_parent_id AS parent_id, category_child_id AS child_id
            FROM #__virtuemart_category_categories';
        $db->setQuery($query);
        return $db->loadObjectList();
    }
   
    public function get_branch($parent_id = 0)
    {
        return isset($this->tree[$parent_id]) ? $this->tree[$parent_id] : false;
    }
   
    public function get_children_list($cat_id = 0, $with_it = true)
    {
        $list = array();
        if (preg_match_all('|\[(\d+)\]|isU', print_r($this->get_branch($cat_id), true), $pregs)) {
            $list = $pregs[1];
        }
        if ($with_it && $cat_id != 0) array_unshift($list, $cat_id);
        return $list;
    }
   
    public function get_children_list_string($cat_id = 0, $with_it = true)
    {
        $list = $this->get_children_list($cat_id, $with_it);
        return implode(', ', $list);
    }
   
    public function get_parents($cat_id = 0)
    {
        return isset($this->parents[$cat_id]) ? $this->parents[$cat_id] : false;
    }
   
    public function get_parents_list($cat_id = 0, $with_it = true, $with_root = false)
    {
        $list = array();
        if (preg_match_all('|\[(\d+)\]|isU', print_r($this->get_parents($cat_id), true), $pregs)) {
            $list = $pregs[1];
        }
        $list = array_reverse($list);
        if (!$with_root && $list[0] == 0) {
            unset($list[0]);
            $list = array_values($list);
        }
        if ($with_it && $cat_id != 0) $list[] = $cat_id;
        return $list;
    }
   
    public function get_parents_list_string($cat_id = 0, $with_it = true, $with_root = false)
    {
        $list = $this->get_parents_list($cat_id, $with_it);
        return implode(', ', $list);
    }
   
    public function get_subcats_lists_for_all_cats($with_root = false)
    {
        $lists = [];       
        foreach ($this->tree as $id => $val) {
            if (!$with_root && $id == 0) continue;
            $list = $this->get_children_list($id);
            $lists[$id] = $list;
        }
        return $lists;
    }
}

Принимаю отзывы, предложения и пожелания )
« Последнее редактирование: 20.10.2020, 15:15:28 от rsn »
Возможно, будет интересно: Интеграция с Ozon
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Пример результата (для первой (старой) версии класса):
Код
Tree Object
(
    [id] => 0
    [children] => Array
        (
            [0] => Tree Object
                (
                    [id] => 265
                    [children] => Array
                        (
                            [0] => Tree Object
                                (
                                    [id] => 566
                                    [children] => Array
                                        (
                                            [0] => Tree Object
                                                (
                                                    [id] => 650
                                                    [children] => Array
                                                        (
                                                            [0] => Tree Object
                                                                (
                                                                    [id] => 282
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                            [1] => Tree Object
                                                                (
                                                                    [id] => 295
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                            [2] => Tree Object
                                                                (
                                                                    [id] => 624
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                            [3] => Tree Object
                                                                (
                                                                    [id] => 641
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                            [4] => Tree Object
                                                                (
                                                                    [id] => 651
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                        )

                                                )

                                            [1] => Tree Object
                                                (
                                                    [id] => 562
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => Tree Object
                                                (
                                                    [id] => 293
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [3] => Tree Object
                                                (
                                                    [id] => 294
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [4] => Tree Object
                                                (
                                                    [id] => 538
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [1] => Tree Object
                                (
                                    [id] => 308
                                    [children] => Array
                                        (
                                        )

                                )

                            [2] => Tree Object
                                (
                                    [id] => 305
                                    [children] => Array
                                        (
                                            [0] => Tree Object
                                                (
                                                    [id] => 506
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => Tree Object
                                                (
                                                    [id] => 307
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => Tree Object
                                                (
                                                    [id] => 306
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [3] => Tree Object
                                                (
                                                    [id] => 508
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [4] => Tree Object
                                                (
                                                    [id] => 507
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [3] => Tree Object
                                (
                                    [id] => 309
                                    [children] => Array
                                        (
                                        )

                                )

                            [4] => Tree Object
                                (
                                    [id] => 291
                                    [children] => Array
                                        (
                                        )

                                )

                            [5] => Tree Object
                                (
                                    [id] => 502
                                    [children] => Array
                                        (
                                            [0] => Tree Object
                                                (
                                                    [id] => 576
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [6] => Tree Object
                                (
                                    [id] => 397
                                    [children] => Array
                                        (
                                        )

                                )

                            [7] => Tree Object
                                (
                                    [id] => 398
                                    [children] => Array
                                        (
                                        )

                                )

                            [8] => Tree Object
                                (
                                    [id] => 446
                                    [children] => Array
                                        (
                                            [0] => Tree Object
                                                (
                                                    [id] => 560
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => Tree Object
                                                (
                                                    [id] => 594
                                                    [children] => Array
                                                        (
                                                            [0] => Tree Object
                                                                (
                                                                    [id] => 599
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                            [1] => Tree Object
                                                                (
                                                                    [id] => 597
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                            [2] => Tree Object
                                                                (
                                                                    [id] => 598
                                                                    [children] => Array
                                                                        (
                                                                        )

                                                                )

                                                        )

                                                )

                                            [2] => Tree Object
                                                (
                                                    [id] => 595
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [3] => Tree Object
                                                (
                                                    [id] => 596
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [9] => Tree Object
                                (
                                    [id] => 396
                                    [children] => Array
                                        (
                                            [0] => Tree Object
                                                (
                                                    [id] => 504
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [1] => Tree Object
                                                (
                                                    [id] => 505
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [2] => Tree Object
                                                (
                                                    [id] => 503
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [3] => Tree Object
                                                (
                                                    [id] => 542
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                            [4] => Tree Object
                                                (
                                                    [id] => 556
                                                    [children] => Array
                                                        (
                                                        )

                                                )

                                        )

                                )

                            [10] => Tree Object
                                (
                                    [id] => 510
                                    [children] => Array
                                        (
                                        )

                                )

                            [11] => Tree Object
                                (
                                    [id] => 509
                                    [children] => Array
                                        (
                                        )

                                )

                            [12] => Tree Object
                                (
                                    [id] => 426
                                    [children] => Array
                                        (
                                        )

                                )

                            [13] => Tree Object
                                (
                                    [id] => 425
                                    [children] => Array
                                        (
                                        )

                                )

                            [14] => Tree Object
                                (
                                    [id] => 563
                                    [children] => Array
                                        (
                                        )

                                )

                            [15] => Tree Object
                                (
                                    [id] => 621
                                    [children] => Array
                                        (
                                        )

                                )

                            [16] => Tree Object
                                (
                                    [id] => 399
                                    [children] => Array
                                        (
                                        )

                                )

                            [17] => Tree Object
                                (
                                    [id] => 467
                                    [children] => Array
                                        (
                                        )

                                )

                            [18] => Tree Object
                                (
                                    [id] => 564
                                    [children] => Array
                                        (
                                        )

                                )

                            [19] => Tree Object
                                (
                                    [id] => 601
                                    [children] => Array
                                        (
                                        )

                                )

                            [20] => Tree Object
                                (
                                    [id] => 555
                                    [children] => Array
                                        (
                                        )

                                )

                            [21] => Tree Object
                                (
                                    [id] => 557
                                    [children] => Array
                                        (
                                        )

                                )

                            [22] => Tree Object
                                (
                                    [id] => 565
                                    [children] => Array
                                        (
                                        )

                                )

                            [23] => Tree Object
                                (
                                    [id] => 561
                                    [children] => Array
                                        (
                                        )

                                )

                        )

                )
...
« Последнее редактирование: 03.10.2020, 17:42:07 от rsn »
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Сойдет. Правда, можно было обойтись без связывания таблиц в запросе и без рекурсий. Но это дело вкуса.
Если вдруг ИД вложенной категории окажется меньше, чем ИД ее родителя - отработает правильно или "потеряет" эту вложенную категорию?
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
можно было обойтись ... без рекурсий
Это как - покажете?
Если число уровней может быть любым
Возможно, будет интересно: Интеграция с Ozon
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Если вдруг ИД вложенной категории окажется меньше, чем ИД ее родителя - отработает правильно или "потеряет"
Отработает правильно.
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Это как - покажете?
Почему нет. Формат вывода будет немного другой, чем у вас, но можно сделать и точно такой же, если это принципиально. Будет ли это быстрее, чем ваш вариант, не знаю - проверьте.
Код
<?php
/**
 * build categories tree for root category or subcategory
 *
 * @author alexey@gnevyshev.ru
 * @return subcategories tree all levels
 *
 * @example of usage:
 * $tree = new Tree(0);
 */
class Tree
{
    public $tree = array();
   
    function __construct($table = array())
    {
        if(empty($tree)){
            if(empty($table)) $table = $this->getTable();
            foreach($table as $item){
                if(!isset($this->tree[$item->category_parent_id])) $this->tree[$item->category_parent_id] = array();
                if(!isset($this->tree[$item->category_child_id])) $this->tree[$item->category_child_id] = array();
                $this->tree[$item->category_parent_id][$item->category_child_id] = &$this->tree[$item->category_child_id];
            }
        }
    }
   
    private function getTable()
    {
        $db = JFactory::getDbo();
        $query = '
            SELECT cc.category_parent_id, cc.category_child_id
            FROM #__virtuemart_category_categories cc
        ';
        $db->setQuery($query);
        $relations_table = $db->loadObjectList();
        return $relations_table;
    }
   
    public function find_children($parent_id = 0)
    {
        return isset($this->tree[$parent_id])? $this->tree[$parent_id] : false;
    }
}
Работать должно примерно так:
Код
$tree = new Tree();
$rootChildren = $tree->find_children();
$chldren3 = $tree->find_children(3);
$children8 = $tree->find_children(8);
print_r($rootChildren);
print_r($chldren3);
print_r($children8);
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Спасибо,
поэкспериментирую на досуге
Возможно, будет интересно: Интеграция с Ozon
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Будет ли это быстрее, чем ваш вариант, не знаю - проверьте.
Код
<?php
/**
 * build categories tree for root category or subcategory
 *
 * @author alexey@gnevyshev.ru
 * @return subcategories tree all levels
 *
 * @example of usage:
 * $tree = new Tree(0);
 */
class Tree
{
    public $tree = array();
   
    function __construct($table = array())
    {
        if(empty($tree)){
            if(empty($table)) $table = $this->getTable();
            foreach($table as $item){
                if(!isset($this->tree[$item->category_parent_id])) $this->tree[$item->category_parent_id] = array();
                if(!isset($this->tree[$item->category_child_id])) $this->tree[$item->category_child_id] = array();
                $this->tree[$item->category_parent_id][$item->category_child_id] = &$this->tree[$item->category_child_id];
            }
        }
    }
   
    private function getTable()
    {
        $db = JFactory::getDbo();
        $query = '
            SELECT cc.category_parent_id, cc.category_child_id
            FROM #__virtuemart_category_categories cc
        ';
        $db->setQuery($query);
        $relations_table = $db->loadObjectList();
        return $relations_table;
    }
   
    public function find_children($parent_id = 0)
    {
        return isset($this->tree[$parent_id])? $this->tree[$parent_id] : false;
    }
}
Работать должно примерно так:
Код
$tree = new Tree();
$rootChildren = $tree->find_children();
$chldren3 = $tree->find_children(3);
$children8 = $tree->find_children(8);
print_r($rootChildren);
print_r($chldren3);
print_r($children8);

@sivers, а Ваш способ работает побыстрее!
С теми же исходными данными строит дерево за 0,001-0,002 сек. Разница ощутимая.

Единственное - сортировка (порядок подкатегорий на сайте) так не учитывается. Но это и не критично.
Мне, например, такой класс нужен в основном, чтобы получать все подкатегории для каждой нужной категории - просто список, без учёта сортировки.
Зато в скорости огромный выигрыш.

Я дополнял свой класс ещё методами для получения списка подкатегорий для нужной категории
и списка всех категорий. Для удобства.

Сейчас модифицирую на основе предложенного Вами варианта. Выложу итог.
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Единственное - сортировка (порядок подкатегорий на сайте) так не учитывается. Но это и не критично.
Да, обычно нужны только ИДы, чтоб по ним построить запрос товаров. Но если кому важен порядок, то достаточно будет вернуть связывание таблиц в запросе.
Я дополнял свой класс ещё методами для получения списка подкатегорий для нужной категории
Т.е. плоский список ИДов всех дочек произвольной ветки? Его тоже с помощью рекурсии получаете? Или как-то еще? Поделитесь - интересно. Наверное, рекурсия для этого - самый оптимальный вариант. Но есть и более простой (в плане кода, а не оптимизации) для ленивых - через print_r и регулярное выражение.
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Т.е. плоский список ИДов всех дочек произвольной ветки? Его тоже с помощью рекурсии получаете? Или как-то еще?
Получал с помощью рекурсии, да.
Но вот тут задумался, может можно как-то без неё )

Хотелось бы иметь именно максимально оптимальный способ в плане ресурсозатрат (быстродействие, нагрузка на сервер).

Цитировать
Или как-то еще? Поделитесь - интересно.

Был такой вариант (методы get_subcats и list_all):
Код
class Tree
{
    public $id = 0;
    public $children = array();
    public $table = array();
   
    function __construct($cat_id = 0, $table = array())
    {
        $this->id = $cat_id;
        if (empty($table)) $this->table = $this->getTable();
        else $this->table = $table;
        $this->children = $this->find_children($cat_id, $this->table);
    }
   
    private function getTable()
    {
        // irprint('Запрос к БД');
        $db = JFactory::getDbo();
        $query = '
            SELECT cc.category_parent_id, cc.category_child_id, c.ordering
            FROM #__virtuemart_category_categories cc
            LEFT JOIN #__virtuemart_categories c ON c.virtuemart_category_id = cc.category_child_id
            ORDER BY category_parent_id, ordering, category_child_id
        ';
        $db->setQuery($query);
        return $db->loadObjectList();
    }
   
    public function find_children($parent_id = 0, $table)
    {
        $children = [];
        foreach ($table as $item) {
            if ($item->category_parent_id == $parent_id) {
                $tree = new Tree($item->category_child_id, $table);
                $children[] = $tree;
            }
        }
        return $children;
    }
   
    private function get_children_recursive($branch)
    {
        $children = [];
        if (!empty($branch->children)) {
            foreach ($branch->children as $child) {
                $children[] = $child->id;
                $sub_children = $this->get_children_recursive($child);
                $children = array_merge($children, $sub_children);
            }
        }
        return $children;
    }
   
    public function get_subcats($cat_id = null)
    {
        $subcats = [];
        if ($cat_id === null) {
            $subcats[] = $this->id;
            $branch = $this;
        } else {
            $subcats[] = $cat_id;
            $branch = new Tree($cat_id, $this->table);
        }
        $children = $this->get_children_recursive($branch);
        foreach ($children as $child) {
            $subcats[] = $child;
        }
        return $subcats;
    }
   
    public function list_all()
    {
        $list = [];
        foreach ($this->table as $row) {
            $list[] = $row->category_child_id;
        }
        sort($list);
        return $list;
    }
}
Сейчас подумываю над тем, как это лучше сделать для класса, предложенного Вами.
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Но вот тут задумался, может можно как-то без неё )

Сравните по расходу памяти/времени с одинаковыми исходными данными метод рекурсии и вот этот, что ниже:
Код
// Произвольный древовидный массив
$tree = array();
$tree[1][5] = 1;
$tree[2][6] = 1;
$tree[2][7] = 1;
$tree[2][8][13][15] = 1;
$tree[2][9][14] = 1;
$tree[3][10] = 1;
$tree[4][11] = 1;
$tree[4][12] = 1;

// Получение плоского списка ветки 2
$list = array();
if(preg_match_all('|\[(\d+)\]|isU', print_r($tree[2], true), $pregs)) $list = $pregs[1];
print_r($list);
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Сравните по расходу памяти/времени с одинаковыми исходными данными

Попробую, спасибо!

Пока сделал без рекурсии ) такой вариант:
Код
$start = microtime(true);
// VARIANT 2
class Tree
{
    public $tree = array();
    public $subs = array();
   
    function __construct($table = array())
    {
        if (empty($tree)) {
            if (empty($table)) $table = $this->getTable();
            foreach ($table as $item) {
                if (!isset($this->tree[$item->category_parent_id])) $this->tree[$item->category_parent_id] = array();
                if (!isset($this->tree[$item->category_child_id])) $this->tree[$item->category_child_id] = array();
                $this->tree[$item->category_parent_id][$item->category_child_id] = & $this->tree[$item->category_child_id];
                if (!isset($this->subs[$item->category_parent_id])) $this->subs[$item->category_parent_id] = array();
                if (!isset($this->subs[$item->category_child_id])) $this->subs[$item->category_child_id] = array(); // added later
                $this->subs[$item->category_parent_id][] = $item->category_child_id;
            }
            foreach ($this->subs as $k => $v) {
                foreach ($this->subs as $i => $arr) {
                    if (in_array($k, $arr)) {
                        $this->subs[$i] = array_merge($this->subs[$i], $this->subs[$k]);
                    }
                }
            }
        }
    }
   
    private function getTable()
    {
        $db = JFactory::getDbo();
        $query = 'SELECT category_parent_id, category_child_id FROM #__virtuemart_category_categories';
        $db->setQuery($query);
        return $db->loadObjectList();
    }
   
    public function find_children($parent_id = 0)
    {
        return isset($this->tree[$parent_id])? $this->tree[$parent_id] : false;
    }
   
    public function get_subcats($cat_id = 0, $with_it = true)
    {
        $subcats = $this->subs[$cat_id];
        if ($with_it) array_unshift($subcats, $cat_id);
        return $subcats;
    }
}

$tree = new Tree();
$sucats_for_265 = $tree->get_subcats(265);

$end = microtime(true);
$time = round($end - $start, 4);
irprint('Скрипт выполнен за '.$time.' сек.');

irprint($sucats_for_265);
0.0025 сек.
UPD: Когда добавил строчку, пропущенную изначально
Код
if (!isset($this->subs[$item->category_child_id])) $this->subs[$item->category_child_id] = array(); // added later
время выполнения существенно увеличилось, 0.0215 сек., многовато..
« Последнее редактирование: 05.08.2020, 14:06:28 от rsn »
Возможно, будет интересно: Интеграция с Ozon
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Рассчитываю на то, что методом получения списков подкатегорий буду пользоваться в переборе.
Поэтому один раз в классе заполняю подкатегории для всех категорий.
Возможно, это было бы лишним, если бы нужно было получить подкатегории только 1 раз.
Но для получения в переборе (когда надо получать все подкатегории для ряда категорий) - это как раз самое то, на мой взгляд.
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Рассчитываю на то, что методом получения списков подкатегорий буду пользоваться в переборе.
Поэтому один раз в классе заполняю подкатегории для всех категорий.
Возможно, это было бы лишним, если бы нужно было получить подкатегории только 1 раз.
Но для получения в переборе (когда надо получать все подкатегории для ряда категорий) - это как раз самое то, на мой взгляд.

В методе со ссылками аналогично. Да и как иначе в один запрос построить ветку без постройки всего дерева? Разве что с использованием lft/rgt (оно как раз для этого в
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

Septdir

  • Живу я здесь
  • 3370
  • 168 / 4
Разве что с использованием lft/rgt
NestedSet или же Вложенное множество называется.
И собственно да именно для этого.

Пример результата:
Насчет этого, каждый волен делать как ему нравиться, однако такой вариант вот первых тяжелый, во вторых не практичный.
Тяжелый потому что это объект с массивом в котором объект с массивом и т.д
Не практичный потому что выводить из этого обеъкета можно только рекурсией.

Для построения любого древа достаточно "однородного" ассоциативного массива.
childer => array (
[1] => array(2,3,4,5)
[4] => array(6,7,8)
)
При такой массиве я могу построить любое древо от любого ключа родителя.
Не можете справиться с задачей сами пишите, решу ее за вас, не бесплатно*.
*Интересная задача, Деньги или Бартер. Натурой не беру!
CodersRank | Контакты | Мой GitHub | Workshop
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
NestedSet или же Вложенное множество называется.
Думал перейти на эту модель. Чтобы заполнять таблицу в соответствии с ней, как раз и возникла мысль сделать обсуждаемый класс.
Но потом передумал )
Зачем Nested Sets, если и класс сам по себе с задачей получения всех подкатегорий для нужных категорий справляется вполне неплохо? )

Цитировать
При такой массиве я могу построить любое древо от любого ключа родителя.
Предлагаете какое-то решение получше, чем осуждаемые выше?
(когда в исходных данных таблица вида id_родителя-id_дочернего)
Возможно, будет интересно: Интеграция с Ozon
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Сравните по расходу памяти/времени с одинаковыми исходными данными метод рекурсии и вот этот, что ниже:
Код
// Произвольный древовидный массив
...
// Получение плоского списка ветки 2
$list = array();
if(preg_match_all('|\[(\d+)\]|isU', print_r($tree[2], true), $pregs)) $list = $pregs[1];
print_r($list);

Наконец-таки добрался до этих тестирований, к тому же и ситуация к располагает!
Выпала "уникальная" возможность поработать с сайтом, где ~75 000 записей в таблице категорий )))
Но для нужного инфоблока - 37 295 категорий, что тоже отнюдь не мало )
CMS другая, но тут это не так важно.

Во-первых, стоит сказать, что мой изначальный вариант класса, который ранее был представлен в начале темы, провалился. Вообще никак не вписался в ограничение памяти 512 МБ.
Вариант, предложенный sivers, с построением дерева со ссылками - супер! На нём и остановился.
Обновил кода класса в первом сообщении темы.

Далее потестировал получение плоского списка id всех вложенных категорий методами рекурсии и регулярки.
Для рекурсии были такие парочка методов, если что:
Спойлер
[свернуть]

РЕЗУЛЬТАТЫ СРАВНЕНИЯ
Код
ОБЪЕМ ДАННЫХ: 37295 записей в выборке из таблицы категорий.
Через РЕКУРСИЮ: время - 4,355 сек., пик памяти - 56,3 МБ.
Через РЕГУЛЯРКУ: время - 0,120 сек., пик памяти - 49,1 МБ.
Регулярка однозначно побеждает!
0,12 сек. для такой задачи! Блеск!  ^-^

Оставил к классе только этот метод.
А также дополнил для удобства методом получения плоского списка - в строке, с возможностью включения id родительской категории в результат.

@sivers, спасибо за советы!
« Последнее редактирование: 03.10.2020, 18:32:36 от rsn »
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Всегда пожалуйста! )
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Переименовал класс из первого варианта Tree в JFTree, т.к. класс с названием Tree уже используется в Joomla (в функционале меню).
JFTree - в честь нашего форума )
Сокращение от Joomla Forum Tree  ^-^
Возможно, будет интересно: Интеграция с Ozon
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
Хочу дополнить класс обратным методом - выводом списка родителей для нужной категории.
Рекурсия уже как-то неинтересна  ^-^
(из соображений производительности, конечно)
Уже соорудил решение на основе того же print_r и регулярки:

Код
$tree_str = print_r($cat_tree, true);
$str_arr = explode(PHP_EOL, $tree_str);

$result = [];
$set = [0];
$do_level = '';
foreach ($str_arr as $str) {
   
    if (trim($str) == '(') {
        // начало нового массива, вложенный уровень
        $do_level = 'new';
    } elseif (trim($str) == ')') {
        // возврат на уровень назад
        if ($do_level == 'new') { // предыдущий do_level - new, и тут же закрывается
            $do_level = '';
        } else {
            $do_level = 'prev';
        }
    } else {
        // в строке не скобки
        if (preg_match('|\[(\d+)\]|isU', $str, $match)) {
            // содержит ключ с id
            $value = $match[1];
            if ($do_level == 'new') {
                $set[] = $value;
            }
            elseif ($do_level == 'prev') {
                $del = array_splice($set, -2, 2);
                $set[] = $value;
            }
            else {
                $del = array_splice($set, -1, 1);
                $set[] = $value;
            }
            $result[$value] = $set;
            $do_level = '';
        }
    }
}

print_r($result);

Это ещё не метод, а просто пробы - способ построения.
На выходе в виде:

Код
Array
(
    [265] => Array
        (
            [0] => 0
            [1] => 265
        )

    [566] => Array
        (
            [0] => 0
            [1] => 265
            [2] => 566
        )

    [650] => Array
        (
            [0] => 0
            [1] => 265
            [2] => 566
            [3] => 650
        )

    [282] => Array
        (
            [0] => 0
            [1] => 265
            [2] => 566
            [3] => 650
            [4] => 282
        )

    [295] => Array
        (
            [0] => 0
            [1] => 265
            [2] => 566
            [3] => 650
            [4] => 295
    ...

То есть для любой подкатегории по её id можем получить список родительских.
Вместе с запросом и построением дерева (этим классом) отрабатывает ~ 500 категорий в целом за 0.0061 сек.

Как думаете, могут быть способы более быстрые? Или вряд ли?
Возможно, будет интересно: Интеграция с Ozon
*

sivers

  • Живу я здесь
  • 2453
  • 333 / 0
Как думаете, могут быть способы более быстрые? Или вряд ли?
Они есть )

Один из более эффективных методов полностью аналогичен поиску дочерних элементов. В конструкторе, когда строите ссылочное дерево $this->tree, одновременно можно построить обратное дерево, в котором направление идет не от предка к потомку, а от потомка к предку. И тогда при получении списка предков вообще не нужны будут циклы - получите все через 1 print_r и регулярку.
« Последнее редактирование: 05.10.2020, 19:55:26 от sivers »
На связи в telegram @sivers
sivers @ inbox . ru
https://sivers.su/
*

rsn

  • Давно я тут
  • 520
  • 34 / 3
В конструкторе, когда строите ссылочное дерево $this->tree, одновременно можно построить обратное дерево, в котором направление идет не от предка к потомку, а от потомка к предку

Точно
Возможно, будет интересно: Интеграция с Ozon
Чтобы оставить сообщение,
Вам необходимо Войти или Зарегистрироваться