Opencart 2.x - Как Создать Пользовательский Модуль - 2 Часть

Тема в разделе "Модули и дополнения", создана пользователем admin, 18 фев 2018.

  1. TopicStarter Overlay
    Offline

    admin Команда форума Администратор

    Сообщения:
    2.638
    Симпатии:
    117.823
    Репутация:
    205
    в первой статье мы создали модуль Recent Products, который показывает Х количество товаров на стороне front-end’а. Количество отображаемых товаров можно настроить через back-end форму конфигураций, которую мы создали в первой части. Также мы разобрались с архитектурой модулей в OpenCart. Данная архитектура применяется и к front-end части модуля.

    Быстрый обзор
    Как уже говорилось ранее, в этом уроке мы создадим файлы front-end стороны плагина. Давайте взглянем на список файлов.

    catalog/language/english/module/recent_products.php: файл со статическими заголовками, которые используются на front-end стороне.

    catalog/controller/module/recent_products.php: файл контроллера с логикой приложения нашего модуля.

    catalog/model/module/recent_products.php: файл модели, взаимодействующий с базой данных для получения товаров.

    catalog/view/theme/default/template/module/recent_products.tpl: шаблон представления с XHTML кодом.

    Первым делом вы заметите, что в отличие от директории admin, тут используется папка catalog, в которой хранятся файлы плагина на front-end стороне. Также есть файл модели, который не создавался для back-end’а и хранит программный код нашего плагина, чтобы вытягивать недавние товары из базы данных.

    Другая вещь, на которую нужно обратить внимание – расположение файла представления recent_products.tpl. На самом деле, на стороне front-end’а у вас может быть несколько тем, и файл будет храниться в папке темы. У нас указан путь к теме по умолчанию в OpenCart, по которому хранится большая часть файлов шаблонов. Во всем остальном структура плагина такая же, в ней есть файл языка и контроллера.

    Создаем файлы плагина
    Первым делом создадим файл языка catalog/language/english/module/recent_products.php с кодом.

    Код:
    <?php
    // catalog/language/english/module/recent_products.php
    // Заголовок
    $_['heading_title'] = 'Recent Products';
    Файл используется для установки статичных заголовков, которые будут использоваться в файле шаблона представления. Файл почти идентичен файлу языка из админки.

    Теперь давайте создадим файл контроллера, который должен находиться по адресу catalog/controller/module/recent_products.php.

    Код:
    <?php
    // catalog/controller/module/recent_products.php
    class ControllerModuleRecentProducts extends Controller {
    public function index($setting) {
    $this->load->language('module/recent_products');
    $data['heading_title'] = $this->language->get('heading_title');
    $this->load->model('module/recent_products');
    $this->load->model('tool/image');
    $data['products'] = array();
    $results = $this->model_module_recent_products->getRecentProducts( $setting['limit'] );
    if ($results) {
    foreach ($results as $result) {
    if ($result['image']) {
    $image = $this->model_tool_image->resize( $result['image'], 100, 100 );
    } else {
    $image = $this->model_tool_image->resize( 'placeholder.png', 100, 100 );
    }
    if ( ( $this->config->get('config_customer_price') && $this->customer->isLogged() ) || !$this->config->get( 'config_customer_price' ) ) {
    $price = $this->currency->format( $this->tax->calculate($result['price'], $result['tax_class_id'], $this->config->get('config_tax')) );
    } else {
    $price = false;
    }
    if ((float)$result['special']) {
    $special = $this->currency->format( $this->tax->calculate( $result['special'], $result['tax_class_id'], $this->config->get('config_tax') ) );
    } else {
    $special = false;
    }
    $data['products'][] = array(
    'product_id'  => $result['product_id'],
    'thumb' => $image,
    'name' => $result['name'],
    'description' => utf8_substr( strip_tags( html_entity_decode($result['description'], ENT_QUOTES, 'UTF-8') ), 0, $this->config->get( 'config_product_description_length' ) ) . '..',
    'price' => $price,
    'special' => $special,
    'href' => $this->url->link('product/product', 'product_id=' . $result['product_id'])
    );
    }
    if (file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/recent_products.tpl')) {
    return $this->load->view( $this->config->get('config_template') . '/template/module/recent_products.tpl', $data );
    } else {
    return $this->load->view( 'default/template/module/recent_products.tpl', $data );
    }
    }
    }
    }
    Опять же, в методе index хранится большая часть нашего кода. В большинстве плагинов в методе index вам встретится аргумент $setting. Вспомните форму настроек в админке из первого урока, которая нужна для настройки параметров плагина – это и есть переменная $setting. В ней в виде массива хранятся значения настроек плагина для формы.

    Сокращение $this->load->language загружает файл языка с front-end стороны, который подробно мы разобрали в первом уроке. Точно так же $this->load->model загружает модель плагина, которая хранится по адресу catalog/model/module/recent_products.php. Также мы подгружаем модель Image из папки tool, в ней есть метод для изменения размера изображений.

    Самый важный вызов в методе index – вызов метода getRecentProducts, который возвращает из базы данных массив недавно просмотренных товаров. Когда будем разбирать файл модели, мы разберем его более подробно. В качестве аргумента методу передается значение $setting['limit'], которое определяется на стороне back-end’а.

    Код:
    $results = $this->model_module_recent_products->getRecentProducts( $setting['limit'] );
    Затем мы проходимся по массиву товаров и подготавливаем массив $data['products'], который будем использовать в файле шаблона. В процессе подготовки массива мы используем метод для изменения размера изображений из модели Image и создаем с его помощью маленькие изображения. Большие изображения на front-end’е показывать нет смысла.

    Также вы заметите $this->config->get – данная строка используется для вытягивания глобальных значений настроек магазина. Изменить эти параметры можно в System > Settings.

    Сокращение $this->url->link создает SEO дружелюбные ссылки на страницы товаров. И наконец, идет кусок кода, загружающий файл шаблона recent_products.tpl, в котором данные подготавливаются к выводу при помощи массива $data.
    В отличие от админки, на front-end стороне есть условие загрузки файла шаблона, так как вы можете использовать тему не по умолчанию. Если у вас тем нет, всегда используется тема по умолчанию в качестве фолбэка.

    Код:
    if ( file_exists(DIR_TEMPLATE . $this->config->get('config_template') . '/template/module/recent_products.tpl') ) {
    return $this->load->view( $this->config->get('config_template') . '/template/module/recent_products.tpl', $data );
    } else {
    return $this->load->view( 'default/template/module/recent_products.tpl', $data );
    }
    С файлом контроллера закончили. Теперь давайте создадим файл модели catalog/model/module/recent_products.php.

    Код:
    <?php
    // catalog/model/module/recent_products.php
    class ModelModuleRecentProducts extends Model {
    public function getRecentProducts($limit) {
    $this->load->model('catalog/product');
    $product_data = $this->cache->get( 'product.recent.' . (int)$this->config->get('config_language_id') . '.' . (int)$this->config->get('config_store_id') . '.' . $this->config->get('config_customer_group_id') . '.' . (int)$limit );
    if (!$product_data) {
    $query = $this->db->query("SELECT p.product_id FROM " . DB_PREFIX . "product p LEFT JOIN " . DB_PREFIX . "product_to_store p2s ON (p.product_id = p2s.product_id) WHERE p.status = '1' AND p.date_available <= NOW() AND p2s.store_id = '" . (int)$this->config->get('config_store_id') . "' ORDER BY p.date_added DESC LIMIT " . (int)$limit);
    foreach ($query->rows as $result) {
    $product_data[$result['product_id']] = $this->model_catalog_product->getProduct( $result['product_id'] );
    }
    $this->cache->set( 'product.recent.' . (int)$this->config->get('config_language_id') . '.' . (int)$this->config->get('config_store_id') . '.' . $this->config->get('config_customer_group_id') . '.' . (int)$limit, $product_data );
    }
    return $product_data;
    }
    }
    По коду видно, что класс модели начинается с ключевого слова Model, и затем указывается структура папок. Класс наследует все от класса Model, в котором хранятся объекты и методы для взаимодействия с базой данных.

    Также мы загружаем модель Product из папки catalog при помощи $this->load->model(‘catalog/product’). Нам понадобятся методы из этого класса.

    Есть еще пара полезных сокращений — $this->cache->set и $this->cache->get. Первое используется для записи значения в кэш, а второе получает уже записанное значение из кэша по ключу. Хорошая привычка использовать кэш для увеличения производительности магазина.

    В конце мы выполняем запрос к базе данных и вытягиваем недавние товары при помощи строки $this->db->query. Строка запускает метод query класса database.

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

    Осталось создать файл шаблона recent_products.tpl. Создадим его в папке catalog/view/theme/default/template/module/recent_products.tpl.

    Код:
    <!-- catalog/view/theme/default/template/module/recent_products.tpl -->
    <h3><?php echo $heading_title; ?></h3>
    <div class="row">
      <?php foreach ($products as $product) { ?>
      <div class="product-layout col-lg-3 col-md-3 col-sm-6 col-xs-12">
    <div class="product-thumb transition">
    <div class="image"><a href="<?php echo $product['href']; ?>"><img src="<?php echo $product['thumb']; ?>" alt="<?php echo $product['name']; ?>" title="<?php echo $product['name']; ?>" class="img-responsive" /></a></div>
    <div class="caption">
    <h4><a href="<?php echo $product['href']; ?>"><?php echo $product['name']; ?></a></h4>
    <p><?php echo $product['description']; ?></p>
    <?php if ($product['price']) { ?>
    <p class="price">
    <?php if (!$product['special']) { ?>
    <?php echo $product['price']; ?>
    <?php } else { ?>
    <span class="price-new"><?php echo $product['special']; ?></span> <span class="price-old"><?php echo $product['price']; ?></span>
    <?php } ?>
    </p>
    <?php } ?>
    </div>
    </div>
      </div>
      <?php } ?>
    </div>
    В файле шаблона мы просто пробегаемся по массиву $products, который был передан из контроллера и выводим список товаров в XHTML.

    С front-end файлами закончили! В следующем разделе я покажу вам, как прикрепить наш плагин к макету OpenCart, чтобы он показывался на стороне front-end’а.

    Прикрепляем плагин к макету
    Любой плагин, который что-то показывает на front-end стороне, необходимо привязать к свободному макету. Для примера мы привяжем плагин к позиции Content Top.

    Перейдите в панель администратора в System > Design > Layouts. Должны отобразиться все доступные макеты магазина. Перейдите в режим редактирования макета Home. Необходимо просто добавить новый модуль, как показано на скриншоте ниже.

    1.png

    Как видите, мы взяли Recent Products > My Recent Block Plugin и прикрепили его к позиции Content Top. Сохраните изменения и все!

    Front-end демо
    Перейдите на сторону front-end’а, должен появиться красивый блок с недавно просмотренными товарами, как на скриншоте ниже.

    2.png

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

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