Особенности разработки multistore модулей

Опубликовано Опубликовано в рубрике prestashop, Руководство разработчика PrestaShop, Русская документация PrestaShop 1.6, Создание модулей PrestaShop

Особенности разработки multistore модулей

Использование конфигурационных переменных

Как указано в разделе «Конфигурация модуля», некоторые из методов объекта Configuration имеют три необязательных параметра, которые позволяют настроить таргетинг на любое существующее хранилище на текущей установке PrestaShop: id_shopid_shop_group и id_lang.

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

В тех немногих случаях, когда вам нужно применить новое значение к той же переменной  Configuration для всех существующих магазинов, используя метод Configuration::updateGlobalValue('myVariable', 'myValue') . Затем вы можете получить это значение для текущего хранилища, используя метод Configuration::get('myVariable') .

Обработка изображений и других типов файлов

Изображения могут быть определены для каждого хранилища или для каждой группы магазинов: элемент может иметь изображение по умолчанию в установке PrestaShop и другое изображение для определенного хранилища.

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

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

Вот как он сохраняет файл:

Сохранение файла на основе хранилища
{
  // Saving only the main portion of the uploaded file's name, without the file extension.
  Configuration::updateValue(
    'BLOCKADVERT_IMG_EXT',
    substr($_FILES['adv_img']['name'], strrpos($_FILES['adv_img']['name'], '.') + 1)
    );
                    
  // Setting the image's name with a name contextual to the shop context.
  $this->adv_imgname = 'advertising';
  // Creating two versions of the image name, depending on the store context:
  // If the context is the current group, use the image named 'advertising-g'
  // If the context is the current store, use the image named 'advertising-s'
  if (Shop::getContext() == Shop::CONTEXT_GROUP)
    $this->adv_imgname = 'advertising'.'-g'.(int)$this->context->shop->getContextShopGroupID();
  elseif (Shop::getContext() == Shop::CONTEXT_SHOP)
    $this->adv_imgname = 'advertising'.'-s'.(int)$this->context->shop->getContextShopID();
  // Copying the image in the module directory with its new contextual name.
  if (!move_uploaded_file($_FILES['adv_img']['tmp_name'],
    _PS_MODULE_DIR_.$this->name.'/'.$this->adv_imgname.'.'.Configuration::get('BLOCKADVERT_IMG_EXT')))
    $errors .= $this->l('File upload error.');
}

И вот как он решает, какое изображение показать, в зависимости от контекста:

Загрузка файла для каждого магазина
protected function initialize()
{
  // Setting the main name of the image.
  $this->adv_imgname = 'advertising';
  // Setting the contextual name of the file, depending on the context.
  if ((Shop::getContext() == Shop::CONTEXT_GROUP  || Shop::getContext() == Shop::CONTEXT_SHOP)
    && file_exists(_PS_MODULE_DIR_.$this->name.'/'.$this->adv_imgname.'-g'
    .$this->context->shop->getContextShopGroupID().'.'.Configuration::get('BLOCKADVERT_IMG_EXT')))
    $this->adv_imgname .= '-g'.$this->context->shop->getContextShopGroupID();
  if (Shop::getContext() == Shop::CONTEXT_SHOP
    && file_exists(_PS_MODULE_DIR_.$this->name.'/'.$this->adv_imgname.'-s'
    .$this->context->shop->getContextShopID().'.'.Configuration::get('BLOCKADVERT_IMG_EXT')))
    $this->adv_imgname .= '-s'.$this->context->shop->getContextShopID();
  $this->adv_img = Tools::getMediaServer($this->name)._MODULE_DIR_.$this->name.'/'
    .$this->adv_imgname.'.'.Configuration::get('BLOCKADVERT_IMG_EXT');
}

Создание таблиц базы данных

Может быть несколько сценариев:

  • Объект / сущность существует в некоторых магазинах, но не во всех из них: вы должны использовать ассоциативную таблицу и обрабатывать ее, используя id_group_shop.
  • Объект / сущность существует во всех магазинах: используйте обычные таблицы с настраиваемым полем. Обращайтесь с ней, используя id_entity, id_group_shop и атрибуты.
  • Язык должен быть разным для каждого магазина: обрабатывайте его, используя id_shop в  _lang table.

Объект только в некоторых магазинах

Используемый метод Shop::addSqlRestriction($share = false, $alias = null).

Это позволяет добавлять ограничения на SQL-запрос, чтобы получить информацию о магазине или группе магазинов.
Параметры являются необязательными:
  • $share: Используется для добавления предложения WHERE, указывающего, что мы находимся в той же группе, что и текущее хранилище.
  • $alias: Используется для установки псевдонима таблицы, к которому должно применяться предложение WHERE.

Например, этот запрос извлекает визиты посетителей из данного магазина:

'SELECT date_add, COUNT(`date_add`) as total
 FROM `'._DB_PREFIX_.'connections`
 WHERE 1 '.Shop::addSqlRestriction();

Объект во всех магазинах

Используемый метод Shop::addSqlAssociation($table, $alias, $inner_join = true, $on = null, $force_not_default = false).

Это позволяет добавить предложение JOIN в SQL-запрос, объединив таблицу и связанную с ней таблицу в multistore режиме.

Например, этот запрос автоматически связывает _DB_PREFIX_.'product_shop' table to the _DB_PREFIX_.'product' table using the ‘p‘ alias:

'SELECT wp.`id_product`
 FROM `'._DB_PREFIX_.'wishlist_product` wp
 LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = wp.`id_product`
 '.Shop::addSqlAssociation('product', 'p');

Таким образом, применяется соединение между информацией из продукта и контекстом текущего хранилища.

Различные языки в каждом магазине

Используемый метод Shop::addSqlRestrictionOnLang($alias = null, $id_shop = null).

Это позволяет добавить ограничение на id_shop для multishop таблицы языков.

Например, этот запрос автоматически связывает _DB_PREFIX_.'product_lang' table to the _DB_PREFIX_.'wishlist_product' table using the ‘pl‘ alias:

'SELECT wp.`id_product`
 FROM `'._DB_PREFIX_.'wishlist_product` wp
 LEFT JOIN `'._DB_PREFIX_.'product` p ON p.`id_product` = wp.`id_product`
 '.Shop::addSqlAssociation('product', 'p').'
 LEFT JOIN `'._DB_PREFIX_.'product_lang` pl ON pl.`id_product` = wp.`id_product`'.Shop::addSqlRestrictionOnLang('pl').'
 WHERE pl.`id_lang` = '.(int)($id_lang);

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