Статьи

Создайте пользовательский плагин в OpenCart 2.1.xx: часть первая

Как разработчику, всегда интересно создавать собственные компоненты в любой среде, и то же самое относится и к плагинам OpenCart.

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

В этой первой части мы создадим пользовательский плагин, который отображает последние продукты в интерфейсе магазина, и вы сможете настроить количество продуктов из самого конца. В этом и заключается цель этой статьи — разработать внутренний плагин с формой конфигурации.

Я предполагаю, что вы установили последнюю версию OpenCart, которая на момент написания этой статьи была 2.1.0.2. Прежде чем мы продолжим разработку реального плагина, я познакомлю вас с базовой архитектурой плагина OpenCart в следующем разделе.

OpenCart разработан с использованием одного из самых популярных шаблонов веб-разработки, шаблона MVC, с небольшим изменением, или, скорее, я бы сказал, что это дополнение. Дополнение в форме языкового компонента, который делает его MVCL в мире OpenCart. Возможно, вы слышали об этом паттерне, но ради новичков я быстро подведу итоги.

М в MVC обозначает модель, и именно здесь находится большая часть бизнес-логики. В контексте OpenCart это модель, которая взаимодействует со слоем абстракции базы данных, чтобы выполнить всю тяжелую работу, необходимую для запуска магазина. Это область, где вы большую часть времени окажетесь разработчиком.

Далее, V обозначает View, и он представляет уровень представления приложения. Как следует из названия, он имеет дело только с логикой представления любой страницы, и он получает входные данные от других слоев и генерирует выходные данные XHTML большую часть времени. Бизнес-логика приложения должна быть удалена от этого уровня; следует беспокоиться только о том, что делать, а не как это делать.

Это C, контроллер в MVC, который стоит перед всем, обрабатывает каждый запрос и обрабатывает его соответствующим образом. Это область, которая включает в себя большую часть логики приложения — от обработки и проверки пользовательского ввода до загрузки правильной модели и просмотра компонентов для подготовки вывода страницы.

Наконец, есть дополнительный компонент L, который обозначает язык. Это делает настройку многоязычных сайтов проще простого.

Итак, это быстрый взгляд на архитектуру OpenCart, и он будет иметь больше смысла, когда мы перейдем к подробному объяснению каждого компонента.

Давайте кратко рассмотрим список файлов, которые нам нужно реализовать для пользовательского внутреннего плагина.

  • admin/language/english/module/recent_products.php : это файл, который содержит статические метки, используемые в области приложения администратора.
  • admin/controller/module/recent_products.php : это файл контроллера, который содержит логику приложения нашего модуля.
  • admin/view/template/module/recent_products.tpl : это файл шаблона представления и содержит код XHTML.

В следующем разделе мы создадим каждый файл, упомянутый выше, с подробным объяснением.

Согласно соглашениям, мы должны поместить файлы пользовательских плагинов в каталог модуля . В этом случае, когда мы разрабатываем внутренний плагин, наши каталоги будут содержать каталоги с правами администратора . Конечно, файлы распределены по разным каталогам, или, скорее, компонентам, в соответствии с архитектурой OpenCart, показанной выше.

В этом разделе мы начнем создавать файлы модуля. Сначала мы создадим языковой файл admin/language/english/module/recent_products.php со следующим содержимым. Это важный файл с точки зрения OpenCart, так как он необходим для обнаружения вашего плагина OpenCart.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<?php
// admin/language/english/module/recent_products.php
// Heading
$_[‘heading_title’] = ‘Recent Products’;
 
// Text
$_[‘text_module’] = ‘Modules’;
$_[‘text_success’] = ‘Success: You have modified Recent Products module!’;
$_[‘text_edit’] = ‘Edit Recent Products Module’;
 
// Entry
$_[‘entry_name’] = ‘Module Name’;
$_[‘entry_limit’] = ‘Limit’;
$_[‘entry_status’] = ‘Status’;
 
// Error
$_[‘error_permission’] = ‘Warning: You do not have permission to modify Recent Products module!’;
$_[‘error_name’] = ‘Module Name must be between 3 and 64 characters!’;

Как видите, мы присваиваем статические метки массиву PHP. Позже вы получите доступ к этим переменным в файле шаблона представления, поскольку массив преобразуется в переменные PHP.

Возможно, вы также заметили, что файл создается в английском каталоге, так как это язык по умолчанию для магазина. Конечно, в случае многоязычного сайта вам необходимо убедиться, что вы создаете его и для других языков. Например, французская версия того же файла должна быть создана по адресу admin/language/french/module/recent_products.php .

Далее мы создадим один из самых важных файлов плагинов — файл контроллера. Давайте продолжим и создадим admin/controller/module/recent_products.php со следующим содержимым.

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<?php
// admin/controller/module/recent_products.php
class ControllerModuleRecentProducts extends Controller {
    private $error = array();
 
    public function index() {
        $this->load->language(‘module/recent_products’);
 
        $this->document->setTitle($this->language->get(‘heading_title’));
 
        $this->load->model(‘extension/module’);
 
        if (($this->request->server[‘REQUEST_METHOD’] == ‘POST’) && $this->validate()) {
            if (!isset($this->request->get[‘module_id’])) {
                $this->model_extension_module->addModule(‘recent_products’, $this->request->post);
            } else {
                $this->model_extension_module->editModule($this->request->get[‘module_id’], $this->request->post);
            }
 
            $this->session->data[‘success’] = $this->language->get(‘text_success’);
 
            $this->response->redirect($this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’));
        }
 
        $data[‘heading_title’] = $this->language->get(‘heading_title’);
 
        $data[‘text_edit’] = $this->language->get(‘text_edit’);
        $data[‘text_enabled’] = $this->language->get(‘text_enabled’);
        $data[‘text_disabled’] = $this->language->get(‘text_disabled’);
 
        $data[‘entry_name’] = $this->language->get(‘entry_name’);
        $data[‘entry_limit’] = $this->language->get(‘entry_limit’);
        $data[‘entry_status’] = $this->language->get(‘entry_status’);
 
        $data[‘button_save’] = $this->language->get(‘button_save’);
        $data[‘button_cancel’] = $this->language->get(‘button_cancel’);
 
        if (isset($this->error[‘warning’])) {
            $data[‘error_warning’] = $this->error[‘warning’];
        } else {
            $data[‘error_warning’] = »;
        }
 
        if (isset($this->error[‘name’])) {
            $data[‘error_name’] = $this->error[‘name’];
        } else {
            $data[‘error_name’] = »;
        }
 
        $data[‘breadcrumbs’] = array();
 
        $data[‘breadcrumbs’][] = array(
            ‘text’ => $this->language->get(‘text_home’),
            ‘href’ => $this->url->link(‘common/dashboard’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
        );
 
        $data[‘breadcrumbs’][] = array(
            ‘text’ => $this->language->get(‘text_module’),
            ‘href’ => $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
        );
 
        if (!isset($this->request->get[‘module_id’])) {
            $data[‘breadcrumbs’][] = array(
                ‘text’ => $this->language->get(‘heading_title’),
                ‘href’ => $this->url->link(‘module/recent_products’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
            );
        } else {
            $data[‘breadcrumbs’][] = array(
                ‘text’ => $this->language->get(‘heading_title’),
                ‘href’ => $this->url->link(‘module/recent_products’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’)
            );
        }
 
        if (!isset($this->request->get[‘module_id’])) {
            $data[‘action’] = $this->url->link(‘module/recent_products’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);
        } else {
            $data[‘action’] = $this->url->link(‘module/recent_products’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’);
        }
 
        $data[‘cancel’] = $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’);
 
        if (isset($this->request->get[‘module_id’]) && ($this->request->server[‘REQUEST_METHOD’] != ‘POST’)) {
            $module_info = $this->model_extension_module->getModule($this->request->get[‘module_id’]);
        }
 
        if (isset($this->request->post[‘name’])) {
            $data[‘name’] = $this->request->post[‘name’];
        } elseif (!empty($module_info)) {
            $data[‘name’] = $module_info[‘name’];
        } else {
            $data[‘name’] = »;
        }
 
        if (isset($this->request->post[‘limit’])) {
            $data[‘limit’] = $this->request->post[‘limit’];
        } elseif (!empty($module_info)) {
            $data[‘limit’] = $module_info[‘limit’];
        } else {
            $data[‘limit’] = 5;
        }
 
        if (isset($this->request->post[‘status’])) {
            $data[‘status’] = $this->request->post[‘status’];
        } elseif (!empty($module_info)) {
            $data[‘status’] = $module_info[‘status’];
        } else {
            $data[‘status’] = »;
        }
 
        $data[‘header’] = $this->load->controller(‘common/header’);
        $data[‘column_left’] = $this->load->controller(‘common/column_left’);
        $data[‘footer’] = $this->load->controller(‘common/footer’);
 
        $this->response->setOutput($this->load->view(‘module/recent_products.tpl’, $data));
    }
 
    protected function validate() {
        if (!$this->user->hasPermission(‘modify’, ‘module/recent_products’)) {
            $this->error[‘warning’] = $this->language->get(‘error_permission’);
        }
 
        if ((utf8_strlen($this->request->post[‘name’]) < 3) || (utf8_strlen($this->request->post[‘name’]) > 64)) {
            $this->error[‘name’] = $this->language->get(‘error_name’);
        }
 
        return !$this->error;
    }
}

Он определяет новый класс для нашего пользовательского плагина, который расширяет базовый класс Controller . Согласно соглашениям, имя класса должно имитировать структуру каталогов, в которой находится файл. Таким образом, путь controller/module/recent_products.php преобразуется в ControllerModuleRecentProducts путем замены символов косой черты и подчеркивания в соответствии с соглашением о верблюжьем регистре!

Далее, существует метод index de-facto, который вызывается, когда плагин загружается во внешний интерфейс. Итак, это метод индекса, который определяет большую часть логики приложения плагина.

В контексте текущего приложения сокращение $this->load->language загружает соответствующий языковой файл. В нашем случае он загружает языковой файл, определенный в предыдущем разделе. Синтаксис довольно прост — вам просто нужно передать имя плагина с префиксом module/ . Языковые переменные могут быть доступны с помощью метода $this->language->get .

Затем он устанавливает заголовок страницы с помощью метода setTitle объекта документа.

В дальнейшем, сокращенная $this->load->model используется для загрузки модели модуля. Это класс модели, который предоставляет служебные методы для сохранения параметров модуля и тому подобного.

После этого, как показано ниже, есть важный фрагмент, который проверяет, является ли это отправка данных POST, и сохраняет конфигурацию модуля в этом случае.

01
02
03
04
05
06
07
08
09
10
if (($this->request->server[‘REQUEST_METHOD’] == ‘POST’) && $this->validate()) {
    if (!isset($this->request->get[‘module_id’])) {
        $this->model_extension_module->addModule(‘recent_products’, $this->request->post);
    } else {
        $this->model_extension_module->editModule($this->request->get[‘module_id’], $this->request->post);
    }
 
    $this->session->data[‘success’] = $this->language->get(‘text_success’);
    $this->response->redirect($this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’));
}

Кроме того, мы присваиваем языковые метки, такие как heading_title и text_edit $data чтобы мы могли использовать их в файле шаблона представления.

После этого есть фрагмент, который строит правильные ссылки для страницы конфигурации.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$data[‘breadcrumbs’] = array();
 
$data[‘breadcrumbs’][] = array(
    ‘text’ => $this->language->get(‘text_home’),
    ‘href’ => $this->url->link(‘common/dashboard’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);
 
$data[‘breadcrumbs’][] = array(
    ‘text’ => $this->language->get(‘text_module’),
    ‘href’ => $this->url->link(‘extension/module’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
);
 
if (!isset($this->request->get[‘module_id’])) {
    $data[‘breadcrumbs’][] = array(
        ‘text’ => $this->language->get(‘heading_title’),
        ‘href’ => $this->url->link(‘module/recent_products’, ‘token=’ . $this->session->data[‘token’], ‘SSL’)
    );
} else {
    $data[‘breadcrumbs’][] = array(
        ‘text’ => $this->language->get(‘heading_title’),
        ‘href’ => $this->url->link(‘module/recent_products’, ‘token=’ . $this->session->data[‘token’] . ‘&module_id=’ . $this->request->get[‘module_id’], ‘SSL’)
    );
}

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

1
2
3
if (isset($this->request->get[‘module_id’]) && ($this->request->server[‘REQUEST_METHOD’] != ‘POST’)) {
    $module_info = $this->model_extension_module->getModule($this->request->get[‘module_id’]);
}

Наконец, мы загружаем общие элементы страницы, такие как верхний и нижний колонтитулы и левая боковая панель Кроме того, это сокращенная recent_products.tpl $this->load->view которая загружает фактический файл view recent_products.tpl и отображает форму конфигурации.

В файле контроллера нужно запомнить несколько важных замечаний. Вы увидите множество вызовов, таких как $this->load->ELEMENT , где ELEMENT может быть представлением, моделью или языком. Загружает соответствующий вид, модель и языковые компоненты.

Следующий и последний файл для сегодняшней статьи — это файл шаблона представления admin/view/template/module/recent_products.tpl . Идите и создайте это!

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<!— admin/view/template/module/recent_products.tpl —>
<?php echo $header;
<div id=»content»>
  <div class=»page-header»>
    <div class=»container-fluid»>
      <div class=»pull-right»>
        <button type=»submit» form=»form-recent-products» data-toggle=»tooltip» title=»<?php echo $button_save; ?>» class=»btn btn-primary»><i class=»fa fa-save»></i></button>
        <a href=»<?php echo $cancel; ?>» data-toggle=»tooltip» title=»<?php echo $button_cancel; ?>» class=»btn btn-default»><i class=»fa fa-reply»></i></a></div>
      <h1><?php echo $heading_title;
      <ul class=»breadcrumb»>
        <?php foreach ($breadcrumbs as $breadcrumb) { ?>
        <li><a href=»<?php echo $breadcrumb[‘href’]; ?>»><?php echo $breadcrumb[‘text’];
        <?php } ?>
      </ul>
    </div>
  </div>
  <div class=»container-fluid»>
    <?php if ($error_warning) { ?>
    <div class=»alert alert-danger»><i class=»fa fa-exclamation-circle»></i> <?php echo $error_warning;
      <button type=»button» class=»close» data-dismiss=»alert»>&times;</button>
    </div>
    <?php } ?>
    <div class=»panel panel-default»>
      <div class=»panel-heading»>
        <h3 class=»panel-title»><i class=»fa fa-pencil»></i> <?php echo $text_edit;
      </div>
      <div class=»panel-body»>
        <form action=»<?php echo $action; ?>» method=»post» enctype=»multipart/form-data» id=»form-recent-products» class=»form-horizontal»>
          <div class=»form-group»>
            <label class=»col-sm-2 control-label» for=»input-name»><?php echo $entry_name;
            <div class=»col-sm-10″>
              <input type=»text» name=»name» value=»<?php echo $name; ?>» placeholder=»<?php echo $entry_name; ?>» id=»input-name» class=»form-control» />
              <?php if ($error_name) { ?>
              <div class=»text-danger»><?php echo $error_name;
              <?php } ?>
            </div>
          </div>
          <div class=»form-group»>
            <label class=»col-sm-2 control-label» for=»input-limit»><?php echo $entry_limit;
            <div class=»col-sm-10″>
              <input type=»text» name=»limit» value=»<?php echo $limit; ?>» placeholder=»<?php echo $entry_limit; ?>» id=»input-limit» class=»form-control» />
            </div>
          </div>
          <div class=»form-group»>
            <label class=»col-sm-2 control-label» for=»input-status»><?php echo $entry_status;
            <div class=»col-sm-10″>
              <select name=»status» id=»input-status» class=»form-control»>
                <?php if ($status) { ?>
                <option value=»1″ selected=»selected»><?php echo $text_enabled;
                <option value=»0″><?php echo $text_disabled;
                <?php } else { ?>
                <option value=»1″><?php echo $text_enabled;
                <option value=»0″ selected=»selected»><?php echo $text_disabled;
                <?php } ?>
              </select>
            </div>
          </div>
        </form>
      </div>
    </div>
  </div>
</div>
<?php echo $footer;

Пользователи с острыми глазами уже заметили, что это просто отображение переменных, которые были переданы из файла контроллера. Кроме этого, это простой XHTML-код для отображения формы конфигурации, а главное в том, что он адаптивный из коробки.

Вот и все, что касается настройки файла для нашего пользовательского плагина.

Перейдите на задний план OpenCart и перейдите к Расширения> Модули . Вы должны увидеть последние продукты в списке. Нажмите на знак +, чтобы установить модуль, как показано на следующем снимке экрана.

Back-End Listing

После установки вы увидите значок редактирования. Нажмите на это, чтобы открыть форму конфигурации модуля.

Configuration Form

В форме конфигурации вы можете указать количество последних продуктов, которые вы хотите показать в блоке переднего плана. Кроме того, не забудьте установить в поле состояния « Включено» ! Сохраните модуль, и он должен выглядеть примерно так.

Replicated Module

Для модуля есть новая запись « Недавние продукты> Мой недавний блочный плагин» . Причина в том, что вы можете повторить его несколько раз для разных страниц!

Итак, мы почти закончили! Мы сделали полноценный пользовательский плагин в OpenCart. В следующей части мы рассмотрим его внешний интерфейс, который отображает симпатичный блок продуктов во внешнем интерфейсе!

Сегодня мы обсудили разработку пользовательских плагинов в OpenCart. В первой части этой серии, состоящей из двух частей, мы прошли разработку внутреннего плагина и создали работающий пользовательский плагин, который предоставляет форму конфигурации.

Если вы ищете дополнительные инструменты OpenCart, утилиты, расширения и т. Д., Которые вы можете использовать в своих собственных проектах или для собственного образования, посмотрите, что у нас есть на рынке .

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