Введение

Для использования шаблонов, файлы страниц должны обрабатываться PHP (как правило, иметь расширение .php).

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

Но для использования всех возможностей движка потребуется разделение кода HTML и PHP, как минимум, на два файла. В основном файле должно содержаться объектное представление страницы - класс. Во втором файле - разметка страницы (код HTML).

Файл с разметкой должен иметь тоже название, что и файл страницы, но с расширением .html.php.

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

Содержание

Блоки контента

Содержимое для блоков контента должно располагаться в тегах: <php:Content />. Имя (идентификатор) блока указывается в параметре ID.

<php:Content ID="имяМетки">
  Содержимое блока.
  Допустимо использование любых тэгов, 
  серверного кода и 
  элементов управления.
</php:Content>

Все, что располагается за переделами тегов <php:Content /> будет проигнорировано.

Этот текст будет проигнорирован, т.к. находится вне блока <php:Content />.

<php:Content ID="MainContent">
  Это текст будет выведен вместо метки <php:MainContent/>.
</php:Content>

Этот текст будет проигнорирован, т.к. находится вне блока <php:Content />.

Допустимо размещение блоков для несуществующих в шаблоне меток. Это будет полезно при динамическом изменении шаблона, когда в одном шаблоне определен один набор блоков контента, а в другом - другой.

В следующем примере показано два шаблона. В первом определен блок <php:MainContent/>, во втором два блока: <php:MainContent/> и <php:RightPanel/>. На странице контента определено содержимое для двух блоков. При использовании шаблона Layout1.php клиент получит только содержимое для блока <php:MainContent/>, поскольку в шаблоне нет других блоков (см. Результат #1). А при использовании шаблона Layout2.php, клиенту будет выдано содержимое определенное для обоих блоков (см. Результат #2).

<!DOCTYPE html>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <div class="container">
      <php:MainContent/>
    </div>
  </body>
</html>
<!DOCTYPE html>
<html>
  <head>
    <title></title>
  </head>
  <body>
    <div class="container">
      <div class="col-md-10">
        <php:MainContent/>
      </div>
      <div class="col-md-2">
        <php:RightPanel/>
      </div>
    </div>
  </body>
</html>
<php:Content ID="MainContent">
  Это содержимое для блока MainContent.
</php:Content>

<php:Content ID="RightPanel">
  Это содержимое для блока RightPanel.  
</php:Content>
<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок по умолчанию</title>
  </head>
  <body>
    <div class="container">
      Это содержимое для блока MainContent.
    </div>
  </body>
</html>
<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок по умолчанию</title>
  </head>
  <body>
    <div class="container">
      <div class="col-md-10">
        Это содержимое для блока MainContent.
      </div>
      <div class="col-md-2">
         Это содержимое для блока RightPanel. 
      </div>
    </div>
  </body>
</html>

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

<php:Content ID="MainContent">
  Это текст будет обработан, но не будет выведен, т.к. ниже размещен второй блок с идентификатором MainContent.
</php:Content>

<php:Content ID="MainContent">
  Это текст будет выведен вместо метки <php:MainContent/>.
</php:Content>

Простые страницы

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

Простые страницы могут быть полезны для вывода статичного содержимого, когда не требуется управление процессом формирования страницы на сервере.

Для работы шаблонизатора, на страницу необходимо включить файл global.php, а также вызвать процесс обработки страницы командной App::Magic().

<?php 
require_once 'global.php';
\Nemiro\App::Magic();
?>

В следующем примере показана реализация простой страницы, которая формирует содержимое для метки <php:MainContent/>. В директиве #Page указана ссылка на файл шаблона, а также заголовок страницы (<title />).

<?#Page Layout="~/Layouts/_Layout.php" Title="Это простая страница"?>

<php:Content ID="MainContent">
  <h2>Привет, мир!</h2>
</php:Content>

<?php 
require_once 'global.php';
Nemiro\App::Magic();
?>

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

Разделение кода PHP и HTML

Для использования всех возможностей, рекомендуется разделять код HTML и PHP.

В основном файле страницы создается класс страницы. Имя класса должно соответствовать имени файла страницы (без расширения). Разметка должна находиться в файле с расширением .html.php.

Например, есть страница index.php, она должна иметь примерно следующее содержание:

<?php
require_once 'global.php';

class Index extends \Nemiro\UI\Page
{

}

\Nemiro\App::Magic();
?>

А разметка должна располагаться в файле index.html.php. В следующем примере показан возможный вариант файла index.html.php.

<php:Content ID="MainContent">
  <h2>Привет, мир!</h2>
</php:Content>

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

Класс страницы может содержать любые публичные свойства и функции, которые можно использовать в коде разметки, через ключевое слово $this. Например, базовый класс \Nemiro\UI\Page имеет свойство Title, которое содержит заголовок текущей страницы и его можно вывести на страницу следующим образом:

<php:Content ID="MainContent">
  <h2>Заголовок страницы: <?=$this->Title?></h2>
</php:Content>

Подробнее о классе Page.

Только код PHP

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

Например, файл index.php может иметь следующее содержание.

<?php
require_once 'global.php';

class Index extends \Nemiro\UI\Page
{

  function Load()
  {
    $this->Title = 'Это страница без разметки';
    $this->Content['MainContent'] = 'А здесь у нас контент для блока MainContent.';
  }

}

\Nemiro\App::Magic();
?>

Но такой подход используется редко, поскольку для большинства случаев это не очень удобно.

Директивы

Директива <?#Page ?>

Директива <?#Page ?> позволяет переопределить параметры инициализации страницы заданные по умолчанию (в файле config.php).

Директива располагается в верхней части страницы HTML, параметры записываются в стиле атрибутов тегов HTML/XML. Например: <?#Page Title="Заголовок страницы" Layout="~/Layouts/_Layout.php" ?>

Список поддерживаемых параметров представлен в следующей таблице.

Параметр Тип значения Описание
Layout Строка Позволяет указать файл шаблона, который следует использовать при формировании страницы.
Title Строка Позволяет указать html-заголовок страницы (аналог тега <title></title>).
Optimized Логический Позволяет управлять режимом оптимизации результирующего html-кода страницы.
Cache Логический Позволяет управлять кешированием страницы.
Culture Строка Позволяет задать культуру (язык) для страницы. Как правило, используется стандартный двухбуквенный код языка. Например: ru, en.

В следующем примере показано использование директивы <?#Page ?> для назначения заголовка страницы и включения режима оптимизации HTML.

<?#Page Title="Заголовок страницы" Optimized="true" ?>

<php:Content ID="MainContent">
  Привет, мир!
</php:Content>

Использование директивы <?#Page ?> наиболее актуально при создании простых страниц.

Директива <?#Register ?>

Как и в шаблонах, на обычных страницах можно использовать директиву <?#Register ?> для регистрации пользовательских элементов управления.

Директива <?#Register ?> принимает четыре параметра, список которых представлен в следующей таблице.

Параметр Тип значения Описание
Src Строка Обязательный параметр. Путь к основному файлу элемента управления.
TagPrefix Строка Обязательный параметр. Префикс имени элемента управления, который будет использоваться при размещении экземпляра элемента на странице. Префикс может быть полезен для разделения элементов на группы, привязки к определенному источнику, или, когда на странице одновременно требуется разместить несколько элементов с одинаковыми именами, но разным источником.
TagName Строка Обязательный параметр. Имя элемента управления, которое будет использоваться при размещении экземпляра элемента на странице.
ClassName Строка Опциональный параметр. Указывает имя класса элемента. По умолчанию, в качестве имени класса ожидается название файла элемента, без учета расширения. Например, основной файл элемента Message.php, то ClassName по умолчанию будет Message.

Количество директив <?#Register ?> на одной странице ограничивается, разве что, здравым смыслом.

В следующем примере показано использование директивы <?#Register ?> для регистрации на странице пользовательских элементов управления Message и TabControl, и их последующее использование.

<?#Register Src="~/Controls/Message.php" TagPrefix="php" TagName="Message"?>
<?#Register Src="~/Controls/TabControl.php" TagPrefix="php" TagName="TabControl"?>

<php:Content ID="MainContent">
  Привет, мир!
  <php:Message Type="success" Content="Всё хорошо!" />
  <php:TabControl>
    <php:Items>
      <php:TabItem Key="Tab1" Title="Обратите внимание">
        Элементы TabControl и Message не являются частью WebForms.PHP,
        эти элементы были сделаны специально для демонстрационного сайта.
</php:TabItem>
      <php:TabItem Key="Tab2" Title="Однако...">
        Но при желании вы можете использовать эти элементы в своих проектах, 
        просто скопировав файлы элементов из папки /Controls.
        Для правильной работы этих элементов также потребуется Bootstrap3.
      </php:TabItem>
    </php:Items>
  </php:TabControl>
</php:Content>
<!DOCTYPE html>
<html>
  <head>
    <title>Заголовок по умолчанию</title>
  </head>
  <body>
    <div class="container">
      <!--Начало вывода блока контента MainContent-->
        Привет, мир!

        <!--Начало вывода элемента Message-->
        <div class="alert alert-success">Всё хорошо!</div>
        <!--Конец вывода элемента Message-->

        <!--Начало вывода элемента TabControl-->
        <ul class="nav nav-tabs" role="tablist">
          <li class="active">
            <a href="#Page_TabControl1_Tab1" aria-controls="Page_TabControl1_Tab1" role="tab" data-toggle="tab" aria-expanded="false">
              Обратите внимание
            </a>
          </li>
          <li>
            <a href="#Page_TabControl1_Tab2" aria-controls="Page_TabControl1_Tab2" role="tab" data-toggle="tab" aria-expanded="true">
              Однако...
            </a>
          </li>
        </ul>
        <div class="tab-content">
          <div role="tabpanel" class="tab-pane" id="Page_TabControl1_Tab1">
            
        Элементы TabControl и Message не являются частью WebForms.PHP,
        эти элементы были сделаны специально для демонстрационного сайта.

          </div>
          <div role="tabpanel" class="tab-pane" id="Page_TabControl1_Tab2">
            
        Но при желании вы можете использовать эти элементы в своих проектах, 
        просто скопировав файлы элементов из папки /Controls.
        Для правильной работы этих элементов также потребуется Bootstrap3.
      
          </div>
        </div>
        <!--Конец вывода элемента TabControl-->
      <!--Конец вывода блока контента MainContent-->
    </div>
  </body>
</html>

Класс Page

Класс \Nemiro\UI\Page (далее Page) - этой основной класс, который отвечает за формирование страниц.

От класса Page должны наследоваться (extends) классы всех страниц.

Если у страницы нет класса, то используется экземпляр класса Page по умолчанию, с ограниченными возможностями.

В следующем фрагменте кода показан вариант наследования класса страницы Forum от базового класса Page.

<?php
require_once 'global.php';

class Forum extends \Nemiro\UI\Page
{

}

\Nemiro\App::Magic();
?>

Свойства

Класс Page имеет следующие публичные свойства.

Свойство Тип значения Описание
Optimized Логический Позволяет управлять режимом оптимизации результирующего html-кода страницы.
Программно изменить режим оптимизации можно в обработчике события PreLoad или Load.
Cache Логический Позволяет управлять кешированием страницы.
Программно изменить режим кеширования страницы можно в обработчике события PreLoad.
Layout Строка Содержит путь к файлу шаблона. Это либо значение по умолчанию, из файла config.php, либо значение определенное в директиве <?#Page ?>, либо установленное программно значение.
Программно изменить путь к файлу шаблона можно в обработчике события PreLoad.
Encode Строка Название кодировки страницы. Передается в Content-Type.
Программно изменить значение этого свойства можно в обработчике события PreLoad.
Culture Строка Код культуры (язык) для страницы. Как правило, используется стандартный двухбуквенный код языка. Например: ru, en.
Программно изменить значение этого свойства можно в обработчике события PreLoad или Load.
Title Строка Заголовок страницы (аналог тега <title></title>).
Программно изменить значение этого свойства можно в обработчике события PreLoad или Load.
Content Коллекция (ключ=значение) Коллекция блоков содержимого страницы; где ключом является имя (идентификатор) блока, а значением - содержимое блока.
Программно изменить блоки контента можно в обработчике события PreLoad или Load.
Например: $this->Content['MainContent'] = 'Контент для блока MainContent.';
Meta Коллекция (ключ=значение) Коллекция метатегов; где ключом является имя (идентификатор) тега, а значением - содержимое тега.
Программно добавить метатеги можно в обработчике события PreLoad или Load.
Например: $this->Meta['DESCRIPTION'] = 'Описание страницы.';, на выходе будет метатег:
<meta name="DESCRIPTION" content="Описание страницы." />.
Для установки описания и ключевых слов также можно использовать методы SetDescription и SetKeyWords.
Например: $this->SetDescription('Описание страницы.');
Scripts Строковой массив Массив ссылок на клиентские скрипты, которые будут включены в страницу.
Программно добавить или изменить ссылки можно в обработчике события PreLoad или Load.
Controls Коллекция (ключ=значение) Коллекция элементов управления; где ключ - идентификатор элемента (ID), а значение - элемент управления.
Программно изменить свойства элементов управления можно в обработчике события Load.
Обратите внимание, что через эту коллекцию нельзя получить прямой доступ к экземплярам элементов управления, это лишь возможность определить значения свойств элементам, которые будут созданы в процессе формирования страницы. Через коллекцию Controls невозможно получить доступ к публичным методам элемента управления.
Resources Коллекция (ключ=значение) Коллекция ресурсов локализации; где ключ - имя ресурса, а значение - локализованная строка.
Программно изменить ресурсы можно в обработчике события Load.

Все публичные свойства доступны для классов-потомков, т.е. классов страниц.

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

Свойства

У страницы существует три события, которые можно обработать.

PreLoad

Событие PreLoad возникает после инициализации страницы, до начала вывода HTTP-заголовков, загрузки шаблона и ресурсов локализации.

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

Управлять ресурсами локализации (свойство Resources) в обработчике этого события не имеет смысла, т.к. ресурсы перезаписываются при загрузке файлов локализации. Однако можно изменить Culture, чтобы загрузились ресурсы для определенного языка.

В следующем примере показано изменение файла шаблона в обработчике события PreLoad.

<?php
require_once 'global.php';

class Index extends \Nemiro\UI\Page
{

  function PreLoad()
  {
    $this->Layout = '/example.html';
  }

}

\Nemiro\App::Magic();
?>

Load

Событие Load происходит перед формированием данных для вывода.

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

В следующем примере показано изменение заголовка страницы в обработчике события Load и добавление описания в метатеги страницы при помощи метода SetDescription.

<?php
require_once 'global.php';

class Index extends \Nemiro\UI\Page
{

  function Load()
  {
    $this->Title = 'Новый заголовок страницы';
    $this->SetDescription('Описание страницы.');
  }

}

\Nemiro\App::Magic();
?>

LoadComplete

Событие LoadComplete происходит после формирования и вывода данных.

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

<?php
require_once 'global.php';

class Index extends \Nemiro\UI\Page
{

  function LoadComplete()
  {
    echo 'Страница сформирована!';
  }

}

\Nemiro\App::Magic();
?>

Локализация

Для локализации страниц можно использовать локальные и глобальные ресурсы (global.json).

Локальные ресурсы - это файлы с расширением .json, имеющие тоже название, что и основной файл страницы. В имени файла должна указываться культура (язык), для которой предназначены ресурсы.

Например, для страницы index.php могут быть следующие файлы ресурсов: index.json - ресурсы по умолчанию, index.ru.json - ресурсы для русского языка, index.en.json - ресурсы для английского языка, index.de.json - ресурсы для немецкого языка и т.п.

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

Подробнее о механизмах локализации.