Блоки

Актуальны для платформ версии 3.x.

О применении блоков для FL2.x можно детально прочитать по ссылке.

Цель применения

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

namespace plugins\example\views;

use bff\view\Block;

class ExampleBlock extends Block
{
    public function init()
    {
        // Инициализация блока 
    }

    public function data()
    {
        // Обработка данных блока, используемых в шаблоне
    }
}

Инициализация

Класс блока создается в директории views и наследуется от базового блока bff\view\Block.
Метод init() обязательный, инициализирует блок.

public function init()
{
    // Вызов базовой инициализации
    parent::init();
    // Объявляем шаблон для отрисовки блока
    $this->setTemplate('tpl/example', $controller);
    // Задаем мультиязычный заголовок блока
    $this->setTitle($this->extension->lang('Example'));
}

Метод setTemplate($tpl, $controller) задает шаблон блока, где

  • $tpl - subdir/tpl_name название шаблона и расположение в директории tpl,
    для блока в плагине указываем также название папки размещения шаблона tpl/subdir/tpl_name,
    для блока в модуле - только поддиректорию и название шаблона subdir/tpl_name;
  • $controller - контроллер блока, это может быть как модуль module_name так и плагин.
    $this->extension = $this->app->plugin('plugin_alias');
    $this->setTemplate('tpl/subdir/tpl_name', $this->extension);
    

Данные блока

Метод data() определяет данные, которые будут переданы в шаблон для отображения блока.

public function data()
{
    // Данные базового класса
    $data = parent::data();
    
    // Данные блока
    $data['title'] = $this->lang('Example block');
    $data['list'] = $this->model->getList();
    
    return $data;
}

Шаблон блока

В шаблоне представления plugins/example/tpl/example.php доступны переменные, инициализированные в методе data().

/**
 * Example block
 * @see plugins\example\views\ExampleBlock
 * @var $title string
 * @var $list array
 */
?>
<div>
    <h1><?= $title ?></h1>
    <?php foreach($list as $item){ ?>
        <?= $item['key'] ?>
    <?php } ?>
</div>

Интеграция блока

Вставляем блок на страницу посредством метода blocks(), указывая ключ и название класса обработчика ExamplePage.

public function blocks()
{
    $this->addBlock('example', ExampleBlock::class);
}    

Метод addBlock($key, $block, $callback, $opts) добавляет блок ExampleBlock в текущий объект класса обработчика страницы.
Принимает параметры:

  • $key - ключ блока,
  • $block - класс, объект блока или замыкание Closure,
  • $callback - необязательный параметр, замыкание, которое будет вызвано после инициализации блока, параметрами являются объект добавленного блока и ключ,
  • $opts - необязательный параметр, массив с дополнительными опциями.

Дале в процессе рендеринга шаблона страницы блок выводится как переменная по ключу example.

Страницы

Для создания страниц используем класс обработчик представления, который наследуется от базовой страницы представления bff\view\Page.
Страницы создаются как в модулях так и в дополнениях.
Рассмотрим структуру страницы и основные методы.

namespace plugins\example\views;

use bff\view\Page;

class ExamplePage extends Page 
{
    public function init()
    {
       // Инициализация страницы 
    }

    public function data()
    {
        // Обработка данных страницы, используемых в шаблоне
    }

    public function blocks()
    {
        // Добавление блоков
    }

    public function settingsForm($form)
    {
        // Настройки страницы в админ панели
    }    
    
    public function seo()
    {
         // Seo настройки страницы 
    }
}

Инициализация и данные страницы аналогичны методам блока init() и data().

Блоки страницы

В методе blocks() добавляются блоки страницы.

public function blocks()
{
    // Добавление существующего блока на страницу 
    $this->addBlock('example', ExampleBlock::class, function (ExampleBlock $block) {
        $block->itemId = $this->itemId;
    }););
    // Объявление блока
    $this->addTemplateBlock('filter', 'tpl/filter', $this->extension, function (bff\view\Block $block) {
        $block->setTitle($this->extension->lang('Filter'));
        ...
    })
}

Добавление блока addBlock() детально описано в разделе "Блоки". Так же в блок при его добавлении в $callback можно передавать параметры страницы.
В классе обработчике страницы можно объявить класс блока в методе addTemplateBlock($key, $template, $controller, $callback):

  • $key - ключ блока,
  • $template - название шаблона и расположение в директории tpl,
  • $controller - контроллер блока,
  • $callback - замыкание, которое будет вызвано после инициализации блока, параметром является объект добавленного блока.

Отображать блоки можно по отдельности как переменные в шаблоне $example и $filter.

Настройки страницы

В методе settingsForm($form) создаётся форма настроек страницы или блока в интерфейсе админ панели проекта, $form - объект конструктора форм bff/tpl/admin/Form, позволяет выводить все типы полей.

/** @var bool */
public $enabled = false;
/** @var string */
public $intro = '';
...
public function settingsForm($form)
{
    $form->checkbox('enebled', $this->extension->lang('Enabled'), $this->enabled);
    $form->wysiwyg('intro', $this->extension->lang('Page Text'));
}

В данном случае, метод создает чекбокс enabled и редактор wysiwyg intro.
Данные настройки задаются как параметры класса обработчика страницы.
Редактировать данные поля можно в админ панели в меню Оформление / Настройки страниц / Страница Example.

Settings_form

Отключить блок или поменять его расположение на странице можно во вкладке Порядок.

В методе seo() настаиваются SEO параметры страницы.

Шаблон страницы

Шаблон страницы page.php задается в методе init() при инициализации объекта класса обработчика:

public function init()
{ 
    ...
    $this->setTemplate('tpl/page', $this->extension);
}    

В шаблоне страницы для рендеринга доступны:

  • данные страницы из метода data(),
  • блоки как переменные шаблона $example, $filter,
  • настройки страницы $enebled, $intro.
/**
 * Example page
 * @see plugins\example\views\ExamplePage
 * @var $title string
 * @var $enebled boolean
 * @var $intro string
 * @var $example plugins\example\views\ExampleBlock
 * @var $filter string 
 */ 
?>
<?php if($enebled){ // настройка класса из settingsForm()  ?>
    <div>
      <h1><?= $title // данные класса из data() ?></h1>  
      <p><?= $intro ?></p>
      <?= $exampleBlock // пример вывода блока ExampleBlock ?>
      <?= $filterBlock ?>
    </div>
<?php } ?>

Отображение страницы

Отображение страницы осуществляется посредством добавления роута в модуле или плагине. В методе start() в роуте /example/ страницы в качестве обработчика указываем класс представления:

protected function start()
{
    ...
    $this->routeAdd(
    'plugin_alias-example', # route id
    [
        'pattern'  => '/example/',
        'callback' => ExamplePage::class,
    ]);
}   

Расширение страниц

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

Рассмотрим такую возможность на примере страницы контактов. Контракт контактов расположен в модуле и выглядит следующим образом:

namespace modules\contacts\views\contracts;

use bff\view\Page;

/**
 * Contact page contract
 * @mixin Page
 */
interface ContactPage
{
}

Находится в пространстве имен представления в директории contracts и может использовать методы класса bff\view\Page.
В теме или плагине можно расширить страницу контактов платформы и создать собственную страницу контактов ContactPageExtended.

namespace plugins\contacts_extended\views;

use modules\contacts\views\ContactPage;
use modules\contacts\views\contracts\ContactPage as ContactPageContract;

class ContactPageExtended extends ContactPage implements ContactPageContract
{
    ...
}

Переопределить конкретную реализацию можно в методе start.

use modules\contacts\views\contracts\ContactPage as ContactPageContract;
use plugins\contacts_extended\views\ContactPageExtended;
...
protected function start()
{
    ...
    $this->app->singleton(
        // Контракт исходной страницы контактов в платформе
        ContactPageContract::class, 
        // Новая класс станицы контактов в плагине
        ContactPageExtended::class 
    );
}
...