Документы

Примечание

Редактор документов появился с версии 4.4.1.

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

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

Типы документов

Для логического разделения все документы поделены на типы. Все доступные типы документов описаны в схеме documents/types (app/schemas/documents/types.php). Каждый тип — это отдельный класс, реализующий интерфейс \Tygh\Template\Document\IType, и должен быть зарегистрирован в контейнере Tygh::$app в следующем формате:

Tygh::$app['template.document.[type].type']

, где [type] — это идентификатор типа, например order.

Для расширения функциональности, каждый тип может дополнительно реализовать следующие интерфейсы:

  • \Tygh\Template\Document\IPreviewableType — реализация этого интерфейса позволяет использовать предпросмотр при редактировании документа.
  • \Tygh\Template\Document\IIncludableType — реализация этого интерфейса позволяет подключать документы данного типа в почтовые уведомления через include_doc.

Подразумевается, что в рамках одного типа структура контекста документа всегда будет одинаковой.

На данный момент реализованы следующие типы документов:

  • Order invoice
  • Order summary
  • Packing slip
  • RMA::Packing slip.
  • Gift certificates::Gift certificate
  • Suppliers::Invoice

Контекст

Контекст — это состояние системы и данные окружения на момент формирования документа. Например, контекстом для документа типа “order” будет являться заказ. Для каждого типа документов структура контекста должна быть известна, за счет этого можно добавлять собственные переменные, которые будут отталкиваться от контекста.

На программном уровне контекст — это класс, реализующий интерфейс \Tygh\Template\IContext, его минимальная обязанность — сообщить язык вывода.

Переменные

Переменные — это динамическая составляющая шаблонов. Именно через переменные шаблон получает доступ к контексту и другим данным. Каждый тип документов имеет свои переменные. Все доступные переменные для типа должны быть описаны в схеме documents/[type] (app/schemas/documents/[type].php), где [type] — это тип документа, например, для типа “order” схема будет documents/order. Каждая переменная — это отдельный класс, реализующий интерфейс \Tygh\Template\IVariable.

Пример описания переменной в схеме:

return array(
    'order' => array(
        'class' => '\Tygh\Template\Document\Invoice\Variables\OrderVariable',
        'arguments' => array('#context', '#config', '@formatter'),
        'alias' => 'o',
        'attributes' => array(
            'order_id', 'company_id', 'total', 'subtotal', ...
        )
    )
);
  • 'order' — основное имя переменной, используя его, можно будет обратиться к переменной в шаблоне, например: {{ order.total }}.

  • 'class' — полное название класса, отвечающего за формирование переменной.

  • 'arguments' — массив, описывающий аргументы конструктора класса переменной.

    Каждая переменная может иметь собственные зависимости, все зависимости должны быть описаны в схеме. В качестве значений можно использовать плейсхолдеры:

    • Начинающиеся с символа “#” — значение для такого аргумента формируется локально, в момент инициализации переменной, на данный момент доступно только 2 варианта: '#context' — экземпляр контекста документа и '#config' — схема переменной.
    • Начинающиеся с символа “@” — значение для такого аргумента будет получено из контейнера Tygh::$app.

    Описание этого параметра можно опустить — по умолчанию считается, что конструктор описываемой переменной принимает 2 аргумента — #context и #config. Это равносильно описанию аргументов как 'arguments' => array('#context', '#config').

  • 'alias' — псевдоним переменной, используя его, также можно будет обратиться к переменной в шаблоне, например: {{ o.total }}.

  • 'attributes' — этот параметр отвечает за описание атрибутов переменной, именно эти атрибуты будут отображены и доступны в редакторе документов.

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

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

    'products' => array(
        '0..N' => array(
            'item_id', 'product_id', 'product_code', 'price', 'amount', 'product', 'product_status'
        )
    )
    

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

Кроме основных параметров, в схеме можно описать любые другие, которые будут доступны через '#config'.

Если переменная имеет сложную структуру, для описания которой нерационально использовать схему, класс переменной может реализовать интерфейс \Tygh\Template\IActiveVariable, который обязывает реализовать единственный метод — attributes(). Таким образом, переменная в виде отдельного класса может самостоятельно описывать свои атрибуты.

Для облегчения добавления переменных добавлен специальный класс \Tygh\Template\Document\Variables\GenericVariable, который может быть полностью настроен из схемы. Таким образом, нет необходимости заводить отдельные классы под каждую из переменных. Пример такой переменной:

'payment' => array(
    'class' => '\Tygh\Template\Document\Variables\GenericVariable',
    'alias' => 'p',
    'data' => function (\Tygh\Template\Document\Order\Context $context) {
        //...
        return $payment;
    },
    'attributes' => array(
          'payment_id', 'payment', 'description', 'payment_category', 'surcharge_title', 'instructions'
    )
),

Где 'data' — либо массив данных, либо анонимная функция, результат которой — массив данных.

Также реализована отложенная инициализация переменных, которая единожды создает экземпляр переменной при первом обращении к ней. Таким образом, разработчику не нужно заботиться об этом самостоятельно. За реализацию этого поведения отвечает прокси-класс \Tygh\Template\VariableProxy.

Структура данных

Шаблоны документов сохраняются в таблице cscart_template_documents, которая имеет следующую структуру:

Название Тип Описание
document_id int Автоинкрементный идентификатор
template text Шаблон
default_template text Шаблон по умолчанию
type varchar(32) Тип документа
code varchar(128) Символьный идентификатор документа
addon varchar(32) Идентификатор модуля-владельца шаблона
updated int UNIX timestamp обновления
created int UNIX timestamp создания

Программный интерфейс

Для управления и взаимодействия с шаблонами документов реализованы следующие классы:

  • \Tygh\Template\Document\Document — модель шаблона документа. Является программным представлением структуры шаблона в БД.
  • \Tygh\Template\Document\Repository — класс-репозиторий. Реализует низкоуровневые методы добавления/обновления/удаления/выборки шаблонов из БД. Экземпляр класса доступен из контейнера Tygh::$app['template.document.repository'].
  • \Tygh\Template\Document\Service — класс-сервис. Реализует более высокоуровневые методы управления шаблонов. Экземпляр класса доступен из контейнера Tygh::$app['template.document.service'].
  • \Tygh\Template\Document\Exim — класс реализует логику экспорта и импорта шаблонов. Экземпляр класса доступен из контейнера Tygh::$app['template.document.exim'].

Вспомогательные классы:

  • \Tygh\Template\Document\TypeFactory — класс-фабрика для создания экземпляров типа документов. Экземпляр класса доступен из контейнера Tygh::$app['template.document.type_factory'].
  • \Tygh\Template\Collection — класс “нетипизированная коллекция данных”. Используется для создания коллекции переменных.
  • \Tygh\Template\ObjectFactory — класс-фабрика объектов. Умеет на основе описывающей информации создавать экземпляры классов. Экземпляр класса доступен из контейнера Tygh::$app['template.object_factory'].
  • \Tygh\Template\Renderer — класс-обертка над Twig. Экземпляр класса доступен из контейнера Tygh::$app['template.renderer'].
  • \Tygh\Template\VariableMetaData — класс для обработки мета данных переменных.
  • \Tygh\Template\VariableCollectionFactory — фабрика коллекций переменных. Умеет создавать коллекцию переменных на основе схемы переменных. Экземпляр класса доступен из контейнера Tygh::$app['template.variable_collection_factory'].
  • \Tygh\Template\VariableProxy — прокси-класс. Организует отложенную инициализацию переменных.

Схема формирования отображения документа

New banner
  1. Получение шаблона документа. Выборка модели шаблона документа с помощью класса-репозитория \Tygh\Template\Document\Repository.
  2. Формирование контекста документа. На основе переданных данных создаем контекст документа.
  3. Формирование коллекции переменных. Инициализация коллекции переменных на основе контекста документа с помощью класса \Tygh\Template\VariableCollectionFactory.
  4. Вызов шаблонизатора для формирования отображения документа.
  5. Возврат результата.

Добавление переменных в список доступных переменных

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

Пример добавления переменной, выводящей “barcode” для заказа:

Файл app/addons/barcode/Tygh/Addons/Barcode/Documents/Order/BarcodeVariable.php:

<?php

namespace Tygh\Addons\Barcode\Documents\Order;

use Tygh\Registry;
use Tygh\Template\Invoice\Order\Context;
use Tygh\Template\IVariable;

class BarcodeVariable implements IVariable
{
    public $image;

    public function __construct(Context $context)
    {
        $order = $context->getOrder();

        $width = Registry::get('addons.barcode.width');
        $height = Registry::get('addons.barcode.height');
        $url = fn_url(sprintf(
            'image.barcode?id=%s&type=%s&width=%s&height=%s&xres=%s&font=%s&no_session=Y',
            $order->getId(),
            Registry::get('addons.barcode.type'),
            $width,
            $height,
            Registry::get('addons.barcode.resolution'),
            Registry::get('addons.barcode.text_font')
        ));

        $this->image = <<<EOF
<div style="text-align:center">
    <img src="{$url}" alt="BarCode" width="{$width}" height="{$height}">
</div>
EOF;
    }
}

Расширим схему переменных для документов типа “order”. Для этого добавляем файл /app/addons/barcode/schemas/documents/order.post.php:

<?php
$schema['barcode'] = array(
    'class' => '\Tygh\Addons\Barcode\Documents\Order\BarcodeVariable'
);

return $schema;

После этих манипуляций в редакторе документов типа “order” появится еще одна доступная переменная с именем “barcode” и атрибутом “image”.

Добавление сниппетов в список доступных сниппетов

Для того, чтобы сниппет появился в списках доступных сниппетов, необходимо для выбранного типа документа добавить сниппет в БД. Тип сниппета в этом случае будет равен [type]_[code], где:

  • [type] — тип документа;
  • [code] — символьный код шаблона документа.

Расширение документов

PHP-хуки

  • 'template_document_get_name' — вызывается после формирования имени документа. С помощью хука можно повлиять на название документа:

    fn_set_hook('template_document_get_name', $this, $result)
    
  • 'template_document_remove_post' — вызывается после удаления документа:

    fn_set_hook('template_document_remove_post', $this, $document)
    

Template-хуки

  • {hook name="documents:tabs_extra"}{/hook} (design/backend/templates/views/documents/update.tpl) — позволяет добавлять дополнительные вкладки на страницу редактирования документа.
  • {hook name="documents:update_buttons_extra"}{/hook} (design/backend/templates/views/documents/update.tpl) — позволяет добавлять дополнительные кнопки на панель инструментов.
  • {hook name="documents:update_adv_buttons_extra"}{/hook} (design/backend/templates/views/documents/update.tpl) — позволяет добавлять дополнительные кнопки на панель инструментов в зависимости от текущей вкладки.

Ограничения

Хуки

Одно из самых заметных ограничений — отсутствие хуков в самом шаблоне документа. Т.е. подразумевается, что шаблон документа не может быть изменен автоматически (программно), это действие полностью возлагается на администратора магазина. Таким образом, модули могут лишь расширять списки доступных сниппетов и переменных.

Сложная логика шаблонов

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