Содержание
При разработке модуля, для новой неизвестной мне CMS, всегда хотелось сначала сделать страницу настроек разрабатываемого модуля, чтобы провести быстрый экскурс в ядро движка и на основе примеров из соседних модулей ознакомится с кодом.
Однако, порой при разборе встроенных или сторонних модулей (почему-то не нашелся внятный ман для OpenCart по этой теме), не удается изъть код, который решает некоторые, казалось бы, элементарные вещи, на самой ранней стадии разработки модуля.
Именно этим мы и займемся в данной статье, ну хотя бы попытаемся :)
Создадим файл перевода admin/language/ru-ru/extension/module/mymodulesettings.php
в который помещаем минимально необходимый набор переводов:
php$_['doc_title'] = 'Мой модуль с настройками'; $_['heading_title'] = 'Мой модуль с настройками'; $_['settings_success'] = 'Настройки успешно изменены!'; $_['settings_edit'] = 'Настройки модуля'; $_['entry_setting1'] = 'Введите настройку 1'; $_['entry_setting2'] = 'Введите настройку 2';
heading_title
модуль появится в списке модулей с неправильным именемСоздать контроллер модуля страницы настроек admin/controller/extension/module/mymodulesettings.php
в котором должны быть методы:
index
- вывод страницы настроек, обработка их сохраненияvalidate
- для валидации настроек из метода indexinstall
- установка модуляuninstall
- деинсталяция/удаление (из системы движка) модуляphpclass ControllerExtensionModuleMyModuleSettings extends Controller { //страница настроек модуля public function index() {} //установка модуля public function install() {} //деинсталяция модуля public function uninstall() {} //валидация настроек модуля protected function validate() {} //линейный массив с ошибками private $m_aErrors = []; };
Метод контроллера позволяющий вывести интерфейс страницы настроек (метод по умолчанию):
phppublic function index() { ... }
Помещаем в этот метод код. Осуществляем первичные действия:
php//загрузка файла перевода модуля $this->load->language('extension/module/mymodulesettings'); //установка title страницы $this->document->setTitle($this->language->get('doc_title')); //загрузка модели настроек $this->load->model('setting/setting'); //создаем пустой массив, позже заполним его данными для шаблона $data = [];
Теперь, если текущий метод POST, тогда нужно обработать входящие данные и сохранить настройки модуля если проверка корректности данных прошла успешно (если нет, то останутся старые данные):
phpif($this->request->server['REQUEST_METHOD'] == 'POST') { //если валидация прошла успешно if($this->validate()) { //сохранение настроек модуля $this->model_setting_setting->editSetting('mymodulesettings', $this->request->post); //записываем в сессию статус успеха сохранения настроек $this->session->data['settings_success'] = $this->language->get('settings_success'); } //валидация закончилась ошибкой, запишем информацию об этом в сессию else $this->session->data['settings_error'] = $this->m_aErrors; //перенаправляем на страницу настроек модуля $this->response->redirect($this->url->link('extension/module/mymodulesettings', 'token=' . $this->session->data['token'] . '&type=module', true)); }
Внимательный читатель заметит что мы что-то там записываем в сессию.
Нам как-то надо иметь информацию о статусе сохранения (удалось или нет) и показывать ее в интерфейсе. А у нас тут перенаправление при сохранении (оно и понятно, ведь нам нужно сбросить текущий метод запроса страницы, а он сбрасывается редиректом, если не сбросить то при обновлении страницы на сервер будет отправляться POST запрос). Самый простой вариант, который пришел на ум это сохранять статус в сессию (вообще-то не статус, а текст статуса), а при показе страницы показывать статус и удалять его из сессии.
Статус мы уже сохранили в сессию ранее, теперь обработаем сохраненные данные и вставим в массив для шаблона то, что нам нужно:
php//если было успешное изменение настроек - показываем сообщение и удаляем из сессии чтобы больше не показывать if(array_key_exists("settings_success", $this->session->data)) { $data['settings_success'] = $this->language->get('settings_success'); unset($this->session->data["settings_success"]); } else $data['settings_success'] = false; //если есть ошибки - показываем и удаляем из сессии чтобы больше не показывать if(array_key_exists("settings_error", $this->session->data)) { $data['error_warning'] = implode("<br/>", $this->session->data["settings_error"]); unset($this->session->data["settings_error"]); } else $data['error_warning'] = false;
Удаляем данные статуса из сессии для того чтобы не показывать его повторно, при обновлении страницы.
Далее ...
При разработке модуля для фискализации, мне потребовалось иметь неизменяемые данные в настройках, которые не надо было показывать юзеру. Для безопасности (гарантии неизменяемости данных при изменении настроек), использовал такое перед сохранением настроек:
php$this->request->post["mymodulesettings_readonly"] = $this->config->get('mymodulesettings_readonly');
Теперь нужно показать страницу с формой редактирования настроек модуля. Продолжаем заполнять массив данными для шаблона представления.
Установка основных данных для страницы редактирования модуля в админке:
php//загрузка представления головной части страницы $data['header'] = $this->load->controller('common/header'); //загрузка сайдбара $data['column_left'] = $this->load->controller('common/column_left'); //загрузка подвала админки $data['footer'] = $this->load->controller('common/footer'); //заголовок h1 (но не title) $data['heading_title'] = $this->language->get('heading_title'); $data['button_save'] = $this->language->get('button_save'); $data['settings_edit'] = $this->language->get('settings_edit'); //плейхолдеры для настроек $data['entry_setting1'] = $this->language->get('entry_setting1'); $data['entry_setting2'] = $this->language->get('entry_setting2');
Теперь настройки модуля:
php//получаем массив настроек модуля (ранее мы загружали модель setting/setting) $aModuleInfo = $this->model_setting_setting->getSetting("mymodulesettings"); $data['mymodulesettings_setting1'] = $aModuleInfo["mymodulesettings_setting1"]; $data['mymodulesettings_setting2'] = $aModuleInfo["mymodulesettings_setting2"]; //...
Еще нужны хлебные крошки:
php$data['breadcrumbs'] = []; $data['breadcrumbs'][] = [ 'text' => $this->language->get('text_home'), 'href' => $this->url->link('common/dashboard', 'token=' . $this->session->data['token'], true) ]; $data['breadcrumbs'][] = [ 'text' => $this->language->get('text_extension'), 'href' => $this->url->link('marketplace/extension', 'token=' . $this->session->data['token'] . '&type=module', true) ]; $data['breadcrumbs'][] = [ 'text' => $this->language->get('heading_title'), 'href' => $this->url->link('extension/module/mymodulesettings', 'token=' . $this->session->data['token'], true) ];
В заключение нужно еще добавить ссылку на отправку формы редактирования настроек нашего модуля:
phpif (!array_key_exists('module_id', $this->request->get)) { $data['action'] = $this->url->link('extension/module/mymodulesettings', 'token=' . $this->session->data['token'], true); } else { $data['action'] = $this->url->link('extension/module/mymodulesettings', 'token=' . $this->session->data['token'] . '&module_id=' . $this->request->get['module_id'], true); }
И наконец - все это отправляем в шаблон:
php$this->response->setOutput($this->load->view('extension/module/mymodulesettings', $data));
Метод валидации просто проверяет все входящие данные:
phpprotected function validate() { //... return true; }
К слову, в данном методе можно проверять данные на их наличие, на определенный диапазон, или даже проверять через сторонний сервис, как это надо было в моем случае (там были авторизационные данные стороннего сервиса). Все зависит от конкретной ситуации.
В случае возникновения ошибок метод validate
записывает сообщения об ошибках в массив $this->m_aErrors
.
phppublic function install() { //... }
В данном методе нам нужно создать настройки по умолчанию:
php$this->load->model('setting/setting'); $this->model_setting_setting->editSetting('mymodulesettings', [ 'mymodulesettings_setting1' => '', 'mymodulesettings_setting2' => '', 'mymodulesettings_readonly' => 'dsgf5' ]);
modulename_settingname
Если нужно поработать с базой данных, то внутри каждого контроллера есть объект класса DB
расположенного по пути system/library/db.php
(а по пути system/library/db/
лежат классы-адапторы для конкретной низкой реализации), который доступен как $this->db
.
У этого объекта нас интересуют следующие методы:
query($sql, $params = array())
- выполнить SQL запрос в переменной sql
, подставив параметры из массива params
escape($value)
- экранирует строку запроса value
countAffected()
- возвращает количество строк затронутых последним запросомgetLastId()
- возвращает последний вставленный IDconnected()
- установлено ли соединение с БДДля детального разбора, знакомым с pdo можно посмотреть файл system/library/db/mpdo.php
.
Пример работы с БД можно взять из статьи где мы разбирали создание дополнительного поля в карточке товара.
install
могут устанавливаться обработчики событий.Здесь можно удалить настройки модуля:
php$this->load->model('setting/setting'); $this->model_setting_setting->deleteSetting('mymodulesettings');
А также произвести нужные манипуляция с базой данных через тот же объект $this->db
.
uninstall
должны удаляться все обработчики событий установленные этим модулем.А теперь посмотрим как сделаны другие файлы представления из директории admin/view/template/extension/module/
и частично возьмем оттуда код шаблона.
Создаем файл admin/view/template/extension/module/mymodulesettings.tpl
(не забываем что .tpl для OpenCart 2.3, а для 3.0 .twig), в который помещаем адаптированный код для нашего модуля подсмотренный в других файлах шаблонов :)
Пропустим здесь этот момент (много html), лучше посмотреть файл в репозитории.
В конечном итоге мы смогли собрать простейший модуль с настройками для OpenCart. Не то чтобы это уберполезная инфа, но как минимум она поможет сократить время входа в понимание самых основ движка.
Теперь можно двигаться дальше ...