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

Каталог оборудования
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Производители
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Функциональные группы
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.