Мы пойдём другим путём. Я решился попробовать реализовать эту хню когда увидел в Symfony 2 такой фрагмент:
[tt]<?php $view->extend('HelloBundle::layout') ?>[/tt]
Типа шаблоны нативные, но за счет класса-обертки появляется дополнительный функционал.
Неплохо. Ну давай клепать своё, чтобы было просто и красиво!
v1:
Заведем простейшую обертку над нативным шаблоном:
[tt]index.php[/tt]
<?php
class MyView
{
public function render($id, $data)
{
extract($data);
include 'templates/' . $id . '.php';
}
}
// —– Test
$view = new MyView();
$view->render('test', array('title' => 'Blablabla', 'text' => 'The wind has blown over ther ocean'));
[tt]templates/test.php[/tt]
<h1><?php echo $title ?></h1>
<p><?php echo $text ?></p>
Негусто, но работает. Попытаемся в лоб обернуть этот шаблон в шапку и валенки.
v2:
Класс оставляем таким же, а в шаблоне инклудим постоянные составляющие.
[tt]templates/test.php[/tt]
<?php
include 'templates/header.php';
?>
<h1><?php echo $title ?></h1>
<p><?php echo $text ?></p>
<?php
include 'templates/footer.php';
?>
[tt]templates/header.php[/tt]
<html>
<head>
<title><?php echo $title ?></title>
</head>
<body>
<div id="content">
[tt]templates/footer.php[/tt]
</div>
</body>
</html>
Работает, но это как-то некашерно.
v3:
Рожаем наследование шаблона через вызов метода extend() — позаимствуем слово из Symfony
[tt]templates/test.php[/tt]
<?php
$this->extend('default');
?>
<h1><?php echo $title ?></h1>
<p><?php echo $text ?></p>
[tt]templates/default.php[/tt]
<?php
$this->extend('page-layout');
?>
<!– Default content –>
<p>No content yet</p>
[tt]templates/page-layout.php[/tt]
<html>
<head>
<title><?php echo $title ?></title>
<style>
#sidebar { float: left; padding: 0 0.5em; width: 200px; border-right: solid 1px #b00; }
#content { float: left; padding: 0 0.5em; margin-left: -1px; border-left: solid 1px #b00; }
</style>
</head>
<body>
<div id="sidebar">
<h4>Sidebar</h4>
<?php $this->output('sidebar') ?>
</div>
<div id="content">
<?php $this->output('content') ?>
</div>
</body>
</html>
Я тут сделал даже заготовку под сайдбар, но пока наследую/перекрываю только контент. Если в test.php удалить весь контент, то сработает контент из базового шаблона. В конечном счете весь контент в самом "родительском" шаблоне оборачивается в шапку и валенки. Красота!
А вот и новый класс:
[tt]index.php[/tt]
<?php
error_reporting(-1);
class MyView
{
private
$_parents = array(),
$_blocks = array();
public function render($id, $data)
{
extract($data);
include 'templates/' . $id . '.php';
while (!empty($this->_parents)) {
$this->_grab('content');
include 'templates/' . array_pop($this->_parents) . '.php';
}
}
private function extend($id)
{
array_push($this->_parents, $id);
ob_start();
}
private function output($block, $default = '')
{
if (isset($this->_blocks[$block])) {
echo $this->_blocks[$block];
}
}
private function _grab($block)
{
if (isset($this->_blocks[$block])) {
ob_end_clean();
return;
}
$tmp = ob_get_clean();
if (strlen(trim($tmp)) > 0) {
$this->_blocks[$block] = $tmp;
}
}
}
// —– Test
$view = new MyView();
$view->render('test', array('title' => 'Blablabla', 'text' => 'The wind has blown over ther ocean'));
Почти совершенство. Теперь надо как-то задавать другие блоки кроме основного контента.
v4:
Определение блоков через вызов blockBegin-blockEnd
[tt]index.php[/tt]
<?php
error_reporting(-1);
class MyView
{
private
$_parents = array(),
$_names = array(),
$_blocks = array();
public function render($id, $data)
{
extract($data);
include 'templates/' . $id . '.php';
while (!empty($this->_parents)) {
$this->_grab('content');
include 'templates/' . array_pop($this->_parents) . '.php';
}
}
private function extend($id)
{
array_push($this->_parents, $id);
ob_start();
}
private function blockBegin($block)
{
array_push($this->_names, $block);
ob_start();
}
private function blockEnd()
{
$this->_grab(array_pop($this->_names));
}
private function output($block, $default = '')
{
echo (isset($this->_blocks[$block])) ?
$this->_blocks[$block] :
$default;
}
private function _grab($block)
{
if (isset($this->_blocks[$block])) {
ob_end_clean();
return;
}
$tmp = ob_get_clean();
if (strlen(trim($tmp)) > 0) {
$this->_blocks[$block] = $tmp;
}
}
}
// —– Test
$view = new MyView();
$view->render('test', array('title' => 'Blablabla', 'text' => 'The wind has blown over ther ocean'));
[tt]templates/test.php[/tt]
<?php
$this->extend('default');
?>
<h1><?php echo $title ?></h1>
<p><?php echo $text ?></p>
<?php $this->blockBegin('sidebar') ?>
<!– New sidebar –>
<ul>
<li>lorem</li>
<li>ipsum</li>
<li>dolor</li>
<li>sit</li>
<li>amet</li>
</ul>
<?php $this->blockEnd() ?>
Задача выполнена: просто и достаточно красиво, imho.