Использование представлений
Представления представляют пользовательский интерфейс вашего приложения. Представления часто являются HTML-файлами с встроенным PHP-кодом, который выполняет задачи, связанные только с представлением данных. Представления выполняют работу по предоставлению данных веб-браузеру или другому инструменту, используемому для отправки запросов вашему приложению.
За управление слоем представлений вашего приложения MVC отвечают Phalcon\Mvc\View и Phalcon\Mvc\View\Simple.
Интеграция представлений с контроллерами
Phalcon автоматически передает выполнение компоненту представления, как только определенный контроллер завершит свой цикл. Компонент представления будет искать в папке представлений папку с таким же именем, как у последнего выполненного контроллера, а затем файл с именем последнего выполненного действия. Например, если запрос отправлен на URL http://127.0.0.1/blog/posts/show/301, Phalcon разобъёт URL следующим образом:
| Адрес сервера | 127.0.0.1 |
| Директория Phalcon | blog |
| Контроллер | posts |
| Действие | show |
| Параметр | 301 |
Диспетчер будет искать контроллер “PostsController” и его действие “showAction”. Пример простого файла контроллера для этого случая:
class PostsController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
}
public function showAction($postId)
{
// Pass the $postId parameter to the view
$this->view->setVar("postId", $postId);
}
}
Метод setVar позволяет динамически создавать переменные представления, чтобы их можно было использовать в шаблоне представления. Приведённый пример демонстрирует, как передать параметр $postId в соответствующий шаблон представления.
Иерархическое рендеринг
Phalcon\Mvc\View поддерживает иерархию файлов и является компонентом по умолчанию для рендеринга представлений в Phalcon. Эта иерархия позволяет использовать общие макеты (часто используемые представления), а также папки с именами контроллеров, определяющие соответствующие шаблоны представлений.
Этот компонент по умолчанию использует сам PHP в качестве движка шаблонов, поэтому представления должны иметь расширение .phtml. Если директория представлений — app/views, то компонент представления автоматически найдёт эти 3 файла представления.
| Имя | Файл | Описание |
|---|---|---|
| Представление действия | app/views/posts/show.phtml | Это представление, связанное с действием. Оно будет отображаться только при выполнении действия “show”. |
| Макет контроллера | app/views/layouts/posts.phtml | Это представление, связанное с контроллером. Оно будет отображаться для каждого действия, выполненного в контроллере “posts”. Весь код, реализованный в макете, будет повторно использован для всех действий в этом контроллере. |
| Главный макет | app/views/index.phtml | Это главное действие, оно будет отображаться для каждого контроллера или действия, выполненного в приложении. |
Вам не нужно реализовывать все упомянутые выше файлы. Phalcon\Mvc\View просто перейдёт к следующему уровню представления в иерархии файлов. Если все три файла представления реализованы, они будут обработаны следующим образом:
<!-- app/views/posts/show.phtml --> <h3>This is show view!</h3> <p>I have received the parameter <?php echo $postId ?></p>
<!-- app/views/layouts/posts.phtml --> <h2>This is the "posts" controller layout!</h2> <?php echo $this->getContent() ?>
<!-- app/views/index.phtml -->
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>This is main layout!</h1>
<?php echo $this->getContent() ?>
</body>
</html>
Обратите внимание на строки, где вызывается метод $this->getContent(). Этот метод указывает Phalcon\Mvc\View, где вставить содержимое ранее выполненного представления в иерархии. В приведённом примере результатом будет:
Сгенерированный HTML по запросу будет:
<!-- app/views/index.phtml -->
<html>
<head>
<title>Example</title>
</head>
<body>
<h1>This is main layout!</h1>
<!-- app/views/layouts/posts.phtml -->
<h2>This is the "posts" controller layout!</h2>
<!-- app/views/posts/show.phtml -->
<h3>This is show view!</h3>
<p>I have received the parameter 101</p>
</body>
</html>
Использование шаблонов
Шаблоны — это представления, которые могут быть использованы для совместного использования кода представления. Они действуют как макеты контроллеров, поэтому их необходимо разместить в директории макетов.
class PostsController extends \Phalcon\Mvc\Controller
{
public function initialize()
{
$this->view->setTemplateAfter('common');
}
public function lastAction()
{
$this->flash->notice("These are the latest posts");
}
}
<!-- app/views/index.phtml -->
<!DOCTYPE html>
<html>
<head>
<title>Blog's title</title>
</head>
<body>
<?php echo $this->getContent() ?>
</body>
</html>
<!-- app/views/layouts/common.phtml -->
<ul class="menu">
<li><a href="/">Home</a></li>
<li><a href="/articles">Articles</a></li>
<li><a href="/contact">Contact us</a></li>
</ul>
<div class="content"><?php echo $this->getContent() ?></div>
<!-- app/views/layouts/posts.phtml --> <h1>Blog Title</h1> <?php echo $this->getContent() ?>
<!-- app/views/posts/last.phtml -->
<article>
<h2>This is a title</h2>
<p>This is the post content</p>
</article>
<article>
<h2>This is another title</h2>
<p>This is another post content</p>
</article>
Конечный результат будет следующим:
<!-- app/views/index.phtml -->
<!DOCTYPE html>
<html>
<head>
<title>Blog's title</title>
</head>
<body>
<!-- app/views/layouts/common.phtml -->
<ul class="menu">
<li><a href="/">Home</a></li>
<li><a href="/articles">Articles</a></li>
<li><a href="/contact">Contact us</a></li>
</ul>
<div class="content">
<!-- app/views/layouts/posts.phtml -->
<h1>Blog Title</h1>
<!-- app/views/posts/last.phtml -->
<article>
<h2>This is a title</h2>
<p>This is the post content</p>
</article>
<article>
<h2>This is another title</h2>
<p>This is another post content</p>
</article>
</div>
</body>
</html>
Управление уровнями рендеринга
Как видно выше, Phalcon\Mvc\View поддерживает иерархию представлений. Вам может потребоваться контролировать уровень рендеринга, производимого компонентом представления. Метод PhalconMvc\View::setRenderLevel() предлагает эту функциональность.
Этот метод можно вызвать из контроллера или из высшего слоя представления, чтобы повлиять на процесс рендеринга.
use Phalcon\Mvc\Controller,
Phalcon\Mvc\View;
class PostsController extends Controller
{
public function indexAction()
{
}
public function findAction()
{
// This is an Ajax response so it doesn't generate any kind of view
$this->view->setRenderLevel(View::LEVEL_NO_RENDER);
//...
}
public function showAction($postId)
{
// Shows only the view related to the action
$this->view->setRenderLevel(View::LEVEL_ACTION_VIEW);
}
}
Доступные уровни рендеринга:
| Постоянная класса | Описание | Порядок |
|---|---|---|
| LEVEL_NO_RENDER | Указывает на избегание генерации любого вида представления. | |
| LEVEL_ACTION_VIEW | Генерирует представление для представления, связанного с действием. | 1 |
| LEVEL_BEFORE_TEMPLATE | Генерирует шаблоны представления до макета контроллера. | 2 |
| LEVEL_LAYOUT | Генерирует представление для макета контроллера. | 3 |
| LEVEL_AFTER_TEMPLATE | Генерирует представление для шаблонов после макета контроллера. | 4 |
| LEVEL_MAIN_LAYOUT | Генерирует представление для главного макета. Файл views/index.phtml | 5 |
Отключение уровней рендеринга
Вы можете временно или постоянно отключить уровни рендеринга. Уровень может быть постоянно отключён, если он вообще не используется во всём приложении:
use Phalcon\Mvc\View;
$di->set('view', function(){
$view = new View();
//Disable several levels
$view->disableLevel(array(
View::LEVEL_LAYOUT => true,
View::LEVEL_MAIN_LAYOUT => true
));
return $view;
}, true);
Или временно отключить в какой-то части приложения:
use Phalcon\Mvc\View,
Phalcon\Mvc\Controller;
class PostsController extends Controller
{
public function indexAction()
{
}
public function findAction()
{
$this->view->disableLevel(View::LEVEL_MAIN_LAYOUT);
}
}
Выбор представлений
Как упоминалось выше, когда Phalcon\Mvc\View управляется Phalcon\Mvc\Application, рендеринг представления связан с последним выполненным контроллером и действием. Вы можете переопределить это, используя метод Phalcon\Mvc\View::pick():
class ProductsController extends \Phalcon\Mvc\Controller
{
public function listAction()
{
// Pick "views-dir/products/search" as view to render
$this->view->pick("products/search");
// Pick "views-dir/products/list" as view to render
$this->view->pick(array('products'));
// Pick "views-dir/products/list" as view to render
$this->view->pick(array(1 => 'search'));
}
}
Отключение представления
Если ваш контроллер не генерирует никакого вывода в представлении (или даже не имеет его), вы можете отключить компонент представления, избежав ненужной обработки:
class UsersController extends \Phalcon\Mvc\Controller
{
public function closeSessionAction()
{
//Close session
//...
//An HTTP Redirect
$this->response->redirect('index/index');
//Disable the view to avoid rendering
$this->view->disable();
}
}
Вы можете вернуть объект «response», чтобы избежать ручного отключения представления:
class UsersController extends \Phalcon\Mvc\Controller
{
public function closeSessionAction()
{
//Close session
//...
//An HTTP Redirect
return $this->response->redirect('index/index');
}
}
Простое рендеринг
Phalcon\Mvc\View\Simple — это альтернативный компонент Phalcon\Mvc\View. Он сохраняет большую часть философии Phalcon\Mvc\View, но не имеет иерархии файлов, которая, по сути, является его основной функцией.
Этот компонент позволяет разработчику контролировать время рендеринга представления и его расположение. Кроме того, этот компонент может использовать наследование представлений, доступное в движках шаблонов, таких как Volt и других.
Компонент по умолчанию необходимо заменить в контейнере сервисов:
$di->set('view', function() {
$view = new Phalcon\Mvc\View\Simple();
$view->setViewsDir('../app/views/');
return $view;
}, true);
Автоматический рендеринг необходимо отключить в Phalcon\Mvc\Application (если необходимо):
try {
$application = new Phalcon\Mvc\Application($di);
$application->useImplicitView(false);
echo $application->handle()->getContent();
} catch (\Exception $e) {
echo $e->getMessage();
}
Чтобы выполнить рендеринг представления, необходимо явно вызвать метод render, указав относительный путь к представлению, которое нужно отобразить:
class PostsController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
//Render 'views-dir/index.phtml'
echo $this->view->render('index');
//Render 'views-dir/posts/show.phtml'
echo $this->view->render('posts/show');
//Render 'views-dir/index.phtml' passing variables
echo $this->view->render('index', array('posts' => Posts::find()));
//Render 'views-dir/posts/show.phtml' passing variables
echo $this->view->render('posts/show', array('posts' => Posts::find()));
}
}
Использование частичных представлений
Частичные шаблоны — это ещё один способ разбить процесс рендеринга на более простые и управляемые фрагменты, которые можно повторно использовать в разных частях приложения. С помощью частичного представления вы можете перенести код для рендеринга определённой части ответа в отдельный файл.
Один из способов использования частичных представлений — рассматривать их как эквивалент подпрограмм: как способ вынести детали из представления, чтобы код стал более понятным. Например, у вас может быть представление, которое выглядит так:
<div class="top"><?php $this->partial("shared/ad_banner") ?></div>
<div class="content">
<h1>Robots</h1>
<p>Check out our specials for robots:</p>
...
</div>
<div class="footer"><?php $this->partial("shared/footer") ?></div>
Метод partial() принимает второй параметр в виде массива переменных/параметров, которые существуют только в области видимости частичного представления:
<?php $this->partial("shared/ad_banner", array('id' => $site->id, 'size' => 'big')) ?>
Передача значений из контроллера в представления
Phalcon\Mvc\View доступен в каждом контроллере с помощью переменной представления ($this->view). Вы можете использовать этот объект для прямой установки переменных в представление из действия контроллера, используя метод setVar().
class PostsController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
}
public function showAction()
{
//Pass all the posts to the views
$this->view->setVar("posts", Posts::find());
//Using the magic setter
$this->view->posts = Posts::find();
//Passing more than one variable at the same time
$this->view->setVars(array(
'title' => $post->title,
'content' => $post->content
));
}
}
Переменная с именем первого параметра setVar() будет создана в представлении, готовая к использованию. Переменная может быть любого типа, от простой строки, целого числа и т. д. до более сложной структуры, такой как массив, коллекция и т. д.
<div class="post">
<?php
foreach ($posts as $post) {
echo "<h1>", $post->title, "</h1>";
}
?>
</div>
Использование моделей в слое представления
Модели приложения всегда доступны в слое представления. Phalcon\Loader будет инициализировать их во время выполнения автоматически:
<div class="categories">
<?php
foreach (Categories::find("status = 1") as $category) {
echo "<span class='category'>", $category->name, "</span>";
}
?>
</div>
Хотя вы можете выполнять операции с моделью, такие как insert() или update(), в слое представления, это не рекомендуется, так как невозможно перенаправить поток выполнения в другой контроллер в случае ошибки или исключения.
Кэширование фрагментов представления
Иногда при разработке динамических веб-сайтов некоторые области не обновляются очень часто, а вывод идентичен между запросами. Phalcon\Mvc\View предлагает кэширование части или всего вывода для повышения производительности.
Phalcon\Mvc\View интегрируется с Phalcon\Cache, чтобы предоставить более простой способ кэширования фрагментов вывода. Вы можете вручную установить обработчик кэша или установить глобальный обработчик:
class PostsController extends \Phalcon\Mvc\Controller
{
public function showAction()
{
//Cache the view using the default settings
$this->view->cache(true);
}
public function showArticleAction()
{
// Cache this view for 1 hour
$this->view->cache(array(
"lifetime" => 3600
));
}
public function resumeAction()
{
//Cache this view for 1 day with the key "resume-cache"
$this->view->cache(
array(
"lifetime" => 86400,
"key" => "resume-cache",
)
);
}
public function downloadAction()
{
//Passing a custom service
$this->view->cache(
array(
"service" => "myCache",
"lifetime" => 86400,
"key" => "resume-cache",
)
);
}
}
Когда мы не определяем ключ для кэша, компонент автоматически создаёт его, используя md5 имени представления, которое в настоящее время рендерится. Хорошей практикой является определение ключа для каждого действия, чтобы вы могли легко идентифицировать кэш, связанный с каждым представлением.
Когда компоненту представления нужно кэшировать что-то, он запросит службу кэширования в контейнере служб. Конвенция именования для этой службы — “viewCache”:
use Phalcon\Cache\Frontend\Output as OutputFrontend,
Phalcon\Cache\Backend\Memcache as MemcacheBackend;
//Set the views cache service
$di->set('viewCache', function() {
//Cache data for one day by default
$frontCache = new OutputFrontend(array(
"lifetime" => 86400
));
//Memcached connection settings
$cache = new MemcacheBackend($frontCache, array(
"host" => "localhost",
"port" => "11211"
));
return $cache;
});
Фронтенд всегда должен быть Phalcon\Cache\Frontend\Output, а служба «viewCache» должна быть зарегистрирована как всегда открытая (не общая) в контейнере служб (DI)
При использовании кэширования представлений также полезно предотвращать выполнение контроллерами процессов, которые генерируют данные для отображения в представлениях.
Для достижения этого мы должны уникально идентифицировать каждый кэш с помощью ключа. Сначала мы проверяем, существует ли кэш или не истек срок его действия, чтобы выполнить вычисления/запросы для отображения данных в представлении:
class DownloadController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
//Check whether the cache with key "downloads" exists or has expired
if ($this->view->getCache()->exists('downloads')) {
//Query the latest downloads
$latest = Downloads::find(array(
'order' => 'created_at DESC'
));
$this->view->latest = $latest;
}
//Enable the cache with the same key "downloads"
$this->view->cache(array(
'key' => 'downloads'
));
}
}
Сайт PHP alternative site является примером реализации кэширования фрагментов.
Движки шаблонов
Движки шаблонов помогают разработчикам создавать представления без использования сложной синтаксической конструкции. Phalcon включает мощный и быстрый движок шаблонов под названием Volt.
Кроме того, Phalcon\Mvc\View позволяет использовать другие движки шаблонов вместо обычного PHP или Volt.
Использование другого движка шаблонов обычно требует сложной обработки текста с помощью внешних библиотек PHP для генерации конечного вывода для пользователя. Это обычно увеличивает количество ресурсов, используемых приложением.
Если используется внешний движок шаблонов, Phalcon\Mvc\View предоставляет точно такую же иерархию представлений, и все еще возможно получить доступ к API внутри этих шаблонов с небольшими усилиями.
Этот компонент использует адаптеры, которые помогают Phalcon взаимодействовать с внешними движками шаблонов унифицированным способом, давайте посмотрим, как выполнить эту интеграцию.
Создание собственного адаптера движка шаблонов
Существует много движков шаблонов, которые вы можете интегрировать или создать свой собственный. Первый шаг для начала использования внешнего движка шаблонов — создание адаптера для него.
Адаптер движка шаблонов — это класс, который выступает в качестве посредника между Phalcon\Mvc\View и самим движком шаблонов. Обычно для него необходимо реализовать только два метода: __construct() и render(). Первый принимает экземпляр Phalcon\Mvc\View, который создает адаптер движка, и контейнер DI, используемый приложением.
Метод render() принимает абсолютный путь к файлу представления и параметры представления, установленные с помощью $this->view->setVar(). Вы можете читать или требовать его, когда это необходимо.
class MyTemplateAdapter extends \Phalcon\Mvc\View\Engine
{
/**
* Adapter constructor
*
* @param \Phalcon\Mvc\View $view
* @param \Phalcon\DI $di
*/
public function __construct($view, $di)
{
//Initialize here the adapter
parent::__construct($view, $di);
}
/**
* Renders a view using the template engine
*
* @param string $path
* @param array $params
*/
public function render($path, $params)
{
// Access view
$view = $this->_view;
// Access options
$options = $this->_options;
//Render the view
//...
}
}
Изменение движка шаблонов
Вы можете заменить или добавить больше движков шаблонов из контроллера следующим образом:
class PostsController extends \Phalcon\Mvc\Controller
{
public function indexAction()
{
// Set the engine
$this->view->registerEngines(
array(
".my-html" => "MyTemplateAdapter"
)
);
}
public function showAction()
{
// Using more than one template engine
$this->view->registerEngines(
array(
".my-html" => 'MyTemplateAdapter',
".phtml" => 'Phalcon\Mvc\View\Engine\Php'
)
);
}
}
Вы можете полностью заменить движок шаблонов или использовать несколько движков шаблонов одновременно. Метод Phalcon\Mvc\View::registerEngines() принимает массив, содержащий данные, определяющие движки шаблонов. Ключ каждого движка — это расширение, которое помогает отличить один от другого. Файлы шаблонов, относящиеся к конкретному движку, должны иметь эти расширения.
Порядок определения движков шаблонов с помощью Phalcon\Mvc\View::registerEngines() определяет приоритет выполнения. Если Phalcon\Mvc\View находит два представления с одинаковым именем, но различными расширениями, он будет отображать только первое.
Если вы хотите зарегистрировать движок шаблонов или набор из них для каждого запроса в приложении. Вы можете зарегистрировать его при создании службы представления:
//Setting up the view component
$di->set('view', function() {
$view = new \Phalcon\Mvc\View();
//A trailing directory separator is required
$view->setViewsDir('../app/views/');
$view->registerEngines(array(
".my-html" => 'MyTemplateAdapter'
));
return $view;
}, true);
На Phalcon Incubator доступны адаптеры для нескольких движков шаблонов.
Внедрение служб в представление
Каждое исполняемое представление включено в экземпляр Phalcon\DI\Injectable, что обеспечивает легкий доступ к контейнеру служб приложения.
Следующий пример демонстрирует, как написать запрос jQuery ajax с использованием URL с соглашениями фреймворка. Служба «url» (обычно Phalcon\Mvc\Url) внедряется в представлении с помощью доступа к свойству с таким же именем:
<script type="text/javascript">
$.ajax({
url: "<?php echo $this->url->get("cities/get") ?>"
})
.done(function() {
alert("Done!");
});
</script>
Самостоятельный компонент
Все компоненты в Phalcon могут использоваться как отдельные компоненты-связки, поскольку они слабо связаны друг с другом:
Иерархическое отображение
Использование Phalcon\Mvc\View в режиме автономного использования продемонстрировано ниже
$view = new \Phalcon\Mvc\View();
//A trailing directory separator is required
$view->setViewsDir("../app/views/");
// Passing variables to the views, these will be created as local variables
$view->setVar("someProducts", $products);
$view->setVar("someFeatureEnabled", true);
//Start the output buffering
$view->start();
//Render all the view hierarchy related to the view products/list.phtml
$view->render("products", "list");
//Finish the output buffering
$view->finish();
echo $view->getContent();
Также доступен короткий синтаксис:
$view = new \Phalcon\Mvc\View();
echo $view->getRender('products', 'list',
array(
"someProducts" => $products,
"someFeatureEnabled" => true
),
function($view) {
//Set any extra options here
$view->setViewsDir("../app/views/");
$view->setRenderLevel(Phalcon\Mvc\View::LEVEL_LAYOUT);
}
);
Простое отображение
Использование Phalcon\Mvc\View\Simple в режиме автономного использования продемонстрировано ниже:
$view = new \Phalcon\Mvc\View\Simple();
//A trailing directory separator is required
$view->setViewsDir("../app/views/");
// Render a view and return its contents as a string
echo $view->render("templates/welcomeMail");
// Render a view passing parameters
echo $view->render("templates/welcomeMail", array(
'email' => $email,
'content' => $content
));
События представления
Phalcon\Mvc\View и Phalcon\Mvc\View могут отправлять события в EventsManager, если он присутствует. События срабатывают с типом «view». Некоторые события при возвращении false могут остановить активную операцию. Поддерживаются следующие события:
| Имя события | Срабатывание | Может остановить операцию? |
|---|---|---|
| beforeRender | Срабатывает перед началом процесса отображения | Да |
| beforeRenderView | Срабатывает перед отображением существующего представления | Да |
| afterRenderView | Срабатывает после отображения существующего представления | Нет |
| afterRender | Срабатывает после завершения процесса отображения | Нет |
| notFoundView | Срабатывает, когда представление не найдено | Нет |
Следующий пример демонстрирует, как подключить обработчики к этому компоненту:
$di->set('view', function() {
//Create an events manager
$eventsManager = new Phalcon\Events\Manager();
//Attach a listener for type "view"
$eventsManager->attach("view", function($event, $view) {
echo $event->getType(), ' - ', $view->getActiveRenderPath(), PHP_EOL;
});
$view = new \Phalcon\Mvc\View();
$view->setViewsDir("../app/views/");
//Bind the eventsManager to the view component
$view->setEventsManager($eventsManager);
return $view;
}, true);
Следующий пример показывает, как создать плагин, который очищает/восстанавливает HTML, созданный процессом отображения, с помощью Tidy:
class TidyPlugin
{
public function afterRender($event, $view)
{
$tidyConfig = array(
'clean' => true,
'output-xhtml' => true,
'show-body-only' => true,
'wrap' => 0,
);
$tidy = tidy_parse_string($view->getContent(), $tidyConfig, 'UTF8');
$tidy->cleanRepair();
$view->setContent((string) $tidy);
}
}
//Attach the plugin as a listener
$eventsManager->attach("view:afterRender", new TidyPlugin());
© 2011–2016 Phalcon Framework Team
Licensed under the Creative Commons Attribution License 3.0.
https://docs.phalconphp.com/en/2.0.0/reference/views.html