Файл admin.structure.php в Cotonti CMF

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

Основное назначение файла "admin.structure.php" и его место в системе

Файл admin.structure.php предназначен для управления структурой (категориями) в системе Cotonti CMF. Он реализует интерфейс администратора для добавления, изменения, удаления и настройки категорий, используемых в модулях или плагинах. Это ключевая часть административной панели для управления иерархией категорий, включая их дополнительные поля, права доступа, шаблоны и настройки.

Место в системе:

  • Входит в административный модуль.
  • Используется для работы с таблицей cot_structure в базе данных.
  • Обеспечивает динамическую генерацию интерфейса на основе данных, хранящихся в структуре.

Основные задачи и условия, выполняемые в коде

  1. Отображение текущей структуры категорий:

    • Подгрузка категорий из базы данных.
    • Визуализация их иерархии (уровень вложенности, пути).
  2. Добавление новых категорий:

    • Обработка формы для создания новой категории.
    • Указание пути, заголовка, описания, значков и других параметров.
  3. Редактирование существующих категорий:

    • Обработка входных данных для обновления информации о категории (код, название, описание и т.д.).
    • Настройка шаблонов для категорий (включая выбор дочерних шаблонов).
  4. Удаление категорий:

    • Проверка возможности удаления категории (например, отсутствие вложенных объектов).
    • Удаление категории из базы данных.
  5. Работа с дополнительными полями (extra fields):

    • Поддержка произвольных полей, созданных администраторами через API Cotonti.
  6. Взаимодействие с правами доступа:

    • Генерация ссылок для настройки прав доступа для каждой категории.
  7. Реализация пагинации:

    • Поддержка навигации при большом количестве категорий.
  8. Обработка AJAX-запросов:

    • Удаление и обновление категорий с использованием AJAX.

Список функций, используемых в файле

1. cot_url()

Назначение: Генерирует URL для административного интерфейса.
Что делает:

  • Собирает параметры в GET-запрос.
  • Возвращает корректный путь на основе роутера Cotonti.

2. cot_import()

Назначение: Импортирует данные из внешнего источника (GET, POST, COOKIE).
Что делает:

  • Проверяет входные данные на корректность (строки, числа и т.д.).
  • Возвращает значение или null, если данные отсутствуют.

3. cot_check_xg()

Назначение: Проверяет CSRF-токен.
Что делает:

  • Защищает от межсайтовых запросов с поддельными токенами.
  • Возвращает true, если токен валиден.

4. cot_confirm_url()

Назначение: Создает ссылку с подтверждением действия.
Что делает:

  • Генерирует URL, включающий уникальный ключ защиты (CSRF).

5. cot_selectbox()

Назначение: Создает HTML-элемент <select> с опциями.
Что делает:

  • Принимает массивы значений и отображаемых текстов.
  • Возвращает HTML-код выпадающего списка.

6. cot_checkbox()

Назначение: Создает HTML-элемент <input type="checkbox">.
Что делает:

  • Возвращает чекбокс с заданными атрибутами.

7. cot_inputbox()

Назначение: Генерирует HTML-элемент <input> для текстовых полей.
Что делает:

  • Поддерживает указание атрибутов (maxlength, placeholder и т.д.).

8. cot_build_extrafields()

Назначение: Генерирует HTML-элемент для работы с дополнительными полями (extra fields).
Что делает:

  • Определяет тип поля (текст, дата, файл).
  • Возвращает HTML-код для вывода в шаблоне.

9. cot_structure_children()

Назначение: Возвращает массив дочерних элементов категории.
Что делает:

  • Определяет вложенные категории.
  • Может возвращать только непосредственных детей или всех потомков.

10. cot_display_messages()

Назначение: Отображает уведомления для пользователя.
Что делает:

  • Обрабатывает сообщения, добавленные через cot_message().
  • Генерирует HTML-код уведомлений.

Список методов и их назначение

Методов, как таковых, в данном файле нет. Используются функции процедурного стиля.


Взаимодействие с классами

  1. Cot::$db

    • Как взаимодействует: Обеспечивает доступ к объекту базы данных.
    • Используется для: Выполнения SQL-запросов (SELECT, INSERT, UPDATE, DELETE).
  2. Cot::$cfg

    • Как взаимодействует: Содержит глобальные настройки системы.
    • Используется для: Проверки конфигурации (например, активация режима совместимости).
  3. Cot::$L

    • Как взаимодействует: Локализация интерфейса.
    • Используется для: Вывода строк с текстами из языкового файла.
  4. Cot::$sys

    • Как взаимодействует: Доступ к системным параметрам (время, CSRF-токен и т.д.).
    • Используется для: Вставки ключей защиты в формы и ссылки.

Взаимодействие с объектами

  1. Объект базы данных (Cot::$db)

    • Выполняются запросы на выборку, обновление и удаление данных.
  2. Шаблонизатор ($t)

    • Как взаимодействует: Передает данные из PHP-кода в шаблон.
    • Используется для: Генерации HTML на основе заданного шаблона.
  3. Сессия ($_SESSION)

    • Как взаимодействует: Используется для хранения временных данных (например, буфера изменений).
  4. Объект структуры ($row)

    • Представляет собой запись в таблице структуры.
    • Используется для обработки данных о категориях.

Стиль PHP-кода

Код написан в процедурном стиле, характерном для более ранних версий PHP. Однако используются современные элементы:

  • Глобальные классы (Cot::$db, Cot::$cfg).
  • Псевдоним пространства имен (Cot::$).
  • Четкое разделение логики на секции с использованием хуков.

Особенности стиля:

  • Логика сосредоточена в основном в одном файле.
  • Используются глобальные переменные и функции.
  • Минимальное использование ООП.

 

находится по адресу: /system/admin/admin.structure.php движка php-фреймворка Cotonti.

 

<?php
/**
 * Панель администратора
 *
 * @package Cotonti
 * @copyright (c) Cotonti Team
 * @license https://github.com/Cotonti/Cotonti/blob/master/License.txt
 *
 * @var string $n Код расширения
 */
(defined('COT_CODE') && defined('COT_ADMIN')) or die('Wrong URL.'); // Проверка, что скрипт вызывается в правильном контексте (COT_CODE и COT_ADMIN должны быть определены)

list(Cot::$usr['auth_read'], Cot::$usr['auth_write'], Cot::$usr['isadmin']) = cot_auth('admin', 'a'); // Получение прав доступа пользователя (чтение, запись, админ) для раздела 'admin'
cot_block(Cot::$usr['isadmin']); // Блокирует доступ, если у пользователя нет прав администратора

require_once cot_incfile('extrafields'); // Подключение файла с дополнительными полями
require_once cot_incfile('structure'); // Подключение файла с функциональностью для структуры

$id = cot_import('id', 'G', 'INT'); // Получение параметра 'id' из GET-запроса, ожидается целое число
$al = cot_import('al', 'G', 'ALP'); // Получение параметра 'al' из GET-запроса, ожидается строка (буквы)
$c = cot_import('c', 'G', 'TXT'); // Получение параметра 'c' из GET-запроса, ожидается текст
$v = cot_import('v', 'G', 'TXT'); // Получение параметра 'v' из GET-запроса, ожидается текст

$maxrowsperpage = (is_int(Cot::$cfg['maxrowsperpage']) && Cot::$cfg['maxrowsperpage'] > 0 || ctype_digit(Cot::$cfg['maxrowsperpage'])) ? // Проверка корректности настройки максимального количества строк на странице
    Cot::$cfg['maxrowsperpage'] : 15; // Если настройка корректна, используется её значение, иначе по умолчанию 15

list($pg, $d, $durl) = cot_import_pagenav('d', $maxrowsperpage); // Получение параметров для пагинации: текущая страница, количество элементов на странице и ссылка для пагинации
$mode = cot_import('mode', 'G', 'ALP'); // Получение параметра 'mode' из GET-запроса, ожидается строка (буквы)

 

$t = new XTemplate(cot_tplfile(array('admin', 'structure', $n), 'core')); // Создание нового объекта XTemplate для загрузки шаблона, с учетом параметра $n (код расширения)

$adminTitle = Cot::$L['Structure']; // Установка заголовка для админки "Структура" из локализованных данных

$extensionsWithStructure = cot_getExtensionsWithStructure(); // Получение списка расширений, которые имеют структуру

$legacyMode = isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']; // Проверка, включен ли режим совместимости (legacyMode) в конфигурации
if ($legacyMode) { // Если режим совместимости включен
    $extension_structure = []; // Инициализация пустого массива для структуры расширений в старом режиме
}

/* === Hook === */
foreach (cot_getextplugins('admin.structure.first') as $pl) { // Перебор всех плагинов для хука 'admin.structure.first'
    include $pl; // Включение каждого плагина
}
/* ===== */

if ($legacyMode && !empty($extension_structure)) { // Если режим совместимости активен и структура расширений не пуста
    $extensionsWithStructure = array_merge($extensionsWithStructure, $extension_structure); // Слияние структур расширений с основной структурой
    unset($extension_structure); // Удаление временной переменной $extension_structure
}

 

if (empty($n)) { // Если параметр $n пустой (не указан код расширения)
	$adminPath[] = [cot_url('admin', 'm=structure'), Cot::$L['Structure'],]; // Добавление пути в навигацию "Структура"
	// Show available module list
	if (
        is_array($extensionsWithStructure) // Проверка, является ли $extensionsWithStructure массивом
        && count($extensionsWithStructure) == 1 // Если в массиве только один элемент
        && ((cot_plugin_active($extensionsWithStructure[0]) || cot_module_active($extensionsWithStructure[0]))) // Если это активное расширение или модуль
    ) {
		cot_redirect(cot_url('admin', 'm=structure&n='.$extensionsWithStructure[0], '', true)); // Перенаправление на страницу этого расширения или модуля
	}

	if (is_array($extensionsWithStructure) && count($extensionsWithStructure) > 0) { // Если $extensionsWithStructure массив и в нем больше одного элемента
		foreach ($extensionsWithStructure as $code) { // Перебор всех расширений с структурой
			$parse = false; // Флаг для определения, нужно ли парсить расширение
			if (cot_plugin_active($code)) { // Если плагин активен
				$is_module = false; // Это не модуль
				$parse = true; // Устанавливаем флаг на true для парсинга
			}
			if (cot_module_active($code)) { // Если модуль активен
				$is_module = true; // Это модуль
				$parse = true; // Устанавливаем флаг на true для парсинга
			}
			if ($parse) { // Если флаг парсинга установлен в true
				$ext_info = cot_get_extensionparams($code, $is_module); // Получаем параметры расширения
				$t->assign([
					'ADMIN_STRUCTURE_EXT_URL' => cot_url('admin', 'm=structure&n='.$code), // Установка URL для расширения
					'ADMIN_STRUCTURE_EXT_ICON' => $ext_info['icon'], // Установка иконки расширения
					'ADMIN_STRUCTURE_EXT_NAME' => $ext_info['name'], // Установка имени расширения
					'ADMIN_STRUCTURE_EXT_DESC' => $ext_info['desc'], // Установка описания расширения
				]);
                if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) { // Если включен режим совместимости
                    $t->assign([
                        // @deprecated For backward compatibility. Will be removed in future releases
                        'ADMIN_STRUCTURE_EXT_ICO' => $ext_info['legacyIcon'], // Установка старой иконки для совместимости
                    ]);
                }

				$t->parse('LIST.ADMIN_STRUCTURE_EXT'); // Парсинг расширения в шаблон
			}
		}
	}
	else
	{
		$t->parse('LIST.ADMIN_STRUCTURE_EMPTY'); // Если нет расширений, парсинг пустого списка
	}

	$t->assign(array(
		'ADMIN_STRUCTURE_EXFLDS_URL' => cot_url('admin', 'm=extrafields') // Установка URL для экстра-полей
	));
	$t->parse('LIST'); // Парсинг списка расширений
	$adminMain = $t->text('LIST'); // Получение и сохранение HTML-кода для основного контента
} else { // Если параметр $n не пустой (указан код расширения)

 

} else { // Если параметр $n не пустой (указан код расширения)
	$parse = false; // Флаг для определения необходимости парсинга

    if (!in_array($n, $extensionsWithStructure, true)) { // Если $n не найден в массиве расширений с структурой
        cot_die_message(404); // Завершаем выполнение с ошибкой 404 (не найдено)
    }

	if (cot_plugin_active($n)) { // Если плагин активен
		$is_module = false; // Это не модуль
		$parse = true; // Устанавливаем флаг парсинга
	}
	if (cot_module_active($n)) { // Если модуль активен
		$is_module = true; // Это модуль
		$parse = true; // Устанавливаем флаг парсинга
	}
	if (!$parse) { // Если флаг парсинга не установлен
		cot_redirect(cot_url('admin', 'm=structure', '', true)); // Перенаправляем на страницу структуры
	}

	// Edit structure for a module
	if (file_exists(cot_incfile($n, $is_module ? 'module' : 'plug'))) { // Если существует файл для модуля или плагина
		require_once cot_incfile($n, $is_module ? 'module' : 'plug'); // Подключаем файл модуля или плагина
	}

	if (empty($adminHelp)) { // Если переменная $adminHelp пуста
		$adminHelp = Cot::$L['adm_help_structure']; // Устанавливаем помощь по структуре
	}

	if ($a == 'reset' && !empty($al)) { // Если параметр $a равен 'reset' и $al не пустой
		cot_config_reset($n, $v, $is_module, $al); // Сброс конфигурации для расширения
	}

 

if ($a == 'update' && !empty($_POST)) { // Если параметр $a равен 'update' и запрос не пустой
    $editconfig = cot_import('editconfig', 'P', 'TXT'); // Импортируем параметр 'editconfig' из POST-запроса
    if (!empty($editconfig)) { // Если параметр 'editconfig' не пустой
        $owner = $is_module ? 'module' : 'plug'; // Определяем, является ли объект модулем или плагином
        $optionslist = cot_config_list($owner, $n, $editconfig); // Получаем список опций конфигурации для расширения
        foreach ($optionslist as $key => $val) { // Перебираем список опций
            $data = cot_import($key, 'P', !empty($cot_import_filters[$key]) ? $key : 'NOC'); // Импортируем значение конфигурации
            if ($optionslist[$key]['config_value'] != $data) { // Если новое значение отличается от текущего
                if (!isset($optionslist[$key]['config_subdefault'])) { // Если опция не имеет подкатегории по умолчанию
                    $optionslist[$key]['config_value'] = $data; // Обновляем значение опции
                    $optionslist[$key]['config_subcat'] = $editconfig; // Устанавливаем подкатегорию
                    Cot::$db->insert($db_config, $optionslist[$key]); // Вставляем новую опцию в базу данных
                } else { 
                    Cot::$db->update( // Если подкатегория уже установлена, обновляем запись в базе данных
                        $db_config,
                        array('config_value' => $data), // Обновляем только значение конфигурации
                        "config_name = ? AND config_owner = ? AND config_cat = ?  AND config_subcat = ?", // Условие поиска
                        array($key, $owner, $n, $editconfig) // Параметры для поиска
                    );
                }
            }
        }

        $dir = $owner == 'module' ? Cot::$cfg['modules_dir'] : Cot::$cfg['plugins_dir']; // Определяем директорию для модуля или плагина
        // Если существует файл конфигурации, запускаем его
        if (file_exists($dir . "/" .$n . "/setup/" .$n. ".configure.php")) { // Если файл конфигурации существует
            include $dir . "/" .$n . "/setup/" . $n . ".configure.php"; // Подключаем его
        }
    }
}

 

$rstructurecode = cot_import('rstructurecode', 'P', 'ARR'); // Импортируем параметр 'rstructurecode' как массив из POST-запроса
$rstructurepath = cot_import('rstructurepath', 'P', 'ARR'); // Импортируем параметр 'rstructurepath' как массив из POST-запроса
$rstructuretitle = cot_import('rstructuretitle', 'P', 'ARR'); // Импортируем параметр 'rstructuretitle' как массив из POST-запроса
$rstructuredesc = cot_import('rstructuredesc', 'P', 'ARR'); // Импортируем параметр 'rstructuredesc' как массив из POST-запроса
$rstructureicon = cot_import('rstructureicon', 'P', 'ARR'); // Импортируем параметр 'rstructureicon' как массив из POST-запроса
$rstructurelocked = cot_import('rstructurelocked', 'P', 'ARR'); // Импортируем параметр 'rstructurelocked' как массив из POST-запроса

// Если импортированные данные не пустые, оставляем их, иначе устанавливаем пустой массив
$rstructurecode = !empty($rstructurecode) ? $rstructurecode : []; // Если 'rstructurecode' не пустой, используем его, иначе устанавливаем пустой массив
$rstructurepath = !empty($rstructurepath) ? $rstructurepath : []; // Если 'rstructurepath' не пустой, используем его, иначе устанавливаем пустой массив
$rstructuretitle = !empty($rstructuretitle) ? $rstructuretitle : []; // Если 'rstructuretitle' не пустой, используем его, иначе устанавливаем пустой массив
$rstructuredesc = !empty($rstructuredesc) ? $rstructuredesc : []; // Если 'rstructuredesc' не пустой, используем его, иначе устанавливаем пустой массив
$rstructureicon = !empty($rstructureicon) ? $rstructureicon : []; // Если 'rstructureicon' не пустой, используем его, иначе устанавливаем пустой массив
$rstructurelocked  = !empty($rstructurelocked) ? $rstructurelocked : []; // Если 'rstructurelocked' не пустой, используем его, иначе устанавливаем пустой массив

$rtplmodearr = cot_import('rstructuretplmode', 'P', 'ARR'); // Импортируем параметр 'rstructuretplmode' как массив из POST-запроса
$rtplforcedarr = cot_import('rstructuretplforced', 'P', 'ARR'); // Импортируем параметр 'rstructuretplforced' как массив из POST-запроса
$rtplcodearr = cot_import('rstructuretplcode', 'P', 'ARR'); // Импортируем параметр 'rstructuretplcode' как массив из POST-запроса

// Если импортированные данные не пустые, оставляем их, иначе устанавливаем пустой массив
$rtplmodearr = !empty($rtplmodearr) ? $rtplmodearr : []; // Если 'rstructuretplmode' не пустой, используем его, иначе устанавливаем пустой массив
$rtplforcedarr = !empty($rtplforcedarr) ? $rtplforcedarr : []; // Если 'rstructuretplforced' не пустой, используем его, иначе устанавливаем пустой массив
$rtplcodearr = !empty($rtplcodearr) ? $rtplcodearr : []; // Если 'rstructuretplcode' не пустой, используем его, иначе устанавливаем пустой массив

 

/* === Hook === */
foreach (cot_getextplugins('admin.structure.update.first') as $pl) { // Выполняем хуки перед обновлением структуры, чтобы подключить дополнительные расширения
    include $pl; // Включаем расширение, если оно подключено
}
/* ===== */

foreach ($rstructurecode as $i => $k) { // Проходим по всем элементам массива $rstructurecode
    $oldrow = Cot::$db->query('SELECT * FROM ' . Cot::$db->structure . // Выполняем запрос к базе данных, чтобы получить старые данные структуры по её ID
        " WHERE structure_id=" . (int) $i)->fetch(); // Извлекаем строку данных структуры, идентифицированную через $i (ID)

    if (isset($rstructurecode[$i])) { // Проверяем, существует ли код структуры для данного элемента
        $rstructure['structure_code'] = preg_replace( // Очищаем значение кода структуры от нежелательных символов
            '#[^\w\p{L}\-]#u', // Регулярное выражение для удаления символов, кроме букв, цифр и дефиса
            '', // Заменяем все неподобающие символы на пустую строку
            cot_import($rstructurecode[$i], 'D', 'TXT') // Импортируем и обрабатываем код структуры из массива $rstructurecode
        );
    }

 

if (isset($rstructurepath[$i])) { // Проверяем, существует ли путь структуры для текущего элемента
    $rstructure['structure_path'] = cot_import($rstructurepath[$i], 'D', 'TXT'); // Импортируем путь структуры и присваиваем его переменной
}
if (isset($rstructuretitle[$i])) { // Проверяем, существует ли заголовок структуры для текущего элемента
    $rstructure['structure_title'] = cot_import($rstructuretitle[$i], 'D', 'TXT'); // Импортируем заголовок структуры и присваиваем его переменной
}
if (isset($rstructuredesc[$i])) { // Проверяем, существует ли описание структуры для текущего элемента
    $rstructure['structure_desc'] = cot_import($rstructuredesc[$i], 'D', 'TXT'); // Импортируем описание структуры и присваиваем его переменной
}
if (isset($rstructureicon[$i])) { // Проверяем, существует ли иконка структуры для текущего элемента
    $rstructure['structure_icon'] = cot_import($rstructureicon[$i], 'D', 'TXT'); // Импортируем иконку структуры и присваиваем её переменной
}
if (isset($rstructurelocked[$i]) && cot_import($rstructurelocked[$i], 'D', 'BOL') !== null) { // Проверяем, существует ли параметр блокировки структуры и его значение
    $rstructure['structure_locked'] = (cot_import($rstructurelocked[$i], 'D', 'BOL')) ? 1 : 0; // Импортируем и присваиваем значение блокировки структуры (1 - заблокировано, 0 - не заблокировано)
}

 

if (!empty(Cot::$extrafields[Cot::$db->structure])) { // Проверяем, есть ли дополнительные поля для структуры
    foreach (Cot::$extrafields[Cot::$db->structure] as $exfld) { // Перебираем все дополнительные поля для структуры
        $inputName = 'rstructure' . $exfld['field_name'] . '_' . $i; // Формируем имя поля ввода для текущего дополнительного поля
        // TODO Мы должны проверить, имеет ли дополнительное поле значение по умолчанию или оно обязательно для заполнения
        if (isset($_POST[$inputName])) { // Проверяем, передано ли значение для дополнительного поля
            $rstructure['structure_' . $exfld['field_name']] = cot_import_extrafields( // Импортируем значение дополнительного поля
                $inputName, // Имя поля ввода
                $exfld, // Сами данные поля
                'P', // Источник данных (POST)
                $oldrow['structure_' . $exfld['field_name']], // Старое значение поля из базы
                'structure_' // Префикс для имени поля в базе
            );
        }
    }
}

 

($rstructure['structure_code'] != 'all') || cot_error('adm_structure_code_reserved', 'rstructurecode'); // Проверяем, не является ли код структуры 'all', если да, то выводим ошибку "adm_structure_code_reserved"
$rstructure['structure_code'] || cot_error('adm_structure_code_required', 'rstructurecode'); // Если код структуры не пуст, иначе выводим ошибку "adm_structure_code_required"
$rstructure['structure_path'] || cot_error('adm_structure_path_required', 'rstructurepath'); // Если путь структуры не пуст, иначе выводим ошибку "adm_structure_path_required"
$rstructure['structure_title'] || cot_error('adm_structure_title_required', 'rstructuretitle'); // Если название структуры не пусто, иначе выводим ошибку "adm_structure_title_required"

$rtplmode = isset($rtplmodearr[$i]) ? cot_import($rtplmodearr[$i], 'D', 'INT') : 0; // Если для текущего элемента существует tplmode, то импортируем его как целое число, иначе устанавливаем значение 0
$rtplcode = isset($rtplcodearr[$i]) ? cot_import($rtplcodearr[$i], 'D', 'TXT') : ''; // Если для текущего элемента существует tplcode, то импортируем его как строку, иначе оставляем пустым

 

$rstructure['structure_tpl'] = ''; // Инициализируем переменную 'structure_tpl' как пустую строку
if (!empty($rtplcode) && (empty($rtplmode) || $rtplmode == 4)) { // Если tplcode не пуст и tplmode пуст или равен 4
    $rstructure['structure_tpl'] = $rtplcode; // Присваиваем tplcode значению 'structure_tpl'
} elseif ($rtplmode == 3 && !empty($rtplforcedarr[$i])) { // Если tplmode равен 3 и tplforced для текущего элемента не пуст
    $rstructure['structure_tpl'] = cot_import($rtplforcedarr[$i], 'D', 'TXT'); // Присваиваем значение из forcedarr
} elseif ($rtplmode == 2) { // Если tplmode равен 2
    $rstructure['structure_tpl'] = 'same_as_parent'; // Присваиваем 'same_as_parent' как значение 'structure_tpl'
} elseif ($rtplmode == 1) { // Если tplmode равен 1
    $rstructure['structure_tpl'] = ''; // Оставляем 'structure_tpl' пустым
}

 

if (!cot_error_found()) { // Проверяем, не были ли найдены ошибки
    $res = cot_structure_update($n, $i, $oldrow, $rstructure, $is_module); // Обновляем структуру с помощью функции cot_structure_update
    if (is_array($res)) { // Если результат обновления является массивом (с ошибками)
        cot_error($res[0], $res[1]); // Выводим ошибку
    }
}
} // закрываем foreach ($rstructurecode as $i => $k)

 

cot_extrafield_movefiles(); // Перемещаем файлы, связанные с дополнительными полями
cot_auth_clear('all'); // Очищаем кэш прав доступа для всех пользователей
if ($cache) { // Если объект кэша существует
    $cache->clear(); // Очищаем кэш
}

/* === Hook === */
foreach (cot_getextplugins('admin.structure.update.done') as $pl) { // Загружаем плагины для завершения обновления структуры
    include $pl; // Включаем каждый плагин
}
/* ===== */

if (!cot_error_found()) { // Если нет ошибок после обновления структуры
    cot_message('Updated'); // Выводим сообщение об успешном обновлении
} else {
    cot_error('adm_structure_somenotupdated'); // Если есть ошибки, выводим сообщение о том, что не все обновления прошли успешно
}

cot_redirect(cot_url('admin', 'm=structure&n='.$n.'&mode='.$mode.'&d='.$durl, '', true)); // Перенаправляем на страницу с результатами обновления

} // Закрываем if ($a == 'update' && !empty($_POST))

 

elseif ($a == 'add' && !empty($_POST)) { // Если запрос добавления и данные отправлены через POST
    $rstructure['structure_code'] = preg_replace('#[^\w\p{L}\-]#u', '', cot_import('rstructurecode', 'P', 'TXT')); // Убираем запрещенные символы из кода структуры
    $rstructure['structure_path'] = cot_import('rstructurepath', 'P', 'TXT'); // Получаем путь структуры из POST
    $rstructure['structure_title'] = cot_import('rstructuretitle', 'P', 'TXT'); // Получаем заголовок структуры из POST
    $rstructure['structure_desc'] = cot_import('rstructuredesc', 'P', 'TXT'); // Получаем описание структуры из POST
    $rstructure['structure_icon'] = cot_import('rstructureicon', 'P', 'TXT'); // Получаем иконку структуры из POST
    $rstructure['structure_locked'] = (cot_import('rstructurelocked', 'P', 'BOL')) ? 1 : 0; // Определяем, заблокирована ли структура, и присваиваем значение
    $rstructure['structure_area'] = $n; // Устанавливаем область структуры равной текущему расширению
    $rtplmode = cot_import('rtplmode', 'P', 'INT'); // Получаем режим шаблона из POST
    $rtplcode = cot_import('rtplcode', 'P', 'TXT'); // Получаем код шаблона из POST

 

if (!empty(Cot::$extrafields[Cot::$db->structure])) { // Проверяем, есть ли дополнительные поля для структуры
    foreach (Cot::$extrafields[Cot::$db->structure] as $exfld) { // Проходим по всем дополнительным полям
        $inputName = 'rstructure' . $exfld['field_name']; // Формируем имя поля из префикса и имени дополнительного поля
        // TODO Добавить новую запись. Нужно проверить, имеет ли дополнительное поле значение по умолчанию или оно обязательно
        if (isset($_POST[$inputName])) { // Если поле передано в POST
            $rstructure['structure_' . $exfld['field_name']] = cot_import_extrafields($inputName, // Импортируем значение дополнительного поля
                $exfld, 'P', '', 'structure_'); // Сохранение в массив структуры с префиксом "structure_"
        }
    }
}

 

($rstructure['structure_code'] != 'all') || cot_error('adm_structure_code_reserved', 'rstructurecode'); // Проверка, что код структуры не равен 'all', иначе ошибка
$rstructure['structure_code'] || cot_error('adm_structure_code_required', 'rstructurecode'); // Проверка, что код структуры не пустой, иначе ошибка
$rstructure['structure_path'] || cot_error('adm_structure_path_required', 'rstructurepath'); // Проверка, что путь структуры не пустой, иначе ошибка
$rstructure['structure_title'] || cot_error('adm_structure_title_required', 'rstructuretitle'); // Проверка, что название структуры не пустое, иначе ошибка

if (!empty($rtplcode)) { // Если код шаблона задан
    $rstructure['structure_tpl'] = $rtplcode; // Присваиваем код шаблона
} elseif ($rtplmode == 3) { // Если режим шаблона 3
    $rstructure['structure_tpl'] = cot_import('rtplforced', 'P', 'TXT'); // Присваиваем принудительно заданный шаблон
} elseif ($rtplmode == 2) { // Если режим шаблона 2
    $rstructure['structure_tpl'] = 'same_as_parent'; // Присваиваем шаблон, одинаковый с родительским
} else { // Если ни одно из условий не выполнено
    $rstructure['structure_tpl'] = ''; // Присваиваем пустое значение для шаблона
}

/* === Hook === */
foreach (cot_getextplugins('admin.structure.add.first') as $pl) { // Выполняем подключение плагинов на первом этапе добавления структуры
    include $pl; // Подключаем плагин
}
/* ===== */

 

if (!cot_error_found()) { // Если не найдены ошибки
    $res = cot_structure_add($n, $rstructure, $is_module); // Добавляем структуру, передавая параметры
    if ($res === true) { // Если результат добавления структуры успешен
        cot_extrafield_movefiles(); // Перемещаем файлы дополнительных полей
        /* === Hook === */
        foreach (cot_getextplugins('admin.structure.add.done') as $pl) { // Выполняем подключение плагинов на этапе завершения добавления структуры
            include $pl; // Подключаем плагин
        }
        /* ===== */
        cot_message('Added'); // Выводим сообщение об успешном добавлении
    } elseif (is_array($res)) { // Если результат добавления структуры - это массив с ошибкой
        cot_error($res[0], $res[1]); // Выводим ошибку
    } else { // В случае других ошибок
        cot_error('Error'); // Выводим общую ошибку
    }
}
cot_redirect(cot_url('admin', 'm=structure&n='.$n.'&mode='.$mode.'&d='.$durl, '', true)); // Перенаправляем пользователя на страницу структуры с соответствующими параметрами

 

} elseif ($a == 'delete') { // Если действие равно "удалить"
    cot_check_xg(); // Проверка на XSRF (Cross-Site Request Forgery)

    $data = Cot::$db->query( // Запрос к базе данных, чтобы получить данные о категории структуры
        'SELECT structure_code, structure_count FROM ' . Cot::$db->structure . 
        ' WHERE structure_area = :area AND structure_code = :code', 
        ['area' => $n, 'code' => $c] // Параметры для запроса
    )->fetch(); // Извлекаем данные

    if (empty($data)) { // Если данные не найдены (категория не существует)
        cot_error($c . ': ' . Cot::$L['adm_structure_category_not_exists']); // Выводим ошибку
    } elseif( // Если категория не пуста или имеет подкатегории
        $data['structure_count'] > 0 || 
        !empty(cot_structure_children($n, $c, true, false, false))
    ) {
        cot_error($c . ': ' . Cot::$L['adm_structure_category_not_empty']); // Выводим ошибку
    }

    if (!cot_error_found()) { // Если нет ошибок
        if (cot_structure_delete($n, $c, $is_module)) { // Удаляем структуру
            /* === Hook === */
            foreach (cot_getextplugins('admin.structure.delete.done') as $pl) { // Выполняем подключение плагинов на этапе удаления
                include $pl; // Подключаем плагин
            }
            /* ===== */
            cot_message('Deleted'); // Выводим сообщение об успешном удалении
        }
    }
    cot_redirect(cot_url('admin', 'm=structure&n='.$n.'&mode='.$mode.'&d='.$durl, '', true)); // Перенаправляем пользователя на страницу структуры с соответствующими параметрами
}

 

} elseif ($a == 'resyncall') { // Если действие равно "пересинхронизировать все"
    cot_check_xg(); // Проверка на XSRF (Cross-Site Request Forgery)
    $res = false; // Инициализация переменной результата
    $area_sync = 'cot_'.$n.'_sync'; // Формируем название функции для синхронизации

    if (function_exists($area_sync)) { // Если функция синхронизации существует
        $res = true; // Устанавливаем результат в true
        $sql = Cot::$db->query( // Запрос к базе данных для получения кодов категорий структуры
            'SELECT structure_code FROM ' . Cot::$db->structure . ' WHERE structure_area=?', 
            $n // Параметры для запроса
        );
        foreach ($sql->fetchAll() as $row) { // Для каждой категории структуры
            $cat = $row['structure_code']; // Получаем код категории
            $items = $area_sync($cat); // Вызываем функцию синхронизации для категории
            Cot::$db->update( // Обновляем количество элементов в структуре
                Cot::$db->structure, 
                ['structure_count' => (int) $items], 
                'structure_code=? AND structure_area=?', 
                [$cat, $n] // Параметры для обновления
            );
        }
        $sql->closeCursor(); // Закрываем курсор запроса
    }

    /* === Hook === */
    foreach (cot_getextplugins('admin.structure.resync.done') as $pl) { // Выполняем подключение плагинов на этапе пересинхронизации
        include $pl; // Подключаем плагин
    }
    /* ===== */

    // Если синхронизация успешна, выводим сообщение об успехе, иначе сообщение об ошибке
    $res ? cot_message('Resynced') : cot_message("Error: function $area_sync doesn't exist."); // TODO i18n

    // Если включен кэш, очищаем его
    if (Cot::$cache && !empty(Cot::$cfg['cache_' . $n])) {
        Cot::$cache->static->clearByUri(cot_url($n)); // Очищаем кэш для конкретного URI
    }

    // Перенаправляем пользователя на страницу структуры
    cot_redirect(
        cot_url('admin', ['m' => 'structure', 'n' => $n, 'mode' => $mode, 'd' => $durl], '', true)
    );
}

 

$ext_info = cot_get_extensionparams($n, true); // Получаем информацию о расширении
$adminPath[] = array(cot_url('admin', 'm=extensions'), Cot::$L['Extensions']); // Добавляем ссылку на раздел расширений в навигацию
$urlParams = array('m' => 'extensions', 'a' => 'details'); // Устанавливаем параметры URL для страницы подробностей
if ($is_module) {
    $urlParams['mod'] = $n; // Если это модуль, добавляем параметр 'mod'
} else {
    $urlParams['pl'] = $n; // Если это плагин, добавляем параметр 'pl'
}
$adminPath[] = [cot_url('admin', $urlParams), $ext_info['name']]; // Добавляем ссылку на страницу расширения
$adminPath[] = [cot_url('admin', 'm=structure&n='.$n), Cot::$L['Structure']]; // Добавляем ссылку на структуру в навигацию

// Проверка на наличие ID или алиаса для структуры
if ($id > 0 || !empty($al)) {
    $where = $id > 0 ? 'structure_id='.(int)$id : "structure_code='".$db->prep($al)."'"; // Устанавливаем условие для поиска структуры
    $sql = Cot::$db->query("SELECT * FROM " . Cot::$db->structure . " WHERE $where LIMIT 1"); // Запрашиваем структуру
    cot_die($sql->rowCount() == 0); // Если не найдено, завершаем выполнение с ошибкой

// Если задан режим 'all' или структура существует для текущего режима
} elseif ($mode && ($mode == 'all' || $structure[$n][$mode])) {
    $sqlmask = ($mode == 'all') ? "structure_path NOT LIKE '%.%'" : "structure_path LIKE '".$db->prep($structure[$n][$mode]['rpath']).".%' AND structure_path NOT LIKE '".$db->prep($structure[$n][$mode]['rpath']).".%.%'"; // Создаем маску для фильтрации
    // Запрашиваем структуры с учетом маски
    $sql = $db->query("SELECT * FROM $db_structure WHERE structure_area='".$db->prep($n)."' AND $sqlmask ORDER BY structure_path ASC, structure_code ASC LIMIT $d, ".$maxrowsperpage);

    // Получаем общее количество элементов для пагинации
    $totalitems = $db->query("SELECT COUNT(*) FROM $db_structure WHERE structure_area='".$db->prep($n)."' AND $sqlmask")->fetchColumn();
    // Генерируем пагинацию
    $pagenav = cot_pagenav('admin', 'm=structure&n='.$n.'&mode='.$mode, $d, $totalitems, $maxrowsperpage, 'd', '', $cfg['jquery'] && $cfg['turnajax']);

} else { // В случае если не задан ни ID, ни алиас, и нет особого режима
    // Запрашиваем все структуры для данного раздела
    $sql = $db->query("SELECT * FROM $db_structure WHERE structure_area='".$db->prep($n)."' ORDER BY structure_path ASC, structure_code ASC LIMIT $d, ".$maxrowsperpage);

    // Получаем общее количество элементов для пагинации
    $totalitems = $db->query("SELECT COUNT(*) FROM $db_structure WHERE structure_area='".$db->prep($n)."'")->fetchColumn();
    // Генерируем пагинацию
    $pagenav = cot_pagenav('admin', 'm=structure&n='.$n, $d, $totalitems, $maxrowsperpage, 'd', '', $cfg['jquery'] && $cfg['turnajax']);
}

 

$t->assign(array(
    'ADMIN_STRUCTURE_UPDATE_FORM_URL' => cot_url('admin', 'm=structure&n='.$n.'&mode='.$mode.'&a=update&d='.$durl), // Ссылка на форму обновления структуры
    'ADMIN_PAGE_STRUCTURE_RESYNCALL' => cot_url('admin', 'm=structure&n='.$n.'&mode='.$mode.'&a=resyncall&'.cot_xg().'&d='.$durl), // Ссылка для синхронизации всех структур
    'ADMIN_STRUCTURE_URL_EXTRAFIELDS' => cot_url('admin', 'm=extrafields&n='.$db_structure) // Ссылка на дополнительные поля структуры
));

$categoryList = []; // Массив для списка категорий

$ii = 0; // Индекс для подсчета элементов
/* === Hook - Part1 : Set === */
$extp = cot_getextplugins('admin.structure.loop'); // Получаем расширения для цикла
/* ===== */

// Проходим по всем строкам результата запроса
foreach ($sql->fetchAll() as $row) {
    $ii++; // Увеличиваем индекс для каждой строки
    // Дальше идет обработка каждой строки в цикле

 

$structureId = $row['structure_id']; // Идентификатор структуры
$structureCode = $row['structure_code']; // Код структуры

$pathfielddep = explode(".", $row['structure_path']); // Разделяем путь структуры на части
$pathfielddep = !empty($pathfielddep) ? count($pathfielddep) : 0; // Получаем количество частей пути
$structureLevel = ($pathfielddep > 0) ? $pathfielddep : 0; // Уровень структуры в иерархии

$pathspaceimg = ''; // Инициализируем переменную для визуальных отступов
for ($pathfielddepi = 1; $pathfielddepi < $pathfielddep; $pathfielddepi++) {
    $pathspaceimg .= '.' . Cot::$R['admin_icon_blank']; // Добавляем иконку для каждого уровня иерархии
}

// @todo Не используйте код категории, используйте ID вместо
foreach ($structure[$n] as $catCode => $x) {
    if ($catCode != 'all') { // Исключаем категорию "all"
        $categoryList[$catCode] = $x['tpath']; // Добавляем в список категорий путь для каждой категории
    }
}

if (empty($row['structure_tpl'])) {
    $tplMode = '1'; // Если шаблон не указан, используем режим 1
} elseif ($row['structure_tpl'] == 'same_as_parent') {
    $tplMode = '2'; // Если шаблон одинаков с родительским, используем режим 2
} else {
    $tplMode = '3'; // Если шаблон указан, используем режим 3
    if (!in_array($row['structure_tpl'], array_keys($categoryList))) {
        $tplMode = '4'; // Если шаблон не найден в списке категорий, используем режим 4
    }
}

 

$categoryTplCodeSelect = cot_selectbox(
    $row['structure_tpl'], // Значение по умолчанию (код текущего шаблона)
    'rstructuretplforced[' . $row['structure_id'] . ']', // Имя поля для выбора шаблона
    array_keys($categoryList), // Список значений (категории)
    array_values($categoryList), // Список отображаемых значений (пути категорий)
    false // Не требуется указание пустого значения
);

$categoryTplCode = cot_inputbox(
    'text', // Тип поля ввода
    'rstructuretplcode[' . $row['structure_id'] . ']', // Имя поля ввода шаблона
    $row['structure_tpl'], // Значение по умолчанию (текущий шаблон)
    'maxlength="255"' // Ограничение на длину ввода
);

$categoryTpl = cot_radiobox(
    $tplMode, // Значение, соответствующее выбранному режиму
    'rstructuretplmode[' . $row['structure_id'] . ']', // Имя поля для выбора режима шаблона
    ['1', '2', '3', '4'], // Возможные значения режима
    [
        Cot::$L['adm_tpl_empty'], // Режим 1: Пустой шаблон
        Cot::$L['adm_tpl_parent'], // Режим 2: Шаблон родителя
        Cot::$L['adm_tpl_forced'] . ' ' . $categoryTplCodeSelect, // Режим 3: Принудительный шаблон с выбором
        Cot::$L['adm_tpl_code'] . ' ' . $categoryTplCode, // Режим 4: Шаблон по коду с возможностью ввода
    ],
    '', // Не указываем дополнительный класс или атрибут
    '<br />', // Разделитель между радиокнопками
    '', // Не указываем id
    true // Ожидаем, что один из вариантов будет выбран по умолчанию
);

 

$children = cot_structure_children(
    $row['structure_area'], // Область структуры (например, модуль или плагин)
    $row['structure_code'], // Код текущей категории
    true, // Включить дочерние элементы
    false, // Исключить текущую категорию из результатов
    false // Не использовать кэширование
);

$deleteUrl = cot_url(
    'admin', // Раздел панели администрирования
    [
        'm' => 'structure', // Модуль управления структурами
        'n' => $n, // Имя области (например, модуля или плагина)
        'mode' => $mode, // Режим отображения
        'a' => 'delete', // Действие (удаление категории)
        'id' => $row['structure_id'], // ID структуры для удаления
        'c' => $row['structure_code'], // Код категории
        'd' => $durl, // Параметр постраничной навигации
        'x' => Cot::$sys['xk'] // CSRF-токен для безопасности
    ]
);

$deleteConfirmUrl = cot_confirm_url($deleteUrl, 'admin'); // URL с подтверждением удаления

 

$t->assign([
    // ID структуры
    'ADMIN_STRUCTURE_ID' => $row['structure_id'],
    
    // Поле ввода для кода структуры
    'ADMIN_STRUCTURE_CODE' => cot_inputbox(
        'text',
        'rstructurecode[' . $row['structure_id'] . ']',
        $row['structure_code'],
        'maxlength="255"' // Ограничение длины
    ),
    
    // Пробелы для иерархии
    'ADMIN_STRUCTURE_SPACEIMG' => $pathspaceimg,
    
    // Уровень вложенности структуры
    'ADMIN_STRUCTURE_LEVEL' => $structureLevel,
    
    // Иконка пути (в зависимости от позиции)
    'ADMIN_STRUCTURE_PATHFIELDIMG' => (mb_strpos($row['structure_path'], '.') == 0) ?
        Cot::$R['admin_icon_join1'] : Cot::$R['admin_icon_join2'],
    
    // Поле ввода пути структуры
    'ADMIN_STRUCTURE_PATH' => cot_inputbox(
        'text',
        'rstructurepath[' . $row['structure_id'] . ']',
        $row['structure_path'],
        'maxlength="255"' // Ограничение длины
    ),
    
    // Выбор шаблона категории
    'ADMIN_STRUCTURE_TPL' => $categoryTpl,
    
    // Выпадающий список для выбора шаблона категории
    'ADMIN_STRUCTURE_TPL_CODE_SELECT' => $categoryTplCodeSelect,
    
    // Поле ввода пользовательского шаблона
    'ADMIN_STRUCTURE_TPL_CODE' => $categoryTplCode,
    
    // Поле ввода названия структуры
    'ADMIN_STRUCTURE_TITLE' => cot_inputbox(
        'text',
        'rstructuretitle[' . $row['structure_id'] . ']',
        $row['structure_title'],
        'maxlength="255"' // Ограничение длины
    ),
    
    // Поле ввода описания структуры
    'ADMIN_STRUCTURE_DESC' => cot_inputbox(
        'text',
        'rstructuredesc[' . $row['structure_id'] . ']',
        $row['structure_desc'],
        'maxlength="255"' // Ограничение длины
    ),
    
    // Поле ввода иконки структуры
    'ADMIN_STRUCTURE_ICON' => cot_inputbox(
        'text',
        'rstructureicon[' . $row['structure_id'] . ']',
        $row['structure_icon'],
        'maxlength="128"' // Ограничение длины
    ),
    
    // Чекбокс для блокировки категории
    'ADMIN_STRUCTURE_LOCKED' => cot_checkbox(
        $row['structure_locked'],
        'rstructurelocked[' . $row['structure_id'] . ']' // Имя чекбокса
    ),
    
    // Количество элементов в структуре
    'ADMIN_STRUCTURE_COUNT' => $row['structure_count'],
    
    // Возможность удаления структуры (если пустая и нет детей)
    'ADMIN_STRUCTURE_CAN_DELETE' => $row['structure_count'] < 1 && empty($children),
    
    // URL для перехода к категории на сайте
    'ADMIN_STRUCTURE_JUMPTO_URL' => cot_url($n, 'c=' . $row['structure_code']),
    
    // URL для управления правами доступа
    'ADMIN_STRUCTURE_RIGHTS_URL' => $is_module
        ? cot_url('admin', 'm=rightsbyitem&ic=' . $n . '&io=' . $row['structure_code'])
        : '',
    
    // URL для редактирования структуры
    'ADMIN_STRUCTURE_OPTIONS_URL' => cot_url(
        'admin',
        'm=structure&n=' . $n . '&d=' . $durl . '&id=' . $row['structure_id'] . '&' . cot_xg()
    ),
    
    // URL для удаления структуры
    'ADMIN_STRUCTURE_DELETE_URL' => $deleteUrl,
    
    // Подтверждение удаления структуры
    'ADMIN_STRUCTURE_DELETE_CONFIRM_URL' => $deleteConfirmUrl,
    
    // Чередование классов (например, для зебры в таблице)
    'ADMIN_STRUCTURE_ODDEVEN' => cot_build_oddeven($ii),
]);

 

if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) { // Проверка режима совместимости
    $t->assign([
        'ADMIN_STRUCTURE_TPLMODE' => $categoryTpl, // @deprecated. Выбор (настройка) кода шаблона
        'ADMIN_STRUCTURE_UPDATE_DEL_URL' => $deleteConfirmUrl, // @deprecated. Используйте ADMIN_STRUCTURE_DELETE_CONFIRM_URL
    ]);
}

 

if (!empty(Cot::$extrafields[Cot::$db->structure])) { // Проверка на наличие дополнительных полей
    foreach (Cot::$extrafields[Cot::$db->structure] as $exfld) { // Обработка каждого дополнительного поля
        $exfld_val = cot_build_extrafields('rstructure' . $exfld['field_name'] . '_' . $row['structure_id'], $exfld, $row['structure_' . $exfld['field_name']]); // Построение значения поля
        $exfld_title = cot_extrafield_title($exfld, 'structure_'); // Получение заголовка поля

        $t->assign(array(
            'ADMIN_STRUCTURE_' . strtoupper($exfld['field_name']) => $exfld_val, // Значение дополнительного поля
            'ADMIN_STRUCTURE_' . strtoupper($exfld['field_name']) . '_TITLE' => $exfld_title, // Заголовок дополнительного поля
            'ADMIN_STRUCTURE_EXTRAFLD' => $exfld_val, // Значение дополнительного поля для шаблона
            'ADMIN_STRUCTURE_EXTRAFLD_TITLE' => $exfld_title // Заголовок дополнительного поля для шаблона
        ));
        $t->parse(($id || !empty($al)) ? 'MAIN.OPTIONS.EXTRAFLD' : 'MAIN.DEFAULT.ROW.EXTRAFLD'); // Парсинг шаблона
    }
}

/* === Hook - Part2 : Include === */
foreach ($extp as $pl) { // Включение хуков
    include $pl;
}
/* ===== */

 

if ($id || !empty($al)) { // Проверка, редактируется ли структура или выбран алиас
    require_once cot_incfile('configuration'); // Подключение файла конфигурации

    $adminTitle .= ': ' . htmlspecialchars($row['structure_title']); // Добавление заголовка
    $adminPath[] = [ // Добавление пути в админской панели
        cot_url('admin', ['m' => 'structure', 'n' => $n, 'id' => $id]),
        $row['structure_title'],
    ];

    $optionslist = cot_config_list($is_module ? 'module' : 'plug', $n, $row['structure_code']); // Получение списка конфигураций

    /* === Hook - Part1 : Set === */
    $extp = cot_getextplugins('admin.config.edit.loop'); // Хуки для цикла конфигурации
    /* ===== */
    foreach ($optionslist as $configRow) { // Обработка каждой строки конфигурации
        list($title, $hint) = cot_config_titles($configRow['config_name'], $configRow['config_text']); // Заголовок и подсказка конфигурации

        if ($configRow['config_type'] == COT_CONFIG_TYPE_SEPARATOR) { // Если это разделитель
            $t->assign('ADMIN_CONFIG_FIELDSET_TITLE', $title); // Название разделителя
            $t->parse('MAIN.OPTIONS.CONFIG.ADMIN_CONFIG_ROW.ADMIN_CONFIG_FIELDSET_BEGIN'); // Парсинг начала раздела
        } else { // Если это обычная настройка
            $t->assign([
                'ADMIN_CONFIG_ROW_CONFIG' => cot_config_input($configRow), // Ввод конфигурации
                'ADMIN_CONFIG_ROW_CONFIG_TITLE' => $title, // Заголовок конфигурации
                'ADMIN_CONFIG_ROW_CONFIG_MORE_URL' => cot_url( // Ссылка для сброса конфигурации
                    'admin',
                    [
                        'm' => 'structure',
                        'n' => $n,
                        'd' => $durl,
                        'id' => $row['structure_id'],
                        'al' => $row['structure_code'],
                        'a' => 'reset',
                        'v' => $configRow['config_name'],
                        'x' => Cot::$sys['xk'],
                    ]
                ),
                'ADMIN_CONFIG_ROW_CONFIG_MORE' => $hint // Подсказка для конфигурации
            ]);

            /* === Hook - Part2 : Include === */
            foreach ($extp as $pl) { // Хуки для настроек
                include $pl;
            }
            /* ===== */

            $t->parse('MAIN.OPTIONS.CONFIG.ADMIN_CONFIG_ROW.ADMIN_CONFIG_ROW_OPTION'); // Парсинг строки опции
        }
        $t->parse('MAIN.OPTIONS.CONFIG.ADMIN_CONFIG_ROW'); // Парсинг строки конфигурации
    }

    /* === Hook  === */
    foreach (cot_getextplugins('admin.config.edit.tags') as $pl) { // Хуки для тегов конфигурации
        include $pl;
    }
    /* ===== */

    $t->assign('CONFIG_HIDDEN', cot_inputbox('hidden', 'editconfig', $row['structure_code'])); // Скрытое поле для отправки кода структуры
    $t->parse('MAIN.OPTIONS.CONFIG'); // Парсинг конфигурации
}

$t->parse(($id || !empty($al)) ? 'MAIN.OPTIONS' : 'MAIN.DEFAULT.ROW'); // Парсинг шаблона в зависимости от режима
}
unset($row); // Очистка строки данных

 

if (!$id && empty($al)) { // Проверка на отсутствие ID и алиаса
    $t->assign([
        'ADMIN_STRUCTURE_PAGINATION_PREV' => $pagenav['prev'], // Предыдущая страница пагинации
        'ADMIN_STRUCTURE_PAGNAV' => $pagenav['main'], // Навигация пагинации
        'ADMIN_STRUCTURE_PAGINATION_NEXT' => $pagenav['next'], // Следующая страница пагинации
        'ADMIN_STRUCTURE_TOTALITEMS' => $totalitems, // Общее количество элементов
        'ADMIN_STRUCTURE_COUNTER_ROW' => $ii, // Счётчик строк
    ]);
    $t->parse('MAIN.DEFAULT'); // Парсинг основного шаблона

    // Очистка буфера, если он содержит данные таблицы обновлений
    $uri = str_replace('&_ajax=1', '', $_SERVER['REQUEST_URI']); // Удаление AJAX-параметра из URI
    $hash = md5($uri); // Генерация хэша URI
    if (isset($_SESSION['cot_buffer']) && isset($_SESSION['cot_buffer'][$hash]) && is_array($_SESSION['cot_buffer'][$hash]['rstructurecode'])) {
        unset($_SESSION['cot_buffer'][$hash]); // Удаление буфера
    }

    // Форма для добавления новой категории
    $categoryTplCodeSelect = !empty($categoryList)
        ? cot_selectbox(
            null,
            'rtplforced',
            array_keys($categoryList),
            array_values($categoryList),
            false
        )
        : ''; // Выпадающий список шаблонов категорий

    $categoryTplCode = cot_inputbox('text', 'rtplcode', null, 'maxlength="255"'); // Поле для кода шаблона
    $categoryTpl = !empty($categoryList)
        ? cot_radiobox(
            null,
            'rtplmode',
            ['1', '2', '3', '4'],
            [
                Cot::$L['adm_tpl_empty'], // Пустой шаблон
                Cot::$L['adm_tpl_parent'], // Родительский шаблон
                Cot::$L['adm_tpl_forced'] . ' ' . $categoryTplCodeSelect, // Принудительный шаблон
                Cot::$L['adm_tpl_code'] . ' ' . $categoryTplCode, // Код шаблона
            ],
            '',
            '<br />',
            '',
            true
        )
        : ''; // Радиобокс выбора шаблона

    $t->assign([
        'ADMIN_STRUCTURE_URL_FORM_ADD' => cot_url( // URL для добавления категории
            'admin',
            ['m' => 'structure', 'n' => $n, 'mode' => $mode, 'a' => 'add', 'd' => $durl]
        ),
        'ADMIN_STRUCTURE_CODE' => cot_inputbox('text', 'rstructurecode', null), // Поле для кода структуры
        'ADMIN_STRUCTURE_PATH' => cot_inputbox('text', 'rstructurepath', null, 'maxlength="16"'), // Поле для пути структуры
        'ADMIN_STRUCTURE_TITLE' => cot_inputbox('text', 'rstructuretitle', null, 'maxlength="100"'), // Поле для названия структуры
        'ADMIN_STRUCTURE_DESC' => cot_inputbox('text', 'rstructuredesc', null, 'maxlength="255"'), // Поле для описания
        'ADMIN_STRUCTURE_ICON' => cot_inputbox('text', 'rstructureicon', null, 'maxlength="128"'), // Поле для иконки
        'ADMIN_STRUCTURE_LOCKED' => cot_checkbox(null, 'rstructurelocked'), // Чекбокс блокировки
        'ADMIN_STRUCTURE_TPL' => $categoryTpl, // Радиобокс шаблона
    ]);
    if (isset(Cot::$cfg['legacyMode']) && Cot::$cfg['legacyMode']) { // Поддержка устаревшего режима
        $t->assign([
            'ADMIN_STRUCTURE_TPLMODE' => $categoryTpl, // Устаревший параметр шаблона
        ]);
    }

    // Добавление дополнительных полей
    if (!empty(Cot::$extrafields[Cot::$db->structure])) {
        foreach (Cot::$extrafields[Cot::$db->structure] as $exfld) { // Перебор дополнительных полей
            $exfld_val = cot_build_extrafields('rstructure' . $exfld['field_name'], $exfld, null); // Построение поля
            $exfld_title = cot_extrafield_title($exfld, 'structure_'); // Заголовок поля

            $t->assign([
                'ADMIN_STRUCTURE_' . strtoupper($exfld['field_name']) => $exfld_val, // Значение поля
                'ADMIN_STRUCTURE_' . strtoupper($exfld['field_name']) . '_TITLE' => $exfld_title, // Заголовок поля
                'ADMIN_STRUCTURE_EXTRAFLD' => $exfld_val, // Поле для вывода
                'ADMIN_STRUCTURE_EXTRAFLD_TITLE' => $exfld_title, // Заголовок для вывода
            ]);
            $t->parse('MAIN.NEWCAT.EXTRAFLD'); // Парсинг дополнительных полей
        }
    }
    $t->parse('MAIN.NEWCAT'); // Парсинг блока для новой категории
}
cot_display_messages($t); // Отображение сообщений (уведомлений) в шаблоне

/* === Hook === */
foreach (cot_getextplugins('admin.structure.tags') as $pl) { // Подключение хуков для тега admin.structure.tags
    include $pl; // Включение плагина
}
/* ===== */

$t->parse('MAIN'); // Парсинг основного блока шаблона
$adminMain = $t->text('MAIN'); // Вывод содержимого основного блока в переменную
}

 

29 minutes read Administrator

Comments (0)

No comments yet
Only registered users can post new comments

Content author

Administrator

Offline

Administrator

Last logged: 2026-07-05 18:32

  • Page published: 2025-01-28 19:25
  • Last update: 2025-01-28 20:19

Similar pages

HTML-шаблон admin.structure.tpl в Cotonti
1 Файл admin.structure.tpl в движке Cotonti CMF является HTML-шаблоном для отображения структуры сайта в административной
Файл structure.php в Cotonti
2 Файл structure.php в системной папке Cotonti CMF отвечает за манипуляции с категориями структуры сайта, то есть, за
Файл admin.cache.disk.php в Cotonti CMF
3 Файл admin.cache.disk.php в движке Cotonti CMF является частью административной панели, предназначенной для управления
Файл admin.config.php в Cotonti CMF
4 Основное назначение файла и его место в системе Файл admin.config.php является частью административной панели системы
Файл admin.extensions.php в Cotonti CMF
5 Файл "admin.extensions.php" в движке Cotonti CMF является важным компонентом административной части системы,