Yii2. Виджеты
03.04.2019
Теги: Web-разработка • Yii2 • Виджет • Теория • Фреймворк
Виджеты — это некоторые компоненты, которые предназначены в первую очередь для реализации элементов интерфейса и которые можно использовать многократно. Классическим примером такого элемента может быть меню. Меню используется практически на каждой странице сайта и от страницы к странице остается неизменным. То есть, на каждой странице нужно повторять один и тот же код для получения меню и его вывода. Но благодаря виджетам можно избежать этой утомительной процедуры и создать меню только один раз, а затем просто вызывать его.
Размещаются виджеты в папке components
, которую нужно создать в корне приложения. Для создания виджета необходимо унаследовать класс yii\base\Widget
. Внутри класса виджета нужно переопределить методы init()
и run()
. Также можно создавать собственные методы. Метод init()
, как правило, используется для нормализации свойств виджета (установка значений), а метод run()
возвращает результат рендеринга.
В Yii2 уже имеется большое количество различных виджетов: для создания форм, меню, jQuery UI и другие. Кроме того, фреймворк позволяет создавать собственные виджеты. Давайте создадим простой виджет, который будет приветствовать посетителей сайта.
Создание виджета
<?php namespace app\components; use yii\base\Widget; use yii\helpers\Html; class HelloWidget extends Widget { public $message; public function init() { parent::init(); if ($this->message === null) { $this->message = 'Добрый день!'; } } public function run() { return '<h1>'.Html::encode($this->message).'</h1>'; } }
Теперь попробуем вызвать созданный виджет в представлении. Для этого необходимо обратиться к созданному классу и вызвать статичный метод widget()
. Метод принимает массив настроек для инициализации виджета и возвращает результат его рендеринга.
<?php /* @var $this yii\web\View */ use app\components\HelloWidget; ?> <div class="page-index"> <?= HelloWidget::widget(['message' => 'Доброе утро!']); ?> </div>
Пока что метод run()
возвращает короткую строку. Но что делать, если нужно возвращать большой объем html-кода? Нужно создать рядом с файлом класса виджета директорию views
, в которую и поместить представление для виджета. Само представление можно получить с помощью метода render()
.
<?php namespace app\components; use yii\base\Widget; class HelloWidget extends Widget { public $message; public function init() { parent::init(); if (!is_null($this->message)) { return; } $hour = date('G'); if ($hour >= 0 && $hour < 6) { $this->message = 'Доброй ночи!'; } elseif ($hour >= 6 && $hour < 12) { $this->message = 'Доброе утро!'; } elseif ($hour >= 12 && $hour < 18) { $this->message = 'Добрый день!'; } else { $this->message = 'Добрый вечер!'; } } public function run() { return $this->render('hello', ['message' => $this->message]); } }
<?php /* * Файл components/views/hello.php */ use yii\helpers\Html; ?> <h1 class="hello"><?= Html::encode($message); ?></h1>
<?php /* @var $this yii\web\View */ use app\components\HelloWidget; ?> <div class="page-index"> <?= HelloWidget::widget(); ?> </div>
Методы begin() и end()
Не все виджеты вызываются с посмощью метода widget()
, иногда у них бывает внутреннее содержимое и тогда виджет вызывается методами begin()
и end()
. Типичный пример — базовый виджет ActiveForm
:
<div class="page-feedback"> <?php $form = ActiveForm::begin(['id' => 'feedback-form']); ?> <?= $form->field($message, 'name')->textInput(); ?> <?= $form->field($message, 'email')->textInput(); ?> <?= $form->field($message, 'body')->textarea(['rows' => 5]); ?> <?= Html::submitButton('Отправить', ['class' => 'btn btn-primary']); ?> <?php ActiveForm::end(); ?> </div>
Этот виджет сгенерирует открывающий и закрывающий тэги <form>
в местах вызова методов begin()
и end()
соответственно. При этом, содержимое, расположенное между вызовами указанных методов будет выведено без каких-либо изменений.
begin()
будет создан новый экземпляр виджета, при этом вызов метода init()
произойдет сразу после выполнения остального кода в конструкторе виджета. При вызове метода end()
, будет вызван метод run()
, а возвращенное им значение будет выведено методом end()
.
Содержимое между вызовами методов begin()
и end()
можно получить внутри класса виджета и как-то обработать:
<?php namespace app\components; use yii\base\Widget; class HelloWidget extends Widget { public $message; public function init() { parent::init(); if (is_null($this->message)) { $this->message = 'Добрый день!'; } ob_start(); } public function run() { $content = ob_get_clean(); return $this->render( 'hello', [ 'message' => $this->message, 'content' => $content ] ); } }
<?php /* * Файл components/views/hello.php */ use yii\helpers\Html; ?> <h1 class="hello"><?= Html::encode($message); ?></h1> <p><?= Html::encode($content); ?></p>
<?php /* @var $this yii\web\View */ use app\components\HelloWidget; ?> <div class="page-index"> <?php HelloWidget::begin(); ?> Lorem ipsum dolor sit amet, consectetur adipisicing elit. <?php HelloWidget::end(); ?> </div>
<div class="page-index"> <h1 class="hello">Добрый день!</h1> <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit.</p> </div>
Поиск: Web-разработка • Yii2 • Виджет • Фреймворк • Widget • init • run • begin • end