Советы и принципы

Виджеты в Yii2

Виджеты в Yii2

Что такое виджеты

Виджеты - это многоразовые строительные блоки, обычно используются в видах, чтобы добавить интерфейсу какие-то элементы. C помощью виджетов обеспечивается ООП-подход к повторному использованию кода пользовательского интерфейса.



Примеры виджетов для Yii2


DatePicker - виджет выпадающего календарика

Например, виджетом можно сделать выпадающий календарь DatePicker и повесить его на поле даты, вызывая для него виджет

<?php
use yii\bootstrap\DatePicker;
?>
<?= DatePicker::widget([
    'model' => $model,
    'attribute' => 'from_date',
    'language' => 'ru',
    'clientOptions' => [
        'dateFormat' => 'yy-mm-dd',
    ],
]) ?>

Такой виджет может понадобиться и для других аналогичных полей в вашем приложении, чтобы не дублировать каждый раз весь код выпадающего календарика.


Imperavi Redactor - удобный визуальный редактор

Или визуальный редактор Imperavi Redactor. Он тоже вешается на текстовое поле как виджет, тем самым заменяя стандартное поле типа textarea на поле, в котором можно визуально форматировать текст. То есть вместо

<?= $form->field($model, 'text')->textarea(['rows' => 6]) ?>

мы пишем вызов виджета с настройками для него

<?php use vova07\imperavi\Widget; /* <- это пишем в самом начале файла */ ?>

<?= $form->field($model, 'text', ['template' => "{label}\n{hint}\n{input}\n{error}"])->hint('<i>Выделяйте важные блоки: <code>blockquote</code>, <code>span.important</code>, <code>span.fullimportant</code>, <code><p class="voffset20 embed-responsive embed-responsive-16by9"><iframe class="embed-responsive-item" src=...></code>, <code><figure class="caption"><img src="..." alt="..."><figcaption>...</code>, <code><dl class="dl-horizontal">
                        <dt><span>Родился</span></dt><dd>1982, Мексика</dd>...</code></i>')->widget(Widget::classname(), [
                    'settings' => [
                        'lang' => 'ru',
                        'removeWithoutAttr' => [],
                        'minHeight' => 300,
                        'pastePlainText' => true,
                        'buttonSource' => true,
                        'replaceDivs' => false,
                        'plugins' => [
                            'clips',
                            'fullscreen',
                            'fontfamily',
                            'fontsize',
                            'fontcolor',
                            'video',
                            'table'
                        ],
                                'imageUpload' => Url::to(['/blog/image-upload']),
                                'imageManagerJson' => Url::to(['/blog/images-get']),
                                'fileManagerJson' => Url::to(['/blog/files-get']),
                                'fileUpload' => Url::to(['/blog/file-upload'])
                    ]
                ]);?>

По умолчанию тег <span> вырезается, если у него отсутствуют какие-либо атрибуты (в настройках redactor.js - установлен removeWithoutAttr: ['span']). Исправить это легко, добавив - 'removeWithoutAttr' => [], в параметры settings в вызове виджета Redactor в виде. Это нужно бывает при вёрстке для красивого выравнивания dt/dd. Впрочем, бывает правильнее оформление делать в файле css.


Виджеты, имеющие внутреннее содержимое. ActiveForm

Не все виджеты вызываются как "->widget()", иногда у них бывает внутреннее содержимое и тогда виджет вызывается методами begin() и end()

Типичный пример: базовый виджет - ActiveForm

<?php
use yii\widgets\ActiveForm;
use yii\helpers\Html;
?>
<?php $form = ActiveForm::begin(['id' => 'login-form']); ?>
    <?= $form->field($model, 'username') ?>
    <?= $form->field($model, 'password')->passwordInput() ?>
    <div class="form-group">
        <?= Html::submitButton('Login') ?>
    </div>
<?php ActiveForm::end(); ?>

Создаются свои виджеты наследованием от класса yii\base\Widget, и переопределением методов init() и run(). В init обрабатываются свойства, а run() возвращает результат рендеринга виджета.

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 = 'Hello World';
        }
    }
    public function run()
    {
        return Html::encode($this->message);
    }
}

После этого можно вызывать ваш виджет в виде или макете

<?php
use app\components\HelloWidget;
?>
<?= HelloWidget::widget(['message' => 'Good morning']) ?>

Но чаще всего виджету надо выводить крупный блок содержимого, для чего в run() вызывается метод render() с указанием файла, где этот блок размещён.

public function run()
{
    return $this->render('hello');
}

Этот файл hello.php по-умолчанию хранится в папке components/HelloWidget/views/, то есть внутри папки класса виджета HelloWidget (или любого вашего виджета) создаётся своя папка для видов view, и так у каждого виджета.


Виджет отличается от обычного вида тем, что он организован как отдельный класс, который легко перенести и использовать в другом проекте. Вид же конкретно разрабатывается для текущего приложения. Но виджет, в котором отсутствует PHP-логика, очень сильно похож на обычный вид.

По мотивам – https://github.com/yiisoft/yii2/blob/master/docs/guide-ru/structure-widgets.md