Bitrix формирование урлов многоуровневых разделов

Сайты каталоги в основном имеют структуру многоуровневых разделов. При тестировании могут потребоваться урлы этих разделов. Рекурсивное формирование ссылок и экспорт их в csv будет рассмотрен в этой статье.

329 zamorozhennie-ovoshi/green-goroh Замороженные овощи/Зеленый горошек «Premiko»
330 conserves/cucumber Консервированные овощи/Огурцы
331 v-steklannih-bankah/grib Овощи в стеклянных банках/Грибы
332 v-steklannih-bankah/tomatos Овощи в стеклянных банках/Помидоры
333 zamorozhennie-ovoshi/brokkoli Замороженные овощи/Брокколи
334 conserves/tomate Консервированные овощи/Банка томатов

Скрипт я написал в ООП стиле
Допустим у нас есть массив разделов где присутствует некий текст, напр. кнопка «Купить».


$strSql = "SELECT * FROM b_iblock_section WHERE DESCRIPTION LIKE '%>Купить<%'";

Выполнение данного запроса вернет массив разделов. Нас интересует полный путь до данного раздела.


$res = $DB->Query($strSql, false);
            if ($res->result->num_rows == false) {
                return;
            }
            while ($row = $res->Fetch()) {
              // CODE  - для формирования УРЛ
                $this->sectns['url'][$row['ID']][$row['CODE']] = $this->getSect($row['IBLOCK_SECTION_ID'], 'CODE');
             // NAME - для "хлебных крошек"
                $this->sectns['nav'][$row['ID']][$row['NAME']] = $this->getSect($row['IBLOCK_SECTION_ID'], 'NAME');
            }

Далее нам нужна функция к-я рекурсивно выдает урлы


    protected function getSect($id, $param)
    {
        $sect = array();
        $res = CIBlockSection::GetByID($id);
        if ($ar_res = $res->GetNext()) {
            if ($ar_res['IBLOCK_SECTION_ID'] != null) {
                $sect[$ar_res[$param]] = $this->getSect($ar_res['IBLOCK_SECTION_ID'], $param);
            } else {
                $sect[$ar_res[$param]] = '';
            }
        }
        return $sect;
    }

В итоге мы получили многомерный массив с урлами и хлеб. крошками. Они записаны в $this->sectns[‘url’] и $this->sectns[‘nav’].
Чтобы привести массивы в нужный вид их надо «сплющить», то бишь сделать одноуровневым и перевернуть. Для этого есть спец. метод. array_1_level()


    /**
     * @param $multiarr
     * @return array
     */
    protected function array_1_level($multiarr)
    {
        $arr2 = [];
        foreach ($multiarr as $key => $marr) {
            while ($marr != '') {
                foreach ($marr as $k => $v) {
                    $arr2[$key][] = $k;
                }
                $marr = array_shift($marr);
            }
            $arr2[$key] = implode('/', array_reverse($arr2[$key]));
        }
        return $arr2;
    }

Массивы готовы, давайте запишем их в csv файл. Как вы знаете массив пишется в csv построчно, и чтобы url и навигация были в одну строку — объединим их. Для этого пробежимся по массиву функцией concatenate_url_nav();


    /**
     * @param $item
     * @param $key
     */
    protected function concatenate_url_nav($item, $key)
    {
        if (isset($this->sectns_nav[$key])) {
            $this->sectns_2[$key][] = $key;
            $this->sectns_2[$key][] = $item;
            $this->sectns_2[$key][] = $this->sectns_nav[$key];
        }
    }


    /**
     *
     */
    protected function WriteToCSV()
    {
        // преобразую многомерный массив в одномерный, значения массива объединяю В урл
        $this->sectns_url = $this->array_1_level($this->sectns['url']);
        $this->sectns_nav = $this->array_1_level($this->sectns['nav']);
        // убираю дубли
        array_unique($this->sectns_url, SORT_REGULAR);
        // объединяю 2 массива в 1 строку для csv
        array_walk($this->sectns_url, array($this, 'concatenate_url_nav'));
        // заголовок для csv
        if($this->csv_header != ''){
            array_unshift($this->sectns_2, array($this->csv_header));
        }
        $path = dirname(__FILE__) . "/" . $this->csv_file;
        $f1 = fopen($path, $this->mode);
        foreach ($this->sectns_2 as $key => $value) {
          fputcsv($f1, $value);
        }
        fclose($f1);
    }

После объединения массива добавляю заголовок, и записываю в режиме «w» или «a» в зависимости от параметра.
Здесь полный скрипт. В нем в конструкторе идет проверка на sql запрос или ID элемента. Соответственно элементы, для которых мы формируем url и навигацию — из таблицы b_iblock_element и b_iblock_section.



require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_before.php");

CModule::IncludeModule("iblock");
error_reporting(E_ERROR | E_WARNING | E_PARSE);


class LogURL
{
    protected $sectns = array();
    protected $sectns_2 = [];
    protected $sectns_url;
    protected $sectns_nav;
    protected $csv_header;
    protected $csv_file;
    protected $mode;
    /**
     * @param $id
     * @param $param
     * @return array
     */
    protected function getSect($id, $param)
    {
        $sect = array();
        $res = CIBlockSection::GetByID($id);
        if ($ar_res = $res->GetNext()) {
            if ($ar_res['IBLOCK_SECTION_ID'] != null) {
                $sect[$ar_res[$param]] = $this->getSect($ar_res['IBLOCK_SECTION_ID'], $param);
            } else {
                $sect[$ar_res[$param]] = '';
            }
        }
        return $sect;
    }

    /**
     * LogURL constructor.
     * @param $sql
     */
    public function __construct($strSql = '', $csv_header = "", $csv_file = "links.csv"){
        global $DB;
        $this->csv_header = $csv_header;
        $this->csv_file = $csv_file;
        // если передано sql выражение
        if(stripos($strSql, "SELECT") !== false) {
            // обязательные поля  ID, NAME, CODE, IBLOCK_SECTION_ID
            $res = $DB->Query($strSql, false);
            if ($res->result->num_rows == false) {
                return;
            }
            while ($row = $res->Fetch()) {
                $this->sectns['url'][$row['ID']][$row['CODE']] = $this->getSect($row['IBLOCK_SECTION_ID'], 'CODE');
                $this->sectns['nav'][$row['ID']][$row['NAME']] = $this->getSect($row['IBLOCK_SECTION_ID'], 'NAME');
            }
            $this->mode = 'w';
        }// если передан ID элемента
        else if(is_numeric($strSql)){
            $res = CIBlockElement::GetByID($strSql);
            if ($res->result->num_rows == false) {
                return;
            }
            if($row = $res->GetNext()){
                $this->sectns['url'][$row['ID']][$row['CODE']] = $this->getSect($row['IBLOCK_SECTION_ID'], 'CODE');
                $this->sectns['nav'][$row['ID']][$row['NAME']] = $this->getSect($row['IBLOCK_SECTION_ID'], 'NAME');
            }
            $this->mode = 'a';
        }
        $this->WriteToCSV();
    }

    /**
     * @param $multiarr
     * @return array
     */
    protected function array_1_level($multiarr)
    {
        $arr2 = [];
        foreach ($multiarr as $key => $marr) {
            while ($marr != '') {
                foreach ($marr as $k => $v) {
                    $arr2[$key][] = $k;
                }
                $marr = array_shift($marr);
            }
            $arr2[$key] = implode('/', array_reverse($arr2[$key]));
        }
        return $arr2;
    }

    /**
     * @param $item
     * @param $key
     */
    protected function concatenate_url_nav($item, $key)
    {
        if (isset($this->sectns_nav[$key])) {
            $this->sectns_2[$key][] = $key;
            $this->sectns_2[$key][] = $item;
            $this->sectns_2[$key][] = $this->sectns_nav[$key];
        }
    }

    /**
     *
     */
    protected function WriteToCSV()
    {
        // преобразую многомерный массив в одномерный, значения массива объединяю В урл
        $this->sectns_url = $this->array_1_level($this->sectns['url']);
        $this->sectns_nav = $this->array_1_level($this->sectns['nav']);
        // убираю дубли
        array_unique($this->sectns_url, SORT_REGULAR);
        // объединяю 2 массива в 1 строку для csv
        array_walk($this->sectns_url, array($this, 'concatenate_url_nav'));
        // заголовок для csv
        if($this->csv_header != ''){
            array_unshift($this->sectns_2, array($this->csv_header));
        }
        $path = dirname(__FILE__) . "/" . $this->csv_file;
        $f1 = fopen($path, $this->mode);
        foreach ($this->sectns_2 as $key => $value) {
          fputcsv($f1, $value);
        }
        fclose($f1);
    }
}
?>

Скачать LogURL.php.zip

2 Comments

  1. можно гораздо проще и более правильно с использованием АПИ
    CModule::IncludeModule(‘iblock’);
    $arFilter = array(‘IBLOCK_ID’ => 7, ‘ACTIVE’ => ‘Y’);
    $arSelect = array(‘ID’,’NAME’,’SECTION_PAGE_URL’);
    $rsSection = CIBlockSection::GetTreeList($arFilter, $arSelect);
    while($arSection = $rsSection->GetNext()) {
    $arRow = array(
    $arSection[‘ID’],
    $arSection[‘NAME’],
    $arSection[‘SECTION_PAGE_URL’]
    );
    }

    • Александр, да, этот пример решает задачу. Метод GetTreeList я узнал позже. Моя задача была привести этот многомерный массив в csv вид для тестировщика.

Leave a comment

Your email address will not be published.


*