Представлення є частиною архітектури MVC. Це код, який відповідає за відображення даних кінцевим користувачам. У веб-додатку представлення зазвичай створені у вигляді шаблонів представлень, які є файлами скриптів PHP, що містять переважно HTML-код та презентаційний PHP-код. Управління ними здійснюється за допомогою компонента додатку view, який надає часто використовувані методи для полегшення компонування та формування представлення. Для простоти, часто шаблони представлень або файли шаблонів представлень називаються представленнями.
Як зазначено вище, представлення є простим скриптом PHP, який містить HTML- та PHP-код. Далі наведено представлення, що представляє форму входу користувача. Як можна побачити, PHP-код використовується для генерування динамічного вмісту, такого як заголовку сторінки та форми, тоді як HTML-код організовує їх у презентабельну HTML-сторінку.
<?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('Увійти') ?>
<?php ActiveForm::end(); ?>
Всередині представлення ви можете використовувати $this
, що відноситься до компоненту представлення, який забезпечує керування
цим шаблоном та його формування.
Окрім $this
, у представленні можуть бути інші попередньо визначені змінні, такі як $model
у прикладі
вище. Ці змінні представляють дані, які були передані у представлення через контролери
або інші об’єкти, які спричинили формування представлення.
Tip: Попередньо визначені змінні перелічені в блоці коментаря у початку представлення, так що вони можуть бути розпізнані в інтегрованих середовищах розробки (IDE). Це також є хорошим способом документування ваших представлень.
При створенні представлень, які генерують HTML-сторінки, важливо кодувати і/або фільтрувати дані, що надходять від кінцевих користувачів, перед їх відображенням. В протилежному випадку ваш додаток може стати предметом атак типу міжсайтовий скриптінг (XSS).
Для відображення звичайного тексту спершу закодуйте його за допомогою yii\helpers\Html::encode(). Наприклад, в наступному коді перед відображенням кодується ім’я користувача:
<?php
use yii\helpers\Html;
?>
<div class="username">
<?= Html::encode($user->name) ?>
</div>
Для відображення HTML-вмісту використовуйте yii\helpers\HtmlPurifier, щоб відфільтрувати потенційно небезпечний вміст. Наприклад, в наступному коді фільтрується вміст публікації перед відображенням:
<?php
use yii\helpers\HtmlPurifier;
?>
<div class="post">
<?= HtmlPurifier::process($post->text) ?>
</div>
Tip: В той час як HTMLPurifier бездоганно виконує роботу, щоб зробити вивід безпечним, він не є швидким. Вам потрібно розглянути можливість кешування результатів фільтрування, якщо ваш додаток потребує високої швидкодії.
Подібно до контролерів та моделей, існують домовленості щодо впорядкування представлень.
@app/views/ControllerID
за замовчуванням,
де ControllerID
відповідає ідентифікатору контролера. Наприклад, для
класу контролера PostController
директорія повинна бути @app/views/post
; для класу PostCommentController
директорія повинна бути @app/views/post-comment
. У випадку, коли контролер належить модулю, директорія
повинна бути views/ControllerID
у директорії модуля.WidgetPath/views
за
замовчуванням, де WidgetPath
означає шлях до директорії, в якій знаходиться файл класу віджету.Ви можете налаштувати ці типові директорії представлень, перевизначивши метод yii\base\ViewContextInterface::getViewPath() контролерів або віджетів.
Ви можете формувати представлення в контролерах, віджетах чи в будь-яких інших місцях за допомогою виклику методів формування представлення. Усі ці методи мають подібну сигнатуру, що наведена нижче:
/**
* @param string $view ім’я представлення або шлях до файлу, в залежності від того, який метод формування використовується
* @param array $params дані, які передаються представленню
* @return string результат формування
*/
methodName($view, $params = [])
Всередині контролерів, ви можете викликати наступні методи контролера для формування представлень:
Наприклад:
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,
]);
}
}
Всередині віджетів, ви можете викликати наступні методи віджету для формування представлень.
Наприклад:
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,
]);
}
}
Ви можете формувати представлення всередині іншого представлення за допомогою виклику одного з наступних методів наданих компонентом представлення:
Наприклад, наступний код у представленні формує файл представлення _overview.php
, який знаходиться в тій самій директорії,
що й представлення, яке зараз формується. Запам’ятайте, що $this
у представленні відноситься до компонента представлення:
<?= $this->render('_overview') ?>
В будь-якому місці ви можете отримати доступ до компонента додатка представлення за допомогою виразу
Yii::$app->view
та потім викликати його вищезгадані методи для формування представлення. Наприклад:
// відображає файл представлення "@app/views/site/license.php"
echo \Yii::$app->view->renderFile('@app/views/site/license.php');
При формуванні представлення ви можете визначити його, використовуючи ім’я представлення або шлях/псевдонім до файлу представлення. У більшості випадків ви будете використовувати перший варіант, тому що він більш лаконічний та гнучкий. Представлення, визначені за допомогою імен називаються іменованими представленнями.
Ім’я представлення перетворюється у відповідний шлях до файлу представлення за наступними правилами:
.php
. Наприклад,
ім’я представлення about
відповідає імені файлу about.php
.//
, то відповідним шляхом до файлу представлення буде @app/views/ViewName
.
Це означає, що представлення шукається в директорії представлень додатку.
Наприклад, //site/about
буде перетворено в @app/views/site/about.php
./
, то шлях до файлу представлення складатиметься з імені представлення та префіксу
у вигляді директорії представлень поточного активного модулю.
Якщо немає активного модулю, то буде використовуватись @app/views/ViewName
. Наприклад, /user/create
буде перетворено в
@app/modules/user/views/user/create.php
, якщо поточним активним модулем є user
. Якщо немає активного модулю,
то шляхом до файлу представлення буде @app/views/user/create.php
.about
буде перетворено в @app/views/site/about.php
, якщо контекстом є контролер SiteController
.item
перетвориться в @app/views/post/item.php
,
якщо буде формуватись із представлення @app/views/post/index.php
.Згідно з наведеними правилами, виклик $this->render('view')
у контролері app\controllers\PostController
буде
формувати представлення з файлу @app/views/post/view.php
, в той час як виклик $this->render('_overview')
у тому представленні
буде формувати представлення з файлу @app/views/post/_overview.php
.
Є два підходи при доступові до даних в середині представлення: "вштовхування" та "витягування".
Передаючи дані другим параметром у методи формування представлення, ви використовуєте підхід "вштовхування".
Дані повинні бути надані у вигляді масиву пар ключ-значення. Під час формування представлення буде викликана функція PHP
extract()
на цьому масиві, видобувши таким чином змінні у представлення.
Наприклад, наступний код формування представлення у контролері "вштовхне" дві змінні до представлення report
:
$foo = 1
та $bar = 2
.
echo $this->render('report', [
'foo' => 1,
'bar' => 2,
]);
Підхід "витягування" активно здобуває дані з компоненту представлення або інших об’єктів, доступних
у представленнях (наприклад, Yii::$app
). Використовуючи нижче наведений код як приклад, всередині представлення можна отримати об’єкт
за допомогою виразу $this->context
. У результаті, стає можливим доступ до усіх властивостей та методів
контролера у представленні report
, як, наприклад, ідентифікатору контролера, що наведений у прикладі:
Ідентифікатор контролера: <?= $this->context->id ?>
Підхід "вштовхування" є бажанішим шляхом для доступу до даних у представленнях, тому що він робить представлення менш залежними від об’єктів контексту, але його недоліком є необхідність весь час будувати масив даних вручну, що може стати стомливим та збільшує вірогідність допустити помилку, якщо представлення використовується та формується у різних місцях.
Компонент представлення надає властивість params, яку можна використовувати для обміну даними між представленнями.
Наприклад, в представленні about
, ви можете мати наступний код, який визначає поточну частину
"хлібних крихт".
$this->params['breadcrumbs'][] = 'Про нас';
Потім у файлі макету, який також є представленням, ви можете відобразити "хлібні крихти", використовуючи дані передані через params:
<?= yii\widgets\Breadcrumbs::widget([
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [],
]) ?>
Макети - особливий тип представлень, які представляють спільні частини для інших представлень. Наприклад, сторінки більшості веб-додатків мають однакові шапку та футер. Ви можете повторювати однакові шапку та футер сторінки у кожному представленні, але краще зробити це один раз у макеті та розмістити результат формування вкладеного представлення у відповідному місці макету.
Оскільки макети є представленнями, вони можуть бути створенні тим самим шляхом, як і звичайні представлення. За замовчуванням, макети
зберігаються в директорії @app/views/layouts
. Макети, які використовуються у модулі,
повинні зберігатись в директорії views/layouts
під директорією модуля.
Ви можете налаштувати типову директорію для макетів сконфігурувавши властивість yii\base\Module::layoutPath
додатку або модулів.
Наступний приклад показує як виглядає макет. Майте на увазі, що для кращого сприйняття код у макеті дуже спрощений.
На практиці, ви можливо захочете додати більше вмісту до нього, такого як теги секції <head>
, головне меню та інше.
<?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().
В більшості макетів наступні методи будуть викликатись як показано у вищенаведеному коді. Ці методи здебільшого породжують події, пов’язані з процесом формування, щоб скрипти та теги, які зареєстровані в інших місцях могли бути правильно включенні в місцях, де ці методи викликаються.
<head>
HTML-сторінки.
Він генерує заповнювач, який буде замінено зареєстрованим HTML-кодом (наприклад, теги link і meta),
коли сторінка буде повністю сформована.<body>
.
Він породжує подію EVENT_BEGIN_BODY та генерує заповнювач, який
буде замінено зареєстрованим HTML-кодом (наприклад, JavaScript) на початку секції <body>
.<body>
.
Він породжує подію EVENT_END_BODY та генерує заповнювач, який
буде замінено зареєстрованим HTML-кодом (наприклад, JavaScript) у кінці секції <body>
.Всередині макету ви маєте доступ до двох попередньо визначених змінних: $this
та $content
. Перша посилається на
компонент представлення, як і у звичайних представленнях, в той час як друга містить результат формування вкладеного
представлення, який формується викликом методу render() у контролерах.
Якщо ви бажаєте мати доступ до інших даних у макетах, то вам потрібно використовувати підхід "витягування", описаний в підрозділі Доступ до даних у представленнях. Якщо ви бажаєте отримати дані з вкладеного представлення у макеті, то можете використати підхід описаний у підрозділі Обмін даними між представленнями.
Як описано в підрозділі Формування в контролерах, під час формування представлення
через виклик методу render() у контролері, буде застосовний макет
до результату формування. За замовчуванням, буде використовуватись макет @app/views/layouts/main.php
.
Ви можете використовувати інший макет сконфігурувавши властивість yii\base\Application::layout або yii\base\Controller::layout.
Перша відповідає за макет, який використовується усіма контролерами, друга ж перекриває першу для окремих контролерів.
Наприклад, наступний код налаштовує контролер post
на використання макету @app/views/layouts/post.php
під час формування його представлень. Інші контролери, за умови, що їх властивість layout
не встановлена, будуть надалі
використовувати типовий макет @app/views/layouts/main.php
.
namespace app\controllers;
use yii\web\Controller;
class PostController extends Controller
{
public $layout = 'post';
// ...
}
Для контролерів, що належать модулю, ви можете також сконфігурувати властивість модуля layout, щоб використовувати окремий макет для цих контролерів.
Оскільки властивість layout
може бути сконфігурована на різних рівнях (контролери, моделі, додаток),
"за лаштунками" Yii виконує два кроки, щоб визначити, який файл макету є актуальним для окремого контролера.
На першому кроці, визначається значення layout
та контекстний модуль:
null
, використовується вона і
модуль контролера як контекстний модуль.null
), здійснюється пошук у всіх батьківських модулях (включаючи сам додаток) контролера та
знаходиться перший модуль, властивість layout якого не дорівнює null
. Використовується значення цього модуля
layout та сам модуль як контекстний модуль.
Якщо такого модуля не знайдено, це означає, що макет не буде застосовано.На другому кроці, визначається актуальний файл макету відповідно до значення layout
та контекстного модулю,
визначених на першому кроці. Значенням layout
може бути:
@app/views/layouts/main
);/main
): значення layout
починається зі слешу. Актуальний файл макету буде
шукатись під директорією макетів додатка, яка типово дорівнює
@app/views/layouts
;main
): актуальний файл макету буде шукатись під
директорією макетів контекстного модуля, яка типово є директорією views/layouts
під
директорією модуля;false
: макет не буде застосовано.Якщо значення layout
не містить розширення файлу, то буде використане типове розширення .php
.
Іноді потрібно вкласти один макет в інший. Наприклад, у різних розділах веб-сайту ви захочете використовувати різні макети, які мають однаковий базовий макет, що генерує загальну структуру HTML5-сторінки. Це можна зробити за допомогою викликів beginContent() та endContent() в дочірніх макетах як наведено нижче:
<?php $this->beginContent('@app/views/layouts/base.php'); ?>
...вміст дочірнього макету...
<?php $this->endContent(); ?>
Як показано вище, вміст дочірнього макету повинен бути замкнений між beginContent() та endContent(). Параметр, який передається в beginContent() визначає батьківський макет. Цей може бути файл макету чи псевдонім шляху.
Використовуючи цей підхід, можна вкладати макети більше, ніж на один рівень.
Блоки дозволяють визначати вміст представлення в одному місці, а відображати в іншому. Вони часто використовуються разом з макетами. Наприклад, ви можете визначити блок у вкладеному представленні та відобразити його у макеті.
Виклики beginBlock() та endBlock() визначають блок.
Потім блок може бути доступним через $view->blocks[$blockID]
, де $blockID
означає унікальний ідентифікатор, який ви призначаєте
блоку під час його визначення.
Нижченаведений приклад показує як ви можете використовувати блоки у вкладеному представленні для налаштовування окремих частин макету.
Спершу, у вкладеному представленні, визначається один чи більше блоків:
...
<?php $this->beginBlock('block1'); ?>
...вміст блоку 1...
$this->endBlock(); ?>
...
$this->beginBlock('block3'); ?>
...вміст блоку 3...
$this->endBlock(); ?>
Потім, у макеті, формуються блоки, якщо вони присутні, або відображається деякий типовий вміст, якщо блок не визначено.
...
<?php if (isset($this->blocks['block1'])): ?>
<?= $this->blocks['block1'] ?>
else: ?>
... типовий вміст для блоку 1 ...
endif; ?>
...
if (isset($this->blocks['block2'])): ?>
<?= $this->blocks['block2'] ?>
else: ?>
... типовий вміст для блоку 2 ...
endif; ?>
...
if (isset($this->blocks['block3'])): ?>
<?= $this->blocks['block3'] ?>
else: ?>
... типовий вміст для блоку 3 ...
endif; ?>
...
Компоненти представлення надають багато можливостей, пов’язаних із представленням. Ви можете отримувати компоненти представлення
за допомогою створення індивідуальних екземплярів yii\base\View або його дочірніх класів, але у більшості випадків ви переважно будете використовувати
компонент view
додатку. Ви можете сконфігурувати цей компонент у конфігураціях додатку
як наведено нижче:
[
// ...
'components' => [
'view' => [
'class' => 'app\components\View',
],
// ...
],
]
Компоненти представлення надають наступні корисні можливості, пов’язані з представленням, які описані більш детально в окремих розділах:
Ви також можете часто використовувати наступні другорядні, але корисні, можливості в процесі розробки веб-сторінок.
Кожна веб-сторінка повинна мати заголовок. Звичайно тег заголовку виводиться в макеті. Однак, на практиці заголовок часто визначається у вкладених представленнях, а не в макетах. Для вирішення цієї проблеми, компонент yii\web\View надає властивість title, за допомогою якої можна передавати з вкладеного представлення до макетів інформацію заголовку.
Для використання цієї можливості, в кожному вкладеному представленні ви можете задати заголовок як наведено нижче:
<?php
$this->title = 'Мій заголовок сторінки';
?>
Потім переконайтесь, що маєте наступний код в секції <head>
у макеті:
<title><?= Html::encode($this->title) ?></title>
Для веб-сторінок зазвичай потрібно генерувати різноманітні мета-теги, які мають різне цільове призначення. Подібно до заголовків сторінок, мета-теги
фігурують в секції <head>
та зазвичай генеруються в макетах.
Якщо ви бажаєте визначити, які мета-теги генерувати у вкладених представленнях, ви можете викликати yii\web\View::registerMetaTag() у вкладеному представленні, подібно до наведеного:
<?php
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']);
?>
В коді вище реєструється мета-тег "keywords" у компоненті представлення. Зареєстрований мета-тег формується після закінчення формування макету. Наступний HTML-код буде згенеровано та вставлено в місці, де ви викличете yii\web\View::head() у макеті:
<meta name="keywords" content="yii, framework, php">
Зауважте, якщо викликати yii\web\View::registerMetaTag() декілька разів, в результаті цього зареєструється кілька мета-тегів, не зважаючи на те, чи мета-теги однакові чи ні.
Щоб мати лише один екземпляр специфічного типу мета-тегу, потрібно визначати ключ в другому параметрі під час виклику методу. Наприклад, наступний код реєструє два мета-теги "description". Однак, лише другий буде сформовано.
$this->registerMetaTag(['name' => 'description', 'content' => 'Це мій класний веб-сайт, який створено за допомогою Yii!'], 'description');
$this->registerMetaTag(['name' => 'description', 'content' => 'Цей веб-сайт про смішних єнотів.'], 'description');
Так само як і мета-теги, теги link є корисними у багатьох випадках, як, наприклад, налаштування favicon, посилання на стрічку новин (RSS) або делегування OpenID іншому серверу. Ви можете працювати з тегами link подібним шляхом як і з мета-тегами, використовуючи yii\web\View::registerLinkTag(). Наприклад, у вкладеному представленні, ви можете зареєструвати тег link наступним чином,
$this->registerLinkTag([
'title' => 'Свіжі новини про Yii',
'rel' => 'alternate',
'type' => 'application/rss+xml',
'href' => 'https://www.yiiframework.com/rss.xml/',
]);
Результатом вищенаведеного коду буде
<link title="Свіжі новини про Yii" rel="alternate" type="application/rss+xml" href="https://www.yiiframework.com/rss.xml/">
Подібно до registerMetaTags(), ви можете визначати ключ під час виклику registerLinkTag() для запобігання генерування повторних тегів link одного типу.
Компоненти представлення породжують кілька подій в процесі формування представлення. Ви можете призначити обробники на ці події для вставлення вмісту в представлення або для опрацювання сформованих результатів перед їх відправленням кінцевим користувачам.
false
для скасування процесу формування.Наприклад, наступний код вставить поточну дату в кінці секції <body>
сторінки:
\Yii::$app->view->on(View::EVENT_END_BODY, function () {
echo date('Y-m-d');
});
До статичних сторінок відносяться ті веб-сторінки, в яких основний вміст здебільшого статичний та не потребує доступу до динамічних даних, що передаються з контролерів.
Можна виводити статичні сторінки, розмістивши їх код у представленні, а потім використовуючи код подібний до наведеного у контролері:
public function actionAbout()
{
return $this->render('about');
}
Якщо веб-сайт містить багато статичних сторінок, було б дуже стомливим повторювати схожий код багато разів. Для вирішення цієї проблеми можна впровадити автономну дію yii\web\ViewAction у контролері. Наприклад,
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
, стане можливим
відображення цього представлення за наступною URL-адресою:
http://localhost/index.php?r=site%2Fpage&view=about
Параметр view
із запиту GET
вказує автономній дії yii\web\ViewAction, яке представлення запитане. Потім дія здійснює пошук
цього представлення в директорії @app/views/site/pages
. Ви можете сконфігурувати yii\web\ViewAction::viewPrefix,
щоб змінити директорію для пошуку цих представлень.
Представлення відповідають за репрезентацію моделей у форматі зрозумілому кінцевим користувачам. В цілому, представлення
$_GET
, $_POST
. Це обов’язок контролерів.
У випадку необхідності дані запиту повинні бути передані в представлення через контролери;Щоб зробити представлення більш контрольованими, уникайте створення представлень, які є дуже складними або містять забагато надлишкового коду. Використовуйте наступні техніки, щоб досягнути цього: