Web
Analytics
Skip to content

Concrete5

на русском языке

Использование контекста для настройки разметки форм и атрибутов

Мы уже объяснили немного об этой проблеме: наши Express Формы прекрасно выглядят в панели управления и в любой теме использующей Twitter Bootstrap – но они не будут выглядеть столь хорошо в темах, основанных на пользовательской разметке как для полей формы, так и для их html элементов контейнера. 

Нам нужно сделать чтобы эта форма:

Ломанная форма

чтобы выглядела так:

Красивая форма

Эта наша поломанная форма, помните? Ну, теперь, когда мы немного знаем о том, как Express выводит свои формы, мы можем изменить это поведение. Это можно сделать для всего сайта, не беспокоясь о пользовательских шаблонов, и не беспокоясь о влиянии на формы, выводимые в панели управления. 

Создание пользовательского контроллера Формы

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

В этом примере, моя тема сайта и настройки находятся в директории  package с именем my_site. Поэтому я добавил следующий код в контроллер плагина:

protected $pkgAutoloaderRegistries = array(
    'src/MySite' => '\MySite',
);

и я создам мой пользовательский контроллер здесь:

packages/my_site/src/MySite/Express/Controller/FormController.php

Этот файл будет выглядеть так, когда он еще будет пустой:

<?php
namespace MySite\Express\Controller;
use Concrete\Core\Express\Controller\StandardController;

class FormController extends StandardController
{

}

Выглядит довольно просто, правда? Мы пока не добавили сюда никакой функциональности - он просто расширяет стандартный контроллер, который используется по умолчанию в каждой экспресс форме в concrete5. Теперь, в нашем методе  on_start() в плагине сайта, мы скажем concrete5, что этот контроллер должен использоваться для каждой Экспресс формы:

public function on_start()
{
    $this->app->make('Concrete\Core\Express\Controller\Manager')
    ->setStandardController('MySite\Express\Controller\FormController');
}

Создание пользовательского контроллера для одной формы

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

public function on_start()
{
    $this->app->make('Concrete\Core\Express\Controller\Manager')
    ->extend('document', function() {
        return new MySite\Express\Controller\DocumentFormController();
    });
}

Осуществление Реестра Контекста

Теперь, когда у нас есть пользовательский контроллер формы, что дальше? Что мы сможем с этим сделать? Разные вещи. Мы могли бы

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

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

Создание класса

Создайте файл, по имени FrontendFormContext.php в директории packages/my_site/src/MySite/Express/Form/Context/FrontendFormContext.php. Давайте пока сделаем этот файл пустым, но сделаем его расширением контекста формы в пользовательском интерфейсе ядра:

<?php
namespace MySite\Express\Form\Context;

use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;

class FrontendFormContext extends CoreFrontendFormContext
{

}

Теперь добавим метод getContextRegistry и пользовательский объект реестра контекста в ваш пользовательский контроллер. 

<?php

namespace MySite\Express\Controller;
use Concrete\Core\Express\Controller\StandardController;
use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use MySite\Express\Form\Context\FrontendFormContext;
use Concrete\Core\Form\Context\Registry\ContextRegistry;

class FormController extends StandardController
{

    public function getContextRegistry()
    {
        return new ContextRegistry([
            CoreFrontendFormContext::class => new FrontendFormContext()
        ]);
    }
}

Что здесь происходит? Сначала, мы добавили новое утверждение use чтобы импортировать нужные классы. Поскольку у некоторых из них одинаковые имена, мы должны использовать несколько алиасов класса. Затем, мы используем метод getContextRegistry, который возвращает объект Concrete\Core\Form\Context\Registry\ContextRegistry. Этот объект довольно простой: он берёт массив строк совпадающих с контекстом ядра, и отмечает те соответствия выводящим классам, которые вы хотите доставить. Поэтому каждый раз форма, использующая этот контроллер выводит контекст, она будет проверять, какой контекст запрошен, и если для этого контекста был зарегистрирован пользовательский контекст, этот пользовательский контекст будет доставлен вместо контекста по умолчанию! 

Конечно, это не даёт нам пока пользы, поскольку в нашем пользовательском контексте нет никакого метода. Давайте добавим нашему пользовательскому контексту немного функциональности. 

Настройка пользовательского контекста

Откройте packages/my_site/src/MySite/Express/Form/Context/FrontendFormContext.php и добавьте туда следующий код:

public function setLocation(TemplateLocator $locator)
{
    $locator = parent::setLocation($locator);
    $locator->prependLocation([DIRNAME_ELEMENTS .
        DIRECTORY_SEPARATOR .
        DIRNAME_EXPRESS .
        DIRECTORY_SEPARATOR .
        DIRNAME_EXPRESS_FORM_CONTROLS .
        DIRECTORY_SEPARATOR .
        DIRNAME_EXPRESS_FORM_CONTROLS // not a typo
    , 'my_site']);
    return $locator;
}

Что он делает? Просто, он дописывает новое место, где надо искать шаблоны. На самом деле это тот же путь, что использует ядро - но обратили вы внимание на "my_site" внизу? Это значит, что мы будем искать шаблон внутри плагина my_site  прежде, чем будем искать в ядре, для любого и всех шаблонов, которые используют наш пользовательский контекст. 

Копирование пользовательского элемента контроля шаблонов

Затем, скопируем все соответствующие пользовательские элементы управления шаблонами из concrete/elements/express/form/form в packages/my_site/elements/express/form/form. На моём сайте я сделал

packages/my_site/elements/express/form/form/form.php
packages/my_site/elements/express/form/form/association/select.php

Затем сделайте свои настройки. Они могут включать отличные теги от филдсет, разные заголовки, дополнительную разметку формы, или что нибудь другое.

Настройка атрибутов

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

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

Создание класса

Создайте файл с именем  FrontendFormContext.php в packages/my_site/src/MySite/Attribute/Context/FrontendFormContext.php. Давайте сделаем этот файл пока пустым, но сделаем его расширением контекста пользовательского интерфейса формы атрибута из ядра :

<?php
namespace MySite\Attribute\Context;

use Concrete\Core\Attribute\Context\FrontendFormContext as BaseFrontendFormContext;

class FrontendFormContext extends BaseFrontendFormContext
{

}

Выглядит знакомо, правда? Теперь давайте сделаем наш класс Контекста Экспресс Формы, использующий класс контекста атрибута для того, чтобы когда он будет выводить атрибуты добавлялся в наш предыдущий класс getAttributeContext. Откройте packages/my_site/src/MySite/Express/Form/Context/FrontendFormContext.php и добавьте туда следующий код:

public function getAttributeContext()
{
    return new \MySite\Attribute\Context\FrontendFormContext();
}

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

Настройка контекста атрибута

Откройте packages/my_site/src/MySite/Attibute/Context/FrontendFormContext.php и добавьте туда следующий код:

public function __construct()
{
    parent::__construct();
    $this->preferTemplateIfAvailable('site', 'my_site');
}

public function setLocation(TemplateLocator $locator)
{
    $locator->setTemplate(['site', 'my_site']);
    return $locator;
}

Итак, что мы здесь делаем? Пару вещей. Во-первых, функция контекста атрибута preferTemplateIfAvailable специфична для контекстов атрибута. Это означает, что если конкретный атрибут выводится в этом контексте, мы будем пытаться загрузить его шаблон до загрузки всего остального. 

Например, скажем, что мы в форме выводим текстовый атрибут.  Обычно, это означает, что этот атрибут вывел бы  concrete/attributes/text/form.php (вместе с выполняемым методом form().) Так было в  concrete5 долгое время. Этот метод означает, что когда какой-нибудь атрибут выводится в конкретном контексте, мы будем сначала смотреть в директории packages/my_site/attributes/text/site.php, а затем вернёмся к поиску  form.php в ядре, если тот файл не существует. Это воздействует только на текущий элемент управления, поскольку только это обычно включено в файл  form.php находящийся в папке  атрибутов.

Затем, давайте посмотрим на метод setLocation(). Он отвечает за установки разметки  HTML окружающей атрибут. В нашем примере, мы устанавливаем шаблон, используемый для 'site.php' , находящийся в плагине  my_site (папка packages). Мы не изменяем местоположение этих шаблонов, что означает, что путь к ним остаётся прежним. Что значит, что с этим простым кодом в одну строку, мы теперь будем искать все шаблоны-обёртки в совершенно новом месте  – и включим их, если только они существуют. 

Копирование и изменение внешних файлов шаблонов

Теперь мы можем переписать внешние шаблоны из bootstrap в ту разметку, которую поддерживает наша тема. Скопируйте concrete/elements/form/bootstrap3.php и concrete/elements/form/grouped/bootstrap3.php в packages/my_site/elements/form/site.php и packages/my_site/elements/form/grouped/site.php и внесите необходимые изменения.

Создание шаблонов формы атрибута

Сейчас, когда мы изменили внешний  HTML для каждого элемента управления атрибута, давайте перепишем каждую форму атрибута для его контекста. На моём сайте я изменил следующие атрибуты

  • address (адрес)
  • email (е-мейл)
  • number (число)
  • select (выпадающий список)
  • text (текстовое поле)
  • textarea (текст)
  • url 

Создавая директории в  packages/my_site/attributes/ (для каждого атрибута), а затем создавая файл в директории  site.php. Почему это опять работает? Всё это загружается в этот код:

public function __construct()
{
    parent::__construct();
    $this->preferTemplateIfAvailable('site', 'my_site');
}

Просто, каждый раз, когда атрибут выводится в контексте, для этого атрибута будет загружаться site.php из packages/my_site/attributes/text/site.php , если он существует (где текст это идентификатор запрашиваемого атрибута).

Когда вы скопироваля файлы form.php из этих атрибутов в новое место, вы можете вносить любые изменения для вашей темы, будучи уверенным, что этот файл будет загружаться только для формы в контексте пользовательского интерфейса. Вы не изменяете атрибут для всех вариантов использования  – композер, панели атрибутов, и панель управления - всё останется неизменным. Вот как выглядит мой файл packages/my_site/attributes/text/site.php :

<?php
defined('C5_EXECUTE') or die("Access Denied.");
?>
<div class="field">
    <?php
    print $form->text(
        $this->field('value'),
        $value,
        [
            'placeholder' => $this->akTextPlaceholder
        ]
    );

    ?>
</div>

Довольно просто и почти без изменений в сравнении со стандартной формой атрибута – но, обратите внимание, что я добавил  <div class="field"></div> вокруг элемента управления, так как это нужно для моей формы.

Заключение

Здесь довольно много изменений, но к счастью, этот и предыдущий документ дают вам общую идею, о мощи и гибкости Экспресс Форм и их атрибутов. Используя эту систему, вы легко можете изменить шаблоны атрибутов и форм для специфических разделов вашего сайта, или даже для специфических форм ( так как это всё управляется архитектурой контроллера формы .)

Хотите больше информации о возможностях Контроллера Экспресс Форм? Читайте примеры для продвинутых пользователей.

Загрузка беседы
Также как и одиночные страницы, типы страниц могут также иметь контроллер. Метод view() для контроллера типа страницы автоматически будет работать, когда страница будет просматриваться на сайте.
Как повысить репутацию сайта на 25% с помощью ссылок на другие ресурсы.