mirror of
https://github.com/yiisoft/yii2.git
synced 2025-08-15 06:40:59 +08:00
645 lines
46 KiB
Markdown
645 lines
46 KiB
Markdown
Виды
|
||
====
|
||
|
||
Виды - это часть [MVC](https://ru.wikipedia.org/wiki/Model-View-Controller) архитектуры, это код, который отвечает за представление данных
|
||
конечным пользователям. В веб приложениях виды создаются обычно в виде *видов - шаблонов*, которые суть PHP скрипты, в основном содержащие HTML код
|
||
и код PHP, отвечающий за представление и внешний вид. Виды управляются компонентом приложения [[yii\web\View|view]], который содержит часто используемые
|
||
методы для упорядочивания видов и их рендеринга. Для упрощения, мы будем называть виды - шаблоны просто видами.
|
||
|
||
## Создание видов <span id="creating-views"></span>
|
||
|
||
Как мы упоминали ранее, вид - это просто PHP скрипт, состоящий из PHP и HTML кодa. В примере ниже - вид, который представляет форму авторизации.
|
||
Как видите, PHP код здесь генерирует динамический контент, как, например, заголовок страницы и саму форму, тогда как HTML организует полученные данные в готовую html страницу.
|
||
|
||
```php
|
||
<?php
|
||
use yii\helpers\Html;
|
||
use yii\widgets\ActiveForm;
|
||
|
||
/* @var $this yii\web\View */
|
||
/* @var $form yii\widgets\ActiveForm */
|
||
/* @var $model app\models\LoginForm */
|
||
|
||
$this->title = 'Вход';
|
||
?>
|
||
<h1><?= Html::encode($this->title) ?></h1>
|
||
|
||
<p>Пожалуйста, заполните следующие поля для входа на сайт:</p>
|
||
|
||
<?php $form = ActiveForm::begin(); ?>
|
||
<?= $form->field($model, 'username') ?>
|
||
<?= $form->field($model, 'password')->passwordInput() ?>
|
||
<?= Html::submitButton('Login') ?>
|
||
<?php ActiveForm::end(); ?>
|
||
```
|
||
|
||
Внутри вида, вы можете использовать `$this`, которое представляет собой [[yii\web\View|компонент вид]], управляющий этим шаблоном и обеспечивающий
|
||
его рендеринг.
|
||
|
||
Кроме `$this`, в виде могут быть доступны другие переменные, такие как `$form` и `$model` из примера выше. Эти переменные представляют собой данные, которые передаются в вид [контроллерами](structure-controllers.md) или другими объектами, которые вызывают [рендеринг вида](#rendering-views).
|
||
|
||
> Совет: Переданные переменные могут быть перечислены в блоке комментария в начале скрипта, чтобы их смогли распознать IDE. К тому же, это хороший способ добавления документации в вид.
|
||
|
||
|
||
### Безопасность <span id="security"></span>
|
||
|
||
При создании видов, которые генерируют HTML страницы, важно кодировать и/или фильтровать данные, которые приходят от пользователей перед тем как их показывать. В противном случае ваше приложение может стать жертвой атаки типа [межсайтовый скриптинг](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D0%B6%D1%81%D0%B0%D0%B9%D1%82%D0%BE%D0%B2%D1%8B%D0%B9_%D1%81%D0%BA%D1%80%D0%B8%D0%BF%D1%82%D0%B8%D0%BD%D0%B3)
|
||
|
||
Чтобы показать обычный текст, сначала кодируйте его с помощью [[yii\helpers\Html::encode()]]. В примере ниже имя пользователя кодируется перед выводом:
|
||
|
||
```php
|
||
<?php
|
||
use yii\helpers\Html;
|
||
?>
|
||
|
||
<div class="username">
|
||
<?= Html::encode($user->name) ?>
|
||
</div>
|
||
```
|
||
|
||
Чтобы показать HTML содержимое, используйте [[yii\helpers\HtmlPurifier]] для того, чтобы отфильтровать потенциально опасное содержимое. В примере ниже содержимое поста фильтруется перед показом:
|
||
|
||
```php
|
||
<?php
|
||
use yii\helpers\HtmlPurifier;
|
||
?>
|
||
|
||
<div class="post">
|
||
<?= HtmlPurifier::process($post->text) ?>
|
||
</div>
|
||
```
|
||
|
||
> Tip: Несмотря на то, что HTMLPurifier отлично справляется с тем, чтобы сделать вывод безопасным, работает он довольно медленно. Если от приложения требуется высокая производительность, рассмотрите возможность [кэширования](caching-overview.md) отфильтрованного результата
|
||
|
||
|
||
### Организация видов <span id="organizing-views"></span>
|
||
|
||
Как и для [контроллеров](structure-controllers.md), и [моделей](structure-models.md), для видов тоже есть определенные соглашения в их организации.
|
||
|
||
* Виды, которые рендерятся из контроллера, по умолчанию должны располагаться в папке `@app/views/ControllerID`, где `ControllerID` это [ID контроллера](structure-controllers.md#routes) . Например, если класс контроллера - `PostController`, то папка будет `@app/views/post`; если контроллер - `PostCommentController`, то папка будет `@app/views/post-comment`. В случае, если контроллер принадлежит модулю, папка будет `views/ControllerID` в [[yii\base\Module::basePath|подпапке модуля]].
|
||
* Виды, которые рендерятся из виджетов, должны располагаться в `ПутьВиджета/views`, где `ПутьВиджета` - это папка, которая содержит класс виджета.
|
||
* С видами, которые рендерятся из других объектов рекомендуется поступать по той же схеме, что и с видами виджетов.
|
||
|
||
В контроллерах и виджетах вы можете изменить папки видов по умолчанию, переопределив метод [[yii\base\ViewContextInterface::getViewPath()]].
|
||
|
||
|
||
## Рендеринг видов <span id="rendering-views"></span>
|
||
|
||
Вы можете рендерить виды в [контроллерах](structure-controllers.md), [widgets](structure-widgets.md), или из любого другого места, вызывая методы рендеринга видов. Методы вызываются приблизительно так, как это показано в примере ниже,
|
||
|
||
```
|
||
/**
|
||
* @param string $view название вида или путь файла, в зависимости от того, какой метод рендеринга используется
|
||
* @param array $params данные, которые передаются виду
|
||
* @return string результат рендеринга
|
||
*/
|
||
methodName($view, $params = [])
|
||
```
|
||
|
||
|
||
### Рендеринг в контроллерах <span id="rendering-in-controllers"></span>
|
||
|
||
Внутри [контроллеров](structure-controllers.md) можно вызывать следующие методы рендеринга видов:
|
||
|
||
* [[yii\base\Controller::render()|render()]]: рендерит [именованный вид](#named-views) и применяет [шаблон](#layouts)
|
||
к результату рендеринга.
|
||
* [[yii\base\Controller::renderPartial()|renderPartial()]]: рендерит [именованный вид](#named-views) без шаблона.
|
||
* [[yii\web\Controller::renderAjax()|renderAjax()]]: рендерит [именованный вид](#named-views) без шаблона,
|
||
и добавляет все зарегистрированные JS/CSS скрипты и стили. Обычно этот метод применяется для рендеринга результата AJAX запроса.
|
||
* [[yii\base\Controller::renderFile()|renderFile()]]: рендерит вид, заданный как путь к файлу или
|
||
[алиас](concept-aliases.md).
|
||
|
||
Например,
|
||
|
||
```php
|
||
namespace app\controllers;
|
||
|
||
use Yii;
|
||
use app\models\Post;
|
||
use yii\web\Controller;
|
||
use yii\web\NotFoundHttpException;
|
||
|
||
class PostController extends Controller
|
||
{
|
||
public function actionView($id)
|
||
{
|
||
$model = Post::findOne($id);
|
||
if ($model === null) {
|
||
throw new NotFoundHttpException;
|
||
}
|
||
|
||
// рендерит вид с названием `view` и применяет к нему шаблон
|
||
return $this->render('view', [
|
||
'model' => $model,
|
||
]);
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
### Рендеринг в виджетах <span id="rendering-in-widgets"></span>
|
||
Внутри [виджетов](structure-widgets.md), вы можете вызывать следующие методы для рендеринга видов.
|
||
|
||
* [[yii\base\Widget::render()|render()]]: рендерит [именованный вид](#named-views).
|
||
* [[yii\base\Widget::renderFile()|renderFile()]]: рендерит вид, заданный как путь файла или
|
||
[алиас](concept-aliases.md).
|
||
|
||
Например,
|
||
|
||
```php
|
||
namespace app\components;
|
||
|
||
use yii\base\Widget;
|
||
use yii\helpers\Html;
|
||
|
||
class ListWidget extends Widget
|
||
{
|
||
public $items = [];
|
||
|
||
public function run()
|
||
{
|
||
// рендерит вид с названием `list`
|
||
return $this->render('list', [
|
||
'items' => $this->items,
|
||
]);
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
### Рендеринг в видах <span id="rendering-in-views"></span>
|
||
|
||
Вы можете рендерить вид внутри другого вида используя методы, которые предоставляет [[yii\base\View|компонент вида]]:
|
||
|
||
* [[yii\base\View::render()|render()]]: рендерит [именованный вид](#named-views).
|
||
* [[yii\web\View::renderAjax()|renderAjax()]]: рендерит [именованный вид](#named-views) и добавляет зарегистрированные JS/CSS скрипты и стили. Обычно используется для рендеринга результата AJAX запроса.
|
||
* [[yii\base\View::renderFile()|renderFile()]]: рендерит вид, заданный как путь к файлу или
|
||
[алиас](concept-aliases.md).
|
||
|
||
Например, следующий код рендерит `_overview.php` файл вида, который находится в той же папке что и вид, который рендерится в текущий момент. Помните, что `$this` в виде - это [[yii\base\View|компонент вида]] (а не контроллер, как это было в Yii1):
|
||
|
||
```php
|
||
<?= $this->render('_overview') ?>
|
||
```
|
||
|
||
|
||
### Рендеринг в других местах <span id="rendering-in-other-places"></span>
|
||
|
||
Вы может получить доступ к [[yii\base\View|виду]] как компоненту приложения вот так:
|
||
`Yii::$app->view`, а затем вызвать вышеупомянутые методы, чтобы отрендерить вид. Например,
|
||
|
||
```php
|
||
// показывает файл "@app/views/site/license.php"
|
||
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
|
||
```
|
||
|
||
|
||
### Именованные виды <span id="named-views"></span>
|
||
|
||
При рендеринге вида, вы можете указать нужный вид, используя как имя вида, так и путь к файлу/алиас. В большинстве случаев вы будете использовать первый вариант, т.к. он более нагляден и гибок. Мы называем виды, которые были вызваны с помощью сокращенного имени *именованные виды*.
|
||
|
||
Имя вида преобразуется в соответствующий ему путь файла в соответствии со следующими правилами:
|
||
|
||
* Имя вида можно указывать без расширения. В таком случае в качестве расширения будет использоваться `.php`. К примеру, имя вида `about` соответствует файлу `about.php`.
|
||
* Если имя вида начинается с двойного слеша `//`, соответствующий ему путь будет `@app/views/ViewName`.
|
||
Т.е. вид будет искаться в [[yii\base\Application::viewPath|папке видов приложения по умолчанию]]. Например, `//site/about` будет преобразован в `@app/views/site/about.php`.
|
||
* Если имя вида начинается с одинарного слеша `/`, то вид будет искаться в [[yii\base\Module::viewPath|папке видов по умолчанию]] текущего [модуля](structure-modules.md) . Если активного модуля на данный момент нет, будет использована папка видов приложения по умолчанию, т.е. вид будет искаться в `@app/views`, как в одном из примеров выше.
|
||
* Если вид рендеринтся с помощью [[yii\base\View::context|контекста]] и контекст реализует интерфейс [[yii\base\ViewContextInterface]], путь к виду образуется путем присоединения [[yii\base\ViewContextInterface::getViewPath()|пути видов]] контекста к имени вида. В основном это применимо к видам, которые рендерятся из контроллеров и виджетов. Например,
|
||
`about` будет преобразован в `@app/views/site/about.php` если контекстом является контроллер `SiteController`.
|
||
* Если вид рендерится из другого вида, папка, в которой находится текущий вид будет добавлена к пути вложенного вида. Например, `item` будет преобразован в `@app/views/post/item`
|
||
если он рендерится из вида `@app/views/post/index.php`.
|
||
|
||
В соответствии с вышесказанным, вызов `$this->render('view')` в контроллере `app\controllers\PostController` будет рендерить файл `@app/views/post/view.php`, а вызов `$this->render('_overview')` в этом виде будет рендерить файл `@app/views/post/_overview.php`.
|
||
|
||
|
||
### Доступ к данным из видов <span id="accessing-data-in-views"></span>
|
||
|
||
Данные можно передавать в вид явно или подгружать их динамически, обращаясь к контексту из вида.
|
||
|
||
Передавая данные через второй параметр методов рендеринга вида, вы явно передаете данные в вид.
|
||
Данные должны быть представлены как обычный массив: ключ-значение. При рендеринге вида, php вызывает встроенную функцию PHP `extract()` на переданном массиве, чтобы переменные из массива "распаковались" в переменные вида. Например, следующий код в контроллере передаст две переменные виду `report` :
|
||
`$foo = 1` и `$bar = 2`.
|
||
|
||
```php
|
||
echo $this->render('report', [
|
||
'foo' => 1,
|
||
'bar' => 2,
|
||
]);
|
||
```
|
||
|
||
Другой подход, подход контекстного доступа, извлекает данные из [[yii\base\View|компонента вида]] или других объектов, доступных в виде (например через глобальный контейнер `Yii::$app`). Внутри вида вы можете вызывать объект контроллера таким образом: `$this->context` (см пример снизу), и, таким образом, получить доступ к его свойствам и методам, например, как указано в примере, вы можете получить ID контроллера:
|
||
|
||
```php
|
||
ID контроллера: <?= $this->context->id ?>
|
||
```
|
||
|
||
Явная передача данных в вид обычно более предпочтительна, т.к. она делает виды независимыми от контекста. Однако, у нее есть недостаток - необходимость каждый раз вручную строить массив данных, что может быть довольно утомительно и привести к ошибкам, если вид рендерится в разных местах.
|
||
|
||
|
||
### Передача данных между видами <span id="sharing-data-among-views"></span>
|
||
|
||
[[yii\base\View|Компонент вида]] имеет свойство [[yii\base\View::params|params]], которое вы можете использовать для обмена данными между видами.
|
||
|
||
Например, в виде `about` вы можете указать текущий сегмент хлебных крошек с помощью следующего кода.
|
||
|
||
```php
|
||
$this->params['breadcrumbs'][] = 'О нас';
|
||
```
|
||
|
||
Затем, в [шаблоне](#layouts), который также является видом, вы можете отобразить хлебные крошки используя данные, переданные через [[yii\base\View::params|params]].
|
||
|
||
```php
|
||
<?= yii\widgets\Breadcrumbs::widget([
|
||
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
|
||
]) ?>
|
||
```
|
||
|
||
|
||
## Шаблоны <span id="layouts"></span>
|
||
|
||
Шаблоны - особый тип видов, которые представляют собой общие части разных видов. Например, у большинства страниц веб приложений одинаковые верх и низ (хедер и футер). Можно, конечно, указать их и в каждом виде, однако лучше сделать это один раз, в шаблоне, и затем, при рендеринге, включать уже отрендеренный вид в заданное место шаблона.
|
||
|
||
### Создание шаблонов <span id="creating-layouts"></span>
|
||
|
||
Поскольку шаблоны это виды, их можно создавать точно так же, как и обычные виды. По умолчанию шаблоны хранятся в папке `@app/views/layouts`. Шаблоны, которые используются в конкретном [модуле](structure-modules.md), хранятся в подпапке `views/layouts` [[yii\base\Module::basePath|папки модуля]]. Вы можете изменить папку шаблонов по умолчанию, используя свойство [[yii\base\Module::layoutPath]] приложения или модулей.
|
||
|
||
Пример ниже показывает как выглядит шаблон. Для лучшего понимания мы сильно упростили код шаблона. На практике, однако, в нем часто содержится больше кода, например, тэги `<head>`, главное меню и т.д.
|
||
|
||
```php
|
||
<?php
|
||
use yii\helpers\Html;
|
||
|
||
/* @var $this yii\web\View */
|
||
/* @var $content string */
|
||
?>
|
||
<?php $this->beginPage() ?>
|
||
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8"/>
|
||
<?= Html::csrfMetaTags() ?>
|
||
<title><?= Html::encode($this->title) ?></title>
|
||
<?php $this->head() ?>
|
||
</head>
|
||
<body>
|
||
<?php $this->beginBody() ?>
|
||
<header>Моя компания</header>
|
||
<?= $content ?>
|
||
<footer>Моя компания © 2014</footer>
|
||
<?php $this->endBody() ?>
|
||
</body>
|
||
</html>
|
||
<?php $this->endPage() ?>
|
||
```
|
||
|
||
Как видите, шаблон генерирует HTML тэги, которые присутствуют на всех страницах. Внутри секции `<body>`, шаблон выводит переменную `$content`, которая содержит результат рендеринга видов контента, который передается в шаблон, при работе метода [[yii\base\Controller::render()]].
|
||
|
||
Большинство шаблонов вызывают методы, аналогично тому, как это сделано в примере выше, чтобы скрипты и тэги, зарегистрированные в других местах приложения могли быть правильно отображены в местах вызова (например, в шаблоне).
|
||
|
||
- [[yii\base\View::beginPage()|beginPage()]]: Этот метод нужно вызывать в самом начале шаблона.
|
||
Он вызывает событие [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]], которое происходит при начале обработки страницы.
|
||
- [[yii\base\View::endPage()|endPage()]]: Этот метод нужно вызывать в конце страницы.
|
||
Он вызывает событие [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]] . Оно указывает на обработку конца страницы.
|
||
- [[yii\web\View::head()|head()]]: Этот метод нужно вызывать в `<head>` секции страницы html.
|
||
Он генерирует метку, которая будет заменена зарегистрированным ранее кодом HTML (тэги `link`, мета тэги), когда рендеринг страницы будет завершен.
|
||
- [[yii\web\View::beginBody()|beginBody()]]: Этот метод нужно вызывать в начале секции `<body>`.
|
||
Он вызывает событие [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] и генерирует метку, которая будет заменена зарегистрированным HTML кодом (например, Javascript'ом), который нужно разместить в начале `<body>` страницы.
|
||
- [[yii\web\View::endBody()|endBody()]]: Этот метод нужно вызывать в конце секции `<body>`.
|
||
Он вызывает событие [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] и генерирует метку, которая будет заменена зарегистрированным HTML кодом (например, Javascript'ом), который нужно разместить в конце `<body>` страницы.
|
||
|
||
|
||
### Доступ к данным в шаблонах <span id="accessing-data-in-layouts"></span>
|
||
|
||
Внутри шаблона, у вас есть доступ к двум предопределенным переменным: `$this` и `$content`. Первая представляет собой
|
||
[[yii\base\View|вид]] компонент, как и в обычных видах, тогда как последняя содержит результат рендеринга вида, который рендерится при вызове метода [[yii\base\Controller::render()|render()]] в контроллерах.
|
||
|
||
Если вы хотите получить доступ к другим данным из шаблона, используйте метод явной передачи (он описан в секции [Доступ к данным в видах](#accessing-data-in-views) настоящего документа). Если вы хотите
|
||
передать данные из вида шаблону, вы можете использовать метод, описанный в [передаче данных между видами](#sharing-data-among-views).
|
||
|
||
|
||
### Использование шаблонов <span id="using-layouts"></span>
|
||
|
||
Как было описано в секции [Рендеринг в контроллерах](#rendering-in-controllers), когда вы рендерите вид, вызывая метод [[yii\base\Controller::render()|render()]] из контроллера, к результату рендеринга будет применен шаблон. По умолчанию будет использован шаблон `@app/views/layouts/main.php` .
|
||
|
||
Вы можете использовать разные шаблоны, конфигурируя [[yii\base\Application::layout]] или [[yii\base\Controller::layout]].
|
||
Первый переопределяет шаблон, который используется по умолчанию всеми контроллерами, а второй переопределяет шаблон в отдельном контроллере.
|
||
Например, код внизу показывает, как можно сделать так, чтобы контроллер использовал шаблон `@app/views/layouts/post.php` при рендеринге вида. Другие контроллеры, если их свойство `layout` не переопределено, все еще будут использовать `@app/views/layouts/main.php` как шаблон.
|
||
|
||
```php
|
||
namespace app\controllers;
|
||
|
||
use yii\web\Controller;
|
||
|
||
class PostController extends Controller
|
||
{
|
||
public $layout = 'post';
|
||
|
||
// ...
|
||
}
|
||
```
|
||
|
||
Для контроллеров, принадлежащих модулю, вы также можете переопределять свойство модуля [[yii\base\Module::layout|layout]], чтобы
|
||
использовать особый шаблон для этих контроллеров.
|
||
|
||
Поскольку свойство `layout` может быть сконфигурировано на разных уровнях приложения (контроллеры, модули, само приложение),
|
||
Yii определяет какой шаблон использовать для контроллера в два этапа.
|
||
|
||
На первом этапе определяется значение шаблона и контекстный модуль.
|
||
|
||
- Если [[yii\base\Controller::layout]] свойство контроллера отлично от `null`, используется оно, и [[yii\base\Controller::module|модуль]]
|
||
контроллера как контекстный модуль.
|
||
- Если [[yii\base\Controller::layout|layout]] равно `null` (не задано), происходит поиск среди родительских модулей контроллера, включая само приложение (которое по умолчанию является родительским модулем для контроллеров, не принадлежащих модулям) и
|
||
находится первый модуль, свойство [[yii\base\Module::layout|layout]] которого не равно `null` . Тогда используется найденное значение `layout` этого модуля
|
||
и сам модуль в качестве контекста. Если такой модуль не найден, значит шаблон применен не будет.
|
||
|
||
На втором этапе определяется сам файл шаблона для рендеринга на основании значения `layout` и контекстного модуля.
|
||
Значением `layout` может быть:
|
||
|
||
- Алиас пути (например, `@app/views/layouts/main`).
|
||
- Абсолютный путь (например `/main`): значение `layout` начинается со слеша. Будет искаться шаблон из [[yii\base\Application::layoutPath|папки шаблонов]] приложения, по умолчанию это `@app/views/layouts`.
|
||
- Относительный путь (например `main`): Будет искаться шаблон из [[yii\base\Module::layoutPath|папки шаблонов контекстного модуля]], по умолчанию это `views/layouts` в [[yii\base\Module::basePath|папке модуля]].
|
||
- Булево значение `false`: шаблон не будет применен.
|
||
|
||
Если у значения `layout` нет расширения, будет использовано расширение по умолчанию - `.php`.
|
||
|
||
### Вложенные шаблоны <span id="nested-layouts"></span>
|
||
|
||
Иногда нужно вложить один шаблон в другой. Например, в разных разделах сайта используются разные шаблоны, но у всех
|
||
этих шаблонов есть основная разметка, которая определяет HTML5 структуру страницы. Вы можете использовать вложенные шаблоны,
|
||
вызывая [[yii\base\View::beginContent()|beginContent()]] и [[yii\base\View::endContent()|endContent()]] в дочерних
|
||
шаблонах таким образом:
|
||
|
||
```php
|
||
<?php $this->beginContent('@app/views/layouts/base.php'); ?>
|
||
|
||
...код дочернего шаблона...
|
||
|
||
<?php $this->endContent(); ?>
|
||
```
|
||
|
||
В коде выше дочерний шаблон заключается в [[yii\base\View::beginContent()|beginContent()]] и [[yii\base\View::endContent()|endContent()]].
|
||
Параметр, передаваемый в метод [[yii\base\View::beginContent()|beginContent()]] определяет родительский шаблон. Это может быть как
|
||
путь к файлу, так и алиас.
|
||
|
||
Используя подход выше, вы можете вкладывать шаблоны друг в друга в несколько уровней.
|
||
|
||
|
||
### Использование блоков <span id="using-blocks"></span>
|
||
|
||
Блоки позволяют "записывать" контент в одном месте, а показывать в другом. Они часто используются совместно с шаблонами.
|
||
Например, вы определяете (записываете) блок в виде и отображаете его в шаблоне.
|
||
|
||
Для определения блока вызываются методы [[yii\base\View::beginBlock()|beginBlock()]] и [[yii\base\View::endBlock()|endBlock()]].
|
||
После определения, блок доступен через `$view->blocks[$blockID]`, где `$blockID` - это уникальный ID, который вы присваиваете блоку
|
||
в начале определения.
|
||
|
||
В примере ниже показано, как можно использовать блоки, определенные в виде, чтобы динамически изменять фрагменты шаблона.
|
||
|
||
Сначала, в виде, вы записываете один или несколько блоков:
|
||
|
||
```php
|
||
...
|
||
|
||
<?php $this->beginBlock('block1'); ?>
|
||
|
||
...содержимое блока 1...
|
||
|
||
<?php $this->endBlock(); ?>
|
||
|
||
...
|
||
|
||
<?php $this->beginBlock('block3'); ?>
|
||
|
||
...содержимое блока 3...
|
||
|
||
<?php $this->endBlock(); ?>
|
||
```
|
||
|
||
Затем, в шаблоне, рендерите блоки если они есть, или показываете контент по умолчанию, если блок не определен.
|
||
|
||
```php
|
||
...
|
||
<?php if (isset($this->blocks['block1'])): ?>
|
||
<?= $this->blocks['block1'] ?>
|
||
<?php else: ?>
|
||
... контент по умолчанию для блока 1 ...
|
||
<?php endif; ?>
|
||
|
||
...
|
||
|
||
<?php if (isset($this->blocks['block2'])): ?>
|
||
<?= $this->blocks['block2'] ?>
|
||
<?php else: ?>
|
||
... контент по умолчанию для блока 2 ...
|
||
<?php endif; ?>
|
||
|
||
...
|
||
|
||
<?php if (isset($this->blocks['block3'])): ?>
|
||
<?= $this->blocks['block3'] ?>
|
||
<?php else: ?>
|
||
... контент по умолчанию для блока 3 ...
|
||
<?php endif; ?>
|
||
...
|
||
```
|
||
|
||
|
||
## Использование компонентов вида <span id="using-view-components"></span>
|
||
|
||
[[yii\base\View|Компоненты вида]] дают много возможностей. Несмотря на то, что существует возможность создавать индивидуальные экземпляры [[yii\base\View]] или дочерних классов, в большинстве случаев используется
|
||
сам компонент `view` приложения. Вы можете сконфигурировать компонент в [конфигурации приложения](structure-applications.md#application-configurations) таким образом:
|
||
|
||
```php
|
||
[
|
||
// ...
|
||
'components' => [
|
||
'view' => [
|
||
'class' => 'app\components\View',
|
||
],
|
||
// ...
|
||
],
|
||
]
|
||
```
|
||
|
||
Компоненты вида предоставляют широкие возможности по работе с видами, они описаны в отдельных секциях документации:
|
||
|
||
* [темы](output-theming.md): позволяет менять темы оформления для сайта.
|
||
* [кэширование фрагментов](caching-fragment.md): позволяет кэшировать фрагменты веб-страниц.
|
||
* [работа с клиентскими скриптами](output-client-scripts.md): Поддерживает регистрацию и рендеринг CSS и Javascript.
|
||
* [управление связками](structure-assets.md): позволяет регистрацию и управление [связками клиентского кода](structure-assets.md).
|
||
* [альтернативные движки шаблонов](tutorial-template-engines.md): позволяет использовать другие шаблонные движки, такие как
|
||
[Twig](http://twig.sensiolabs.org/), [Smarty](http://www.smarty.net/).
|
||
|
||
|
||
Также удобно пользоваться мелкими, но удобными фичами при разработке веб страниц, которые приведены ниже.
|
||
|
||
|
||
### Установка заголовков страниц <span id="setting-page-titles"></span>
|
||
|
||
У каждой страницы должен быть заголовок. Обычно заголовок выводится в [шаблоне](#layouts). Однако на практике
|
||
заголовок часто определяется в видах, а не в шаблонах. Чтобы передать заголовок из вида в шаблон, используется свойство [[yii\web\View::title|title]].
|
||
|
||
В виде можно задать заголовок таким образом:
|
||
|
||
```php
|
||
<?php
|
||
$this->title = 'Мой заголовок страницы';
|
||
?>
|
||
```
|
||
|
||
В шаблоне заголовок выводится следующим образом, (убедитесь, что в `<head>` у вас соответствующий код):
|
||
|
||
```php
|
||
<title><?= Html::encode($this->title) ?></title>
|
||
```
|
||
|
||
|
||
### Регистрация мета-тэгов <span id="registering-meta-tags"></span>
|
||
|
||
На веб страницах обычно есть мета-тэги, которые часто используются различными сервисами. Как и заголовки страниц,
|
||
мета-тэги выводятся в `<head>` и обычно генерируются в шаблонах.
|
||
|
||
Если вы хотите указать, какие мета-тэги генерировать в видах, вы можете вызвать метод [[yii\web\View::registerMetaTag()]] в виде так,
|
||
как в примере ниже:
|
||
|
||
```php
|
||
<?php
|
||
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);
|
||
?>
|
||
```
|
||
|
||
Этот код зарегистрирует мета тэг "keywords" в виде. Зарегистрированные мета тэги рендерятся после того, как закончен
|
||
рендеринг шаблона. Они вставляются в то место, где в шаблоне вызван метод [[yii\web\View::head()]]. Результатом рендеринга
|
||
мета тэгов является следующий код:
|
||
|
||
```php
|
||
<meta name="keywords" content="yii, framework, php">
|
||
```
|
||
|
||
Обратите внимание, что при вызове метода [[yii\web\View::registerMetaTag()]] несколько раз мета тэги будут регистрироваться
|
||
каждый раз без проверки на уникальность.
|
||
|
||
Чтобы убедиться, что зарегистрирован только один экземпляр одного типа мета тэгов, вы можете указать ключ мета тэга в качестве второго
|
||
параметра при вызове метода.
|
||
К примеру, следующий код регистрирует два мета тэга "description", однако отрендерен будет только второй.
|
||
|
||
```php
|
||
$this->registerMetaTag(['name' => 'description', 'content' => 'Мой сайт сделан с помощью Yii!'], 'description');
|
||
$this->registerMetaTag(['name' => 'description', 'content' => 'Это сайт о забавных енотах.'], 'description');
|
||
```
|
||
|
||
|
||
### Регистрация тэгов link <span id="registering-link-tags"></span>
|
||
|
||
Как и [мета тэги](#adding-meta-tags), link тэги полезны во многих случаях, как, например, задание уникальной favicon, указание на RSS фид или указание OpenID сервера для авторизации. С link тэгами можно работать аналогично работе с мета тэгами, вызывая метод [[yii\web\View::registerLinkTag()]]. Например,
|
||
вы можете зарегистрировать link тэг в виде таким образом:
|
||
|
||
```php
|
||
$this->registerLinkTag([
|
||
'title' => 'Сводка новостей по Yii',
|
||
'rel' => 'alternate',
|
||
'type' => 'application/rss+xml',
|
||
'href' => 'http://www.yiiframework.com/rss.xml/',
|
||
]);
|
||
```
|
||
|
||
Этот код выведет
|
||
|
||
```html
|
||
<link title="Сводка новостей по Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/">
|
||
```
|
||
|
||
Как и в случае с [[yii\web\View::registerMetaTag()|registerMetaTag()]], вы можете указать ключ вторым параметром при вызове
|
||
[[yii\web\View::registerLinkTag()|registerLinkTag()]] чтобы избежать дублирования link тэгов одного типа.
|
||
|
||
|
||
## События в видах <span id="view-events"></span>
|
||
|
||
[[yii\base\View|Компонент вида]] вызывает несколько событий во время рендеринга.
|
||
Вы можете задавать обработчики для этих событий чтобы добавлять контент
|
||
в вид или делать пост-обработку результатов рендеринга до того, как они будут отправлены конечным пользователям.
|
||
|
||
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: вызывается в начале рендеринга файла в контроллере.
|
||
Обработчики этого события могут придать атрибуту [[yii\base\ViewEvent::isValid]] значение `false`, чтобы отменить процесс рендеринга.
|
||
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: событие инициируется после рендеринга файла вызовом [[yii\base\View::afterRender()]].
|
||
Обработчики события могут получать результат рендеринга через [[yii\base\ViewEvent::output]] и могут изменять это свойство для изменения
|
||
результата рендеринга.
|
||
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: инициируется вызовом [[yii\base\View::beginPage()]] в шаблонах.
|
||
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: инициируется вызовом [[yii\base\View::endPage()]] в шаблонах.
|
||
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: инициируется вызовом [[yii\web\View::beginBody()]] в шаблонах.
|
||
- [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]]: инициируется вызовом [[yii\web\View::endBody()]] в шаблонах.
|
||
|
||
Например, следующий код вставляет дату в конец `body` страницы:
|
||
|
||
```php
|
||
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
|
||
echo date('Y-m-d');
|
||
});
|
||
```
|
||
|
||
|
||
## Рендеринг статических страниц <span id="rendering-static-pages"></span>
|
||
|
||
Статическими страницами мы считаем страницы, которые содержат в основном статические данные и для формирования
|
||
которых не нужно строить динамические данные в контроллерах.
|
||
|
||
Вы можете выводить статические страницы, сохраняя их в видах, а затем используя подобный код в контроллере:
|
||
|
||
```php
|
||
public function actionAbout()
|
||
{
|
||
return $this->render('about');
|
||
}
|
||
```
|
||
|
||
Если сайт содержит много статических страниц, описанный выше подход не вполне подходит - его использование
|
||
приведет к многократному повторению похожего кода. Вместо этого вы можете использовать [отдельное действие](structure-controllers.md#standalone-actions) [[yii\web\ViewAction]] в контроллере. Например,
|
||
|
||
```php
|
||
namespace app\controllers;
|
||
|
||
use yii\web\Controller;
|
||
|
||
class SiteController extends Controller
|
||
{
|
||
public function actions()
|
||
{
|
||
return [
|
||
'page' => [
|
||
'class' => 'yii\web\ViewAction',
|
||
],
|
||
];
|
||
}
|
||
}
|
||
```
|
||
|
||
Теперь, если вы создадите вид `about` в папке `@app/views/site/pages`, он будет отображаться по такому адресу:
|
||
|
||
```
|
||
http://localhost/index.php?r=site%2Fpage&view=about
|
||
```
|
||
|
||
`GET` параметр `view` сообщает [[yii\web\ViewAction]] какой вид затребован. Действие будет искать этот вид в папке `@app/views/site/pages`.
|
||
Вы можете сконфирурировать параметр [[yii\web\ViewAction::viewPrefix]] чтобы изменить папку в которой ищется вид.
|
||
|
||
|
||
## Полезные советы <span id="best-practices"></span>
|
||
|
||
Виды отвечают за представление данных моделей в формате, понятным конечным пользователям. В целом, виды
|
||
|
||
* должны в основном содержать код, отвечающий за представление, такой как HTML и простой PHP для обхода, форматирования и рендеринга данных.
|
||
* не должны содержать кода, который производит запросы к БД. Такими запросами должны заниматься модели.
|
||
* должны избегать прямого обращения к данным запроса, таким как `$_GET`, `$_POST`. Разбором запроса должны заниматься контроллеры. Если
|
||
данные запросов нужны для построения вида, они должны явно передаваться в вид контроллерами.
|
||
* могут читать свойства моделей, но не должны их изменять.
|
||
|
||
Чтобы сделать виды более управляемыми, избегайте создания видов, которые содержат слишком сложную логику или большое количество кода.
|
||
Используйте следующие подходы для их упрощения:
|
||
|
||
|
||
* используйте [шаблоны](#layouts) для отображения основных секций разметки сайта (верхняя часть (хедер), нижняя часть (футер) и т.п.)
|
||
* разбивайте сложный вид на несколько видов попроще. Меньшие виды можно рендерить и объединять в больший используя методы рендеринга, описанный в
|
||
настоящем документе.
|
||
* создавайте и используйте [виджеты](structure-widgets.md) как строительный материал для видов.
|
||
* создавайте и используйте классы-хелперы для изменения и форматирования данных в видах.
|