| @copyright 2007-2026 (c) AVE.cms | @link https://ave-cms.ru | @version 3.3 */ namespace App\Adminx\Navigation; defined('BASEPATH') || die('Direct access to this location is not allowed.'); use App\Adminx\Support\CodeEditor; use App\Common\AdminAssets; use App\Common\Controller as BaseController; use App\Common\Permission; use App\Helpers\Request; class Controller extends BaseController { public function index(array $params = array()) { AdminAssets::addStyle($this->base() . '/modules/Navigation/assets/navigation.css', 50); AdminAssets::addScript($this->base() . '/modules/Navigation/assets/navigation.js', 50); CodeEditor::useCodeMirror('htmlmixed'); $q = Request::getStr('q', ''); return $this->render('@navigation/index.twig', array( 'navigation_items' => Model::all($q), 'stats' => Model::stats(), 'filters' => array('q' => $q), 'access_groups' => Model::accessGroups(), 'can_manage' => Permission::check('manage_navigation'), )); } public function show(array $params = array()) { $item = Model::one(isset($params['id']) ? (int) $params['id'] : 0); if (!$item) { return $this->error('Навигация не найдена', array(), 404); } return $this->success('', array('data' => $item)); } public function aliasCheck(array $params = array()) { if (!Permission::check('manage_navigation')) { return $this->error('Недостаточно прав', array(), 403); } $alias = trim(Request::getStr('alias', '')); $id = Request::getInt('id', 0); $valid = true; $available = true; $message = 'Алиас свободен'; if ($alias === '') { $valid = false; $available = false; $message = 'Укажите алиас'; } elseif (preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $alias) !== 1 || is_numeric($alias)) { $valid = false; $available = false; $message = 'Только A-Z, 0-9, дефис и подчёркивание, до 20 символов; не число'; } elseif (Model::aliasExists($alias, $id)) { $available = false; $message = 'Такой алиас уже используется'; } return $this->success($message, array( 'data' => array( 'alias' => $alias, 'id' => $id, 'valid' => $valid, 'available' => $available, ), )); } public function documentPicker(array $params = array()) { if (!Permission::check('manage_navigation')) { return $this->error('Недостаточно прав', array(), 403); } return $this->success('', array( 'data' => array( 'items' => Model::documentPicker( Request::getStr('q', ''), Request::getInt('limit', 30) ), ), )); } public function store(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $errors = $this->validate(Request::postAll(), 0); if (!empty($errors)) { return $this->error('Проверьте поля формы', $errors); } $id = Model::save(0, Request::postAll()); return $this->success('Навигация создана', array('data' => array('id' => $id), 'redirect' => $this->base() . '/navigation')); } public function update(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $id = isset($params['id']) ? (int) $params['id'] : 0; if (!Model::one($id)) { return $this->error('Навигация не найдена', array(), 404); } $errors = $this->validate(Request::postAll(), $id); if (!empty($errors)) { return $this->error('Проверьте поля формы', $errors); } Model::save($id, Request::postAll()); return $this->success('Навигация сохранена', array('redirect' => $this->base() . '/navigation')); } public function copy(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } try { Model::copy(isset($params['id']) ? (int) $params['id'] : 0, Request::postStr('title', '')); } catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } return $this->success('Копия создана', array('redirect' => $this->base() . '/navigation')); } public function clearCache(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $item = Model::one(isset($params['id']) ? (int) $params['id'] : 0); if (!$item) { return $this->error('Навигация не найдена', array(), 404); } Model::clearCache($item['navigation_id'], $item['alias']); return $this->success('Кеш навигации очищен'); } public function items(array $params = array()) { $id = isset($params['id']) ? (int) $params['id'] : 0; $nav = Model::one($id); if (!$nav) { return $this->error('Навигация не найдена', array(), 404); } return $this->success('', array( 'data' => array( 'navigation' => array( 'id' => $nav['navigation_id'], 'title' => $nav['title'], 'alias' => $nav['alias'], 'tag' => $nav['tag'], ), 'items' => Model::itemsTree($id), 'flat' => Model::flatItems($id), ), )); } public function item(array $params = array()) { $item = Model::item(isset($params['item']) ? (int) $params['item'] : 0); if (!$item) { return $this->error('Пункт навигации не найден', array(), 404); } return $this->success('', array('data' => $item)); } public function storeItem(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $navigationId = isset($params['id']) ? (int) $params['id'] : 0; if (!Model::one($navigationId)) { return $this->error('Навигация не найдена', array(), 404); } $errors = $this->validateItem(Request::postAll()); if (!empty($errors)) { return $this->error('Проверьте поля пункта', $errors); } $id = Model::saveItem(0, $navigationId, Request::postAll()); return $this->success('Пункт навигации создан', array('data' => array('id' => $id))); } public function updateItem(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $id = isset($params['item']) ? (int) $params['item'] : 0; $item = Model::item($id); if (!$item) { return $this->error('Пункт навигации не найден', array(), 404); } $errors = $this->validateItem(Request::postAll()); if (!empty($errors)) { return $this->error('Проверьте поля пункта', $errors); } Model::saveItem($id, (int) $item['navigation_id'], Request::postAll()); return $this->success('Пункт навигации сохранён'); } public function reorderItems(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $navigationId = isset($params['id']) ? (int) $params['id'] : 0; if (!Model::one($navigationId)) { return $this->error('Навигация не найдена', array(), 404); } $order = Request::postJsonArray('order'); if (!is_array($order)) { return $this->error('Некорректный порядок пунктов', array(), 422); } try { Model::reorderItems($navigationId, $order); } catch (\InvalidArgumentException $e) { return $this->error($e->getMessage(), array(), 422); } return $this->success('Порядок пунктов сохранён'); } public function toggleItem(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } $status = Model::toggleItem(isset($params['item']) ? (int) $params['item'] : 0); if ($status === null) { return $this->error('Пункт навигации не найден', array(), 404); } return $this->success($status === '1' ? 'Пункт включён' : 'Пункт выключен', array('data' => array('status' => $status))); } public function destroyItem(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } if (!Model::deleteItem(isset($params['item']) ? (int) $params['item'] : 0)) { return $this->error('Пункт навигации не найден', array(), 404); } return $this->success('Пункт навигации удалён или выключен'); } public function destroy(array $params = array()) { if (($err = $this->guard()) !== null) { return $err; } try { if (!Model::delete(isset($params['id']) ? (int) $params['id'] : 0)) { return $this->error('Навигация не найдена', array(), 404); } } catch (\Throwable $e) { return $this->error($e->getMessage(), array(), 422); } return $this->success('Навигация удалена'); } protected function guard() { return $this->guardPermission('manage_navigation'); } protected function validate(array $input, $id) { $errors = array(); $title = trim(isset($input['title']) ? (string) $input['title'] : ''); $alias = trim(isset($input['alias']) ? (string) $input['alias'] : ''); $level1 = isset($input['level1']) ? trim((string) $input['level1']) : ''; $level1Active = isset($input['level1_active']) ? trim((string) $input['level1_active']) : ''; if ($title === '') { $errors['title'] = 'Укажите название'; } if ($alias === '') { $errors['alias'] = 'Укажите алиас'; } elseif (preg_match('/^[A-Za-z0-9-_]{1,20}$/i', $alias) !== 1 || is_numeric($alias)) { $errors['alias'] = 'Только A-Z, 0-9, дефис и подчёркивание, до 20 символов; не число'; } elseif (Model::aliasExists($alias, (int) $id)) { $errors['alias'] = 'Такой алиас уже используется'; } if ($level1 === '') { $errors['level1'] = 'Укажите шаблон ссылки первого уровня'; } if ($level1Active === '') { $errors['level1_active'] = 'Укажите активный шаблон первого уровня'; } return $errors; } protected function validateItem(array $input) { $errors = array(); $title = trim(isset($input['title']) ? (string) $input['title'] : ''); $alias = trim(isset($input['alias']) ? (string) $input['alias'] : ''); $parentId = isset($input['parent_id']) ? (int) $input['parent_id'] : 0; if ($title === '') { $errors['item_title'] = 'Укажите название пункта'; } if ($alias === '') { $errors['item_alias'] = 'Укажите ссылку или alias'; } if ($parentId < 0) { $errors['item_parent_id'] = 'Некорректный родитель'; } return $errors; } }