Пишем свой модуль для OpenCart. Advanced Level

48 мин. на чтение

В предыдущих двух записях, посвященных разработке модулей для OpenCart мы разобрались, как написать достаточно простой модуль на примере счетчика Яндекс.Метрики. Ссылки на 2 части статьи вы найдете в под этим текстом.

Сегодня мы научимся писать что-то более интересное и сложное. Недавно мне пришла задача:

Написать «модуль» для отображения иконок на странице товара, которые были предварительно заданы в админке. Иконки должны задаваться на уровне категорий, т.е. указываются для всех товаров выбранной категории сразу. Так же, у Иконок есть Группы, которые тоже нужно создать и присваивать. Должен задаваться порядок сортировки как Групп, так и Иконок в группах. На странице товаров иконки должны выводиться 2 раза. Сначала просто блоком иконок со всплывающими подсказками, а потом отдельной вкладкой, в которой иконки будут уже отображаться с доп. полями, а именно названием и описанием.

Ну, нас таким не напугаешь. Главное, все продумать сначала, а потом уже делать. Как-то на одном собеседовании на Full-stack Developer меня спросили: «Как бы вы поделили свое рабочее время между обсуждением и программированием». Я ответи «80/20». Т.е. 80% времени уделяется планированию, а 20% – программированию. Мы не говорим про рутинные и простые задачи, а скорее про такие, как эта, где нужно сначала все продумать и построить. Если Вам дали задачу покрасить кнопку – просто покрасьте кнопку :)

Административная часть

Из предыдущих статей Вы уже знаете, что OpenCart это MVC(L) система с признаками фреймворка :) Самое важно на текущем этапе, так это то, что у нее отделены друг от друга Пользовательская и Административная часть. Для такой доработки, как описанная выше разумно начать с Административной части, т.к. многое из того, что вы напишите для Админки с успехом будет использовано для Пользовательской части.

Модель

Начинать все сложные доработки, требующие хранения сущностей в базе данных, я советую именно с Модели. Во-первых, добавление новых таблиц в БД не приводит к ошибкам на самом сайте. Я стараюсь исповедовать такой метод разработки, когда сайт и административная часть доступы всегда, если вы дописали код до какой-то логической точки.

Вернемся к нашей БД. У OpenCart хорошо продуманная система БД (ну, разве что кроме дополнительных фото). Я Вам настоятельно рекомендую не изобретать велосипед при разработке, а следовать стандартам. Для нашего модуля под условия ТЗ я решил создать в БД 5 новых таблиц:

  • Таблица oc_function с полями: function_id, function_group_id, sort_order;
  • Таблица oc_function_description с полями: function_id, language_id, name, description, image;
  • Таблица  oc_function_group с полями: function_group_id и sort_order;
  • Таблица oc_function_group_description с полями function_group_id, language_id, name;
  • Таблица oc_function_to_category с полями function_id и category_id.

Прошу заметить, что такая структура весьма привычна при разработке для OpenCart, если нужно создавать новую Сущность. Если вы достаточно хорошо разбираетесь в MySQL, то для экономии времени я прикладываю архив с sql, в котором не только создана эта структура, но и даже заполнены демо-данные. Обращаю Ваше внимание, что в sql-файле уже присутствуют префиксы таблиц OpenCart, по-умолчанию это oc_.

После импорта у Вас должно получиться так:

Так же в самих таблицах уже имеются какие-то записи для того, чтобы вы не работали с пустыми данными.

Теперь можно написать методы в саму модель, чтобы работать с этими таблицами.

Создадим новый файлик в admin/model/catalog/ и назовем его function.php со следующим содержимым:

Файл может Вас немного напугать, но давайте разберем его на составляющие и Вы поймете, что там ничего сложного нет. Во-первых, перечислим основные Методы, которые мы создали:

  • addFunction($data) – создание новой функции;
  • editFunction($function_id, $data) – обновление (изменение) функции с указанным function_id;
  • deleteFunction($function_id) – удалить функцию с указанным function_id. По идее тут еще должна быть проверка, что удаляемая Функция не присвоена какой-то Категории товаров, но ее тут нет. Если у Вас есть академическое желание, вы можете подсмотреть реализацию этой проверки в других моделях, например, Атрибутов;
  • getFunction($function_id) – получить информацию об функции с ID = function_id;
  • getFunctions($data = array()) – получить список всех функций, массив $data используется для фильтрации данных по каким-то признакам;
  • getFunctionDescriptions($function_id) – получить описание функции с ID = function_id;
  • getTotalFunctions() – возвращает количество всех Функций, можно использовать для Пагинации;
  • getTotalFunctionsByFunctionGroupId($function_group_id) – возвращает количество функций в определенной Групы по function_group_id;

В базовом варианте вам вполне хватит первых 6 методов для успешной работы модуля. Два оставшихся используются для Пагинации и не являются обязательными.

Теперь нужно создать Модель для обработки Категорий наших Функций.

Создадим новый файлик в admin/model/catalog/ и назовем его function_group.php со следующим содержимым:

Как и в предыдущем случае, рассмотрим Методы, которые мы создали:

  • addFunctionGroup($data) – создает новую Группу Функций;
  • editFunctionGroup($function_group_id, $data) – изменяет (обновляет_ Группу Функций с заданным function_id;
  • deleteFunctionGroup($function_group_id) – удаляет Группу Функций с заданным ID;
  • getFunctionGroup($function_group_id) – скажем так, этим Методом можно проверить существование Группы. Для этого в OpenCart есть специальный метод драйвера БД $variable_after_query->num_rows, но об этом поговорим в пользовательской части.
  • getFunctionGroups($data = array()) – возвращает список Групп Функций, поддерживает сортировки и фильт через массив $data;
  • getFunctionGroupDescriptions($function_group_id) – возвращает описание Группы Функции.
  • getTotalFunctionGroups() – необязательный Метод, применим для Пагинации.

На этом создание Модели для административной части нашей доработки можно считать законченным. Я на самом деле создавал Методы поэтапно, но воспроизвести весь этот «тернистый путь» в рамках и так не простой статьи считаю излишеством. Если у Вас по прочтению статьи останутся вопросы, вы всегда можете задать их в комментариях.

Контроллер, Язык и Представление

Следующим логичным шагом будет конечно же создание остальной части нашего модуля. Давайте создадим языковый файл. Для этого в admin/language/ru-ru/catalog/ создадим два файла function.php и function_group.php

Листинг function.php

Листинг function_group.php

Также, нужно добавить в Языковый файл главного меню две записи для корректного вывода названий нашего модуля, для этого в admin/language/ru-ru/common/column_left.php добавить

$_['text_function'] = 'Функции';
$_['text_function_group'] = 'Группы функций';

Собственно, можно перейти к святая святых любого MVC – Контроллеру. Создадим в admin/controller/catalog/ два файла function.php и function_group.php

Листинг function.php

Как и в случае с Моделью, Контроллер выглядит устрашающим только при первом взгляде. Он насыщен стандартными конструкциями, такими как хлебные крошки, обработка методов POST, GET значений переменных и пр. У нас присутствуют следующие Методы:

  • index() (совмещен с getList() ) – обрабатывается при запросе admin/index.php?route=catalog/function и возвращает список всех имеющихся Функций. Поддерживает фильтр через GET запросы. Поддерживает Пагинацию, если вы в Моделе указали все Методы;
  • add() (совмещен с getForm() и validateForm() ) – создает новую Функцию после успешного выполнение метода validateForm();
  • edit() (совмещен с getForm() и validateForm() ) – изменяет (обновляет) новую Функцию после успешного выполнение метода validateForm();
  • delete() (совмещен с getList() и validateForm() ) – удаляет заданную Функцию из списка Функций. Как уже было сказано, тут должна быть еще валидация на привязку Функции к Категории товаров, но она не написана, подсмотреть можно у контроллера Атрибутов;
  • getList() — вынесенный отдельно Метод для работы со списком Функций. Т.к. компоненты Метода используются в нескольких других Методах, было вполне уместно создать отдельный Метод вместо избыточного кода;
  • getForm() – аналогично getList(), но уже для работы с формой добавления и удаления Функции;
  • validateForm() – достаточно обычный валидатор формы в OpenCart. Проверяет, что у Пользователя есть права на изменения этого Контроллера, проверяет длину полей у Функции;
  • validateDelete() – не дописанный и не используемый Метод валидации при удалении Функции. Должен проверять права Пользователя и что удаляемая Функция не имеет привязки к Категории товаров. Теоретически, можно написать Метод в Модели, который будет удалять привязку Функций к Категориям. Именно поэтому мы не храним список Функций и Групп Функций в каком-нибудь формате json, а каждую привязку отдельно в своей таблице.
  • autocomplete() – не используемая функция для фильтра в списке Функций. Можете дописать на свое усмотрение.

Листинг function_group.php

Методы этого Контроллера очень похожи на function.php, поэтому не вижу особого смысла останавливаться подробно на каждом из них.

Нам осталось написать всего чуть-чуть:

  • Представления для Функций и Групп Функций
  • Добавить ссылки на Контроллеры в главное меню админки
  • Дать разрешения Пользователю на просмотр и редактирование новых Контроллеров

Терпение и Вы увидите, какая красота у нас получилась!

Т.к. у нас у обоих контроллеров есть Методы отвечающие как за списки так и за формы, то и Представлений получается 4 шт. Создадим в admin/view/template/catalog/ файлы:

  • function_form.tpl;
  • function_list.tpl;
  • function_group_form.tpl;
  • function_group_list.tpl.

Листинги файлов будут в этом архиве. Ничего особенно в них нет, поэтому можно просто скопировать в папку.

Добавим вывод нашего нового Модуля в главное меню и добавим текущему Пользователю права на просмотр и редактирование новых Контроллеров.

Идем в admin/controller/common/column_left.php и скажем после:

// Attributes
			$attribute = array();
			
			if ($this->user->hasPermission('access', 'catalog/attribute')) {
				$attribute[] = array(
					'name'     => $this->language->get('text_attribute'),
					'href'     => $this->url->link('catalog/attribute', 'token=' . $this->session->data['token'], true),
					'children' => array()	
				);
			}
			
			if ($this->user->hasPermission('access', 'catalog/attribute_group')) {
				$attribute[] = array(
					'name'	   => $this->language->get('text_attribute_group'),
					'href'     => $this->url->link('catalog/attribute_group', 'token=' . $this->session->data['token'], true),
					'children' => array()		
				);
			}
			
			if ($attribute) {
				$catalog[] = array(
					'name'	   => $this->language->get('text_attribute'),
					'href'     => '',
					'children' => $attribute
				);
			}

Добавляем:

// Function Daikin
			$function = array();
			
			if ($this->user->hasPermission('access', 'catalog/function_group')) {
				$function[] = array(
					'name'     => $this->language->get('text_function'),
					'href'     => $this->url->link('catalog/function', 'token=' . $this->session->data['token'], true),
					'children' => array()	
				);
			}
			
			if ($this->user->hasPermission('access', 'catalog/function_group')) {
				$function[] = array(
					'name'	   => $this->language->get('text_function_group'),
					'href'     => $this->url->link('catalog/function_group', 'token=' . $this->session->data['token'], true),
					'children' => array()		
				);
			}
			
			if ($function) {
				$catalog[] = array(
					'name'	   => $this->language->get('text_function'),
					'href'     => '',
					'children' => $function
				);
			}

Ну и выставим права нашему Пользователю, для этого идем в Админке в Система -> Группы пользователей. Находим вашу группу (обычно, это Administrator) и добавляем права на Контроллеры: catalog/function и catalog/function_group

Несколько скринов для оценки красоты:

Демо

https://oc.netsh.pp.ua/admin/

demo/demo

 

Архив со всеми файлами в правильной структуре + иконки: Custom_module

В следущей части статьи создадим привязку нашего модуля к Категориям и напишем пользовательскую часть модуля.

1 Комментарий

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *