Новости Joomla

Вышли релизы Joomla 6.1 и Joomla 5.4.5: новые возможности и стабильность

Релиз Joomla 6.1.0

Проект Joomla! объявил о доступности Joomla 6.1 [Nyota] — новой минорной версии шестой серии, а также о выпуске релиза исправлений ошибок Joomla 5.4.5. Релиз 6.1 приносит ряд долгожданных функций, повышающих удобство управления контентом и защиту от спама.

👩‍💻 Компонент "CS Афиши" для Joomla.

👩‍💻 Компонент "CS Афиши" для Joomla.

Расширение "CS Афиши" позволяет выводить список мероприятий, фильтровать их по датам, поиск по заголовкам и описанию.

В состав пакета расширений входят:
- Компонент "CS Афиши"
- Модуль "Календарь событий"
- Модуль "Предстоящие события"
- Библиотека "ImgResize"

Расширение "CS Афиши" позволяет выводить список мероприятий, фильтровать их по датам, поиск по заголовкам и описанию.

Модуль "Календарь событий" отображает предстоящие и прошедшие мероприятие на календаре, с отображением мероприятий на конкретную дату во всплывающем окне.

Модуль "Предстоящие события" показывает список предстоящий событий по порядку их наступления.

P.S. Расширение платное, но плата символическая, чисто для отработки приема платежей. Ключи без ограничения по времени, купившие сейчас - смогут обновляться без ограничений.

Разработчик - участник нашего сообщества Дмитрий Денисов (@codersite).

Страница расширения
Демо

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

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

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

rsn

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

rsn

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

sivers

  • Живу я здесь
  • 2610
  • 363 / 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

  • Живу я здесь
  • 2610
  • 363 / 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

  • Живу я здесь
  • 2610
  • 363 / 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

  • Живу я здесь
  • 2610
  • 363 / 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

  • Живу я здесь
  • 2610
  • 363 / 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

  • Живу я здесь
  • 2610
  • 363 / 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
Чтобы оставить сообщение,
Вам необходимо Войти или Зарегистрироваться