Рендеринг нативных PHP-представлений
«devanych/view-renderer» — это маленькая и простая в использовании PHP-библиотека, предназначенная для рендеринга нативных PHP-представлений. Несмотря на простоту, данный пакет дает возможность внедрения собственной функциональности.
Особенности пакета:
- удобная плоская система блоков;
- поддержка использования существующих PHP-функций;
- установка глобальных параметров для всех представлений;
- гибкий функционал шаблонов с неограниченной вложенностью;
- легкая расширяемость при помощи добавления собственных функций.
Простейший пример рендеринга:
use Devanych\View\Renderer;
$renderer = new Renderer('/path/to/root/directory/of/views');
$content = $renderer->render('path/to/view/file', [
'variableName' => 'значение переменной любого типа',
]);
echo $content;
Метод render()
первым аргументом принимает путь к файлу представления, который должен быть относительно директории, переданной конструктору при создании объекта. Вторым аргументом передается массив параметров name => value
), которые будут преобразованы в переменные внутри представления.
$renderer->render('post/show', [
'post' => $posts->get($id),
]);
В представлении:
<h1><?=$post->getName();?></h1>
Файл представления может быть с расширением или без него, если расширение файла не указано, то по умолчанию подставится .php
. Расширение по умолчанию можно изменить, передав его в конструктор вторым аргументом.
$renderer = new Renderer('/path/to/root/directory/of/views', 'tpl');
Внутри шаблонов и представлений экземпляр рендерера доступен в $this
.
<title><?=$this->renderBlock('title');?></title>
Блоки
Методы block()
, beginBlock()
и endBlock()
позволяют создавать блоки контента в вашем представлении. Содержимое блоков сохраняется для использования в любом месте представления, а также в любом родительском шаблоне. Метод renderBlock()
рендерит сохраненный контент блока.
Код шаблона:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><?=$this->renderBlock('title');?></title>
<?=$this->renderBlock('meta');?>
</head>
<body class="app">
<?=$this->renderBlock('content');?>
</body>
</html>
Код представления:
<?php
declare(strict_types=1);
/** @var Devanych\View\Renderer $this */
$this->layout('layouts/main');
$this->block('title', 'Page Title');
?>
<p>Page Content</p>
<?php $this->beginBlock('meta');?>
<meta name="description" content="Page Description">
<?php $this->endBlock();?>
Результат рендеринга:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Title</title>
<meta name="description" content="Page Description">
</head>
<body class="app">
<p>Page Content</p>
</body>
</html>
Блоки нельзя вкладывать друг в друга, но можно рендерить один блок внутри другого.
<!-- Можно -->
<?php $this->beginBlock('parent');?>
<!-- ... -->
<?=$this->renderBlock('children');?>
<!-- ... -->
<?php $this->endBlock();?>
<!-- Нельзя -->
<?php $this->beginBlock('parent');?>
<!-- ... -->
<?php $this->beginBlock('children');?>
<!-- ... -->
<?php $this->endBlock();?>
<!-- ... -->
<?php $this->endBlock();?>
Обратите внимание, что content
является зарезервированным именем блока, он рендерит контент преставления и дочерних шаблонов. Если попытаться создать блок с именем content
, то будет брошено исключение \RuntimeException
.
При вызове метода renderBlock()
с именем несуществующего блока, метод renderBlock()
вернет пустую строку, поэтому дополнительные методы проверки существования блока не нужны. Вторым аргументом в renderBlock()
можно передать значение по умолчанию, которое будет подставлено, если блока с указанным именем не существует.
<!-- Вывести контент блока, если он существует -->
<?php if ($name = $this->renderBlock('name')): ?>
<h1><?=$name;?></h1>
<?php endif;?>
<!-- Вывести контент по умолчанию, если блок не существует -->
<?=$this->renderBlock('title', 'Default Title');?>
<!-- или используя другой блок -->
<?=$this->renderBlock('title', $this->renderBlock('default-title'));?>
Шаблоны
Шаблоны — это особый тип преставлений, которые очень удобно использовать для рендеринга повторяющихся частей (хедер, футер, сайдбар и т.д.). Данный пакет позволяет строить цепочки шаблонов с неограниченной вложенностью. Наследование шаблона устанавливается в файле представления или дочернего шаблона методом layout()
.
Код родительского шаблона (layouts/main
):
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><?=$this->renderBlock('title');?></title>
</head>
<body class="app">
<?=$this->renderBlock('content');?>
</body>
</html>
Код дочернего шаблона (layouts/columns
):
<?php
declare(strict_types=1);
/** @var Devanych\View\Renderer $this */
$this->layout('layouts/main');
?>
<main class="main">
<?=$this->renderBlock('content');?>
</main>
<aside class="sidebar">
<!-- Sidebar Code -->
</aside>
Код представления (site/page
):
<?php
declare(strict_types=1);
/** @var Devanych\View\Renderer $this */
$this->layout('layouts/columns');
$this->block('title', 'Page Title');
?>
<p>Page Content</p>
Рендеринг представления:
$renderer->render('site/page', [/* параметры */]);
Результат рендеринга:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Title</title>
</head>
<body class="app">
<main class="main">
<p>Page Content</p>
</main>
<aside class="sidebar">
<!-- Sidebar Code -->
</aside>
</body>
</html>
Если необходимо просто отрендерить файл дочернего шаблона из родительского, можно воспользоваться методом render()
.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><?=$this->renderBlock('title');?></title>
</head>
<body class="app">
<?=$this->render('layouts/_header.php')?>
<?=$this->renderBlock('content');?>
<?=$this->render('layouts/_footer.php', [
'parameter' => 'value'
])?>
</body>
</html>
Результат рендеринга:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Page Title</title>
</head>
<body class="app">
<header>Header</header>
<p>Page Content</p>
<footer>Footer</footer>
</body>
</html>
Расширения
Функционал расширений позволяет добавлять собственные функции и использовать их внутри шаблонов и представлений. Чтобы добавить функцию, нужно создать собственный класс, реализующий интерфейс «Devanych\View\Extension\ExtensionInterface». Интерфейс содержит всего один метод, возвращающий массив, ключами которого являются названия добавляемых функций, а значениями могут быть любые возможные варианты типа callable
.
interface ExtensionInterface
{
/**
* Returns an array of functions as `function name` => `function callback`.
*
* @return array<string, callable>
*/
public function getFunctions(): array;
}
Данный пакет содержит одно расширение «Devanych\View\Extension\AssetExtension», которое упрощает подключения ассетов (скриптов, стилей, шрифтов и т.д.) и добавляет метку времени к файлу. Для добавления расширения нужно воспользоваться методом addExtension()
.
$extension = new AssetExtension('/path/to/assets', 'https://examle.com/assets', true);
$renderer->addExtension($extension);
// Результат: 'https://examle.com/assets/css/style.css?v=1601742615'
$renderer->asset('css/style.css');
Глобальные параметры
Используя метод addGlobal()
, можно добавлять глобальные параметры, которые будут доступны во всех представлениях и шаблонах.
// Переменная `$variableName` теперь будет доступна внутри файлов.
$renderer->addGlobal( 'variableName', 'значение переменной любого типа');
Повторное добавление переменной с одним и тем же именем вызовет исключение \RuntimeException
, но есть возможность изменить значение глобальной переменной для конкретного представления, для этого нужно передать параметр с таким же именем при рендеринге представления или просто присвоить в самом представлении.
// Для всех представлений и шаблонов значение `$author` будет равняться `Boby`
$renderer->addGlobal( 'author', 'Boby');
// Только для представления `blog/page` значение `$author` будет равняться `John`
$renderer->render('blog/page', [
'author' => 'John',
]);
// или присвоить значение в представлении
$author = 'John';
Экранирование
Для предотвращения вывода потенциально опасного HTML-кода рендерер содержит метод esc()
, который экранирует специальные символы, а точнее, преобразует их в соответствующие HTML-сущности.
// Результат: '<script>alert(123);</script>'
$renderer->esc('<script>alert(123);</script>');
// Эквивалентно: `htmlspecialchars($content, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8', true)`
Данный метод сделан для удобства, но можно использовать и оригинальную функцию htmlspecialchars()
, так как в предтавлениях и шаблонах доступны все существующие функци PHP.
Коментарии ( 0 )