|
|
|
Виджеты
|
|
|
|
=======
|
|
|
|
|
|
|
|
Виджеты представляют собой многоразовые строительные блоки, используемые в [представлениях](structure-views.md)
|
|
|
|
для создания сложных и настраиваемых элементов пользовательского интерфейса в рамках объектно-ориентированного
|
|
|
|
подхода. Например, виджет выбора даты (date picker) позволяет генерировать интерактивный интерфейс для выбора дат,
|
|
|
|
предоставляя пользователям приложения удобный способ для ввода данных такого типа. Все, что нужно для
|
|
|
|
подключения виджета - это добавить следующий код в представление:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use yii\bootstrap\DatePicker;
|
|
|
|
?>
|
|
|
|
<?= DatePicker::widget(['name' => 'date']) ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
В комплект Yii входит большое количество виджетов, например: [[yii\widgets\ActiveForm|active form]],
|
|
|
|
[[yii\widgets\Menu|menu]], [виджеты jQuery UI](widget-jui.md), [виджеты Twitter Bootstrap](widget-bootstrap.md).
|
|
|
|
Далее будут представлены базовые сведения о виджетах. Для получения сведений относительно использования
|
|
|
|
конкретного виджета, следует обратиться к документации соответствующего класса.
|
|
|
|
|
|
|
|
|
|
|
|
## Использование Виджетов <a name="using-widgets"></a>
|
|
|
|
|
|
|
|
Главным образом, виджеты применяют в [представлениях](structure-views.md). Для того, чтобы использовать виджет
|
|
|
|
в представлении, достаточно вызвать метод [[yii\base\Widget::widget()]]. Метод принимает массив [настроек](concept-configurations.md)
|
|
|
|
для инициализации виджета и возвращает результат его рендеринга. Например, следующий
|
|
|
|
код добавляет виджет для выбора даты, сконфигурированный для использования русского в качестве языка интерфейса
|
|
|
|
виджета и хранения вводимых данных в атрибуте `from_date` модели `$model`.
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use yii\bootstrap\DatePicker;
|
|
|
|
?>
|
|
|
|
<?= DatePicker::widget([
|
|
|
|
'model' => $model,
|
|
|
|
'attribute' => 'from_date',
|
|
|
|
'language' => 'ru',
|
|
|
|
'clientOptions' => [
|
|
|
|
'dateFormat' => 'yy-mm-dd',
|
|
|
|
],
|
|
|
|
]) ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
Некоторые виджеты могут иметь внутреннее содержимое, которое следует располагать между вызовами методов
|
|
|
|
[[yii\base\Widget::begin()]] и [[yii\base\Widget::end()]]. Например, для генерации формы входа, в следующем
|
|
|
|
фрагменте кода используется виджет [[yii\widgets\ActiveForm]]. Этот виджет сгенерирует открывающий и закрывающий
|
|
|
|
тэги `<form>` в местах вызова методов `begin()` и `end()` соответственно. При этом, содержимое, расположенное
|
|
|
|
между вызовами указанных методов будет выведено без каких-либо изменений.
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?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::widget()]], который возвращает результат
|
|
|
|
рендеринга, метод [[yii\base\Widget::begin()]] возвращает экземпляр виджета, который может быть
|
|
|
|
использован в дальнейшем для формирования его внутреннего содержимого.
|
|
|
|
|
|
|
|
|
|
|
|
## Создание Виджетов <a name="creating-widgets"></a>
|
|
|
|
|
|
|
|
Для того, чтобы создать виджет, следует унаследовать класс [[yii\base\Widget]] и переопределить методы
|
|
|
|
[[yii\base\Widget::init()]] и/или [[yii\base\Widget::run()]]. Как правило, метод `init()` должен содержать
|
|
|
|
код, выполняющий нормализацию свойств виджета, а метод `run()` - код, возвращающий результат рендеринга виджета.
|
|
|
|
Результат рендеринга может быть выведен непосредственно с помощью конструкции "echo" или же возвращен
|
|
|
|
в строке методом `run()`.
|
|
|
|
|
|
|
|
В следующем примере, виджет `HelloWidget` HTML-кодирует и отображает содержимое, присвоенное свойству `message`.
|
|
|
|
В случае, если указанное свойство не установлено, виджет, в качестве значения по умолчанию отобразит строку "Hello World".
|
|
|
|
|
|
|
|
```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 = 'Hello World';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
return Html::encode($this->message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Для того, чтобы использовать этот виджет, достаточно добавить в представление следующий код:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use app\components\HelloWidget;
|
|
|
|
?>
|
|
|
|
<?= HelloWidget::widget(['message' => 'Good morning']) ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
Ниже представлен вариант виджета `HelloWidget`, который принимает содержимое, обрамленное вызовами методов
|
|
|
|
`begin()` и `end()`, HTML-кодирует его и выводит.
|
|
|
|
|
|
|
|
```php
|
|
|
|
namespace app\components;
|
|
|
|
|
|
|
|
use yii\base\Widget;
|
|
|
|
use yii\helpers\Html;
|
|
|
|
|
|
|
|
class HelloWidget extends Widget
|
|
|
|
{
|
|
|
|
public function init()
|
|
|
|
{
|
|
|
|
parent::init();
|
|
|
|
ob_start();
|
|
|
|
}
|
|
|
|
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
$content = ob_get_clean();
|
|
|
|
return Html::encode($content);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Как Вы можете видеть, в методе `init()` происходит включение буферизации вывода PHP таким образом, что весь вывод
|
|
|
|
между вызовами `init()` и `run()` может быть перехвачен, обработан и возвращен в `run()`.
|
|
|
|
|
|
|
|
> Информация: При вызове метода [[yii\base\Widget::begin()]] будет создан новый экземпляр виджета, при этом
|
|
|
|
вызов метода `init()` произойдет сразу после выполнения остального кода в конструкторе виджета.
|
|
|
|
При вызове метода [[yii\base\Widget::end()]], будет вызван метод `run()`, а возвращенное им значение будет выведено
|
|
|
|
методом `end()`.
|
|
|
|
|
|
|
|
Следующий фрагмент кода содержит пример использования модифицированного варианта `HelloWidget`:
|
|
|
|
|
|
|
|
```php
|
|
|
|
<?php
|
|
|
|
use app\components\HelloWidget;
|
|
|
|
?>
|
|
|
|
<?php HelloWidget::begin(); ?>
|
|
|
|
|
|
|
|
content that may contain <tag>'s
|
|
|
|
|
|
|
|
<?php HelloWidget::end(); ?>
|
|
|
|
```
|
|
|
|
|
|
|
|
В некоторых случаях, виджету может потребоваться вывести крупный блок содержимого. И хотя это содержимое может
|
|
|
|
быть встроено непосредственно в метод `run()`, целесообразней поместить его в [представление](structure-views.md)
|
|
|
|
и вызвать метод [[yii\base\Widget::render()]] для его рендеринга. Например,
|
|
|
|
|
|
|
|
```php
|
|
|
|
public function run()
|
|
|
|
{
|
|
|
|
return $this->render('hello');
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
По умолчанию, файлы представлений виджетов должны находиться в директории `WidgetPath/views`, где `WidgetPath` -
|
|
|
|
директория, содержащая файл класса виджета. Таким образом, в приведенном выше примере, для виджета будет
|
|
|
|
использован файл представления `@app/components/views/hello.php`, при этом файл с классом виджета расположен в
|
|
|
|
`@app/components`. Для того, чтобы изменить директорию, в которой содержатся файлы-представления для виджета,
|
|
|
|
следует переопределить метод [[yii\base\Widget::getViewPath()]].
|
|
|
|
|
|
|
|
|
|
|
|
## Лучшие Практики <a name="best-practices"></a>
|
|
|
|
|
|
|
|
Виджеты представляют собой объектно-ориентированный подход к повторному использованию кода пользовательского
|
|
|
|
интерфейса.
|
|
|
|
|
|
|
|
При создании виджетов, следует придерживаться основных принципов концепции MVC. В общем случае, основную логику
|
|
|
|
следует располагать в классе виджета, разделяя при этом код, отвечающий за разметку в [представления](structure-views.md).
|
|
|
|
|
|
|
|
Разрабатываемые виджеты должны быть самодостаточными. Это означает, что для их использования должно быть
|
|
|
|
достаточно всего лишь добавить виджет в представление. Добиться этого бывает затруднительно в том случае,
|
|
|
|
когда для его функционирования требуются внешние ресурсы, такие как CSS, JavaScript, изображения и т.д.
|
|
|
|
К счастью, Yii предоставляет поддержку механизма для работы с ресурсами [asset bundles](structure-asset-bundles.md),
|
|
|
|
который может быть успешно использован для решения данной проблемы.
|
|
|
|
|
|
|
|
В случае, когда виджет не содержит логики, а содержит только код, отвечающий за вывод разметки, он мало
|
|
|
|
отличается от [представления](structure-views.md). В действительности, единственное его отличие состоит в том, что
|
|
|
|
виджет представляет собой отдельный и удобный для распространения класс, в то время как представление - это
|
|
|
|
обычный PHP скрипт, подходящий для использования только лишь в конкретном приложении.
|