Widgets ======= Los _widgets_ son bloques de código reutilizables que se usan en las [vistas](structure-views.md) para crear elementos de interfaz de usuario complejos y configurables, de forma orientada a objetos. Por ejemplo, un _widget_ de selección de fecha puede generar un selector de fechas bonito que permita a los usuarios seleccionar una fecha. Todo lo que hay que hacer es insertar el siguiente código en una vista: ```php 'date']) ?> ``` Yii incluye un buen número de _widgets_, tales como [[yii\widgets\ActiveForm|formulario activo]], [[yii\widgets\Menu|menú]], [_widgets_ de jQuery UI](https://www.yiiframework.com/extension/yiisoft/yii2-jui), y [_widgets_ de Twitter Bootstrap](https://www.yiiframework.com/extension/yiisoft/yii2-bootstrap). A continuación presentaremos las nociones básicas de de los _widgets_. Por favor, refiérase a la documentación de la API de clases si quiere aprender más acerca del uso de un _widget_ en particular. ## Uso de los _widgets_ Los _widgets_ se usan principalmente en las [vistas](structure-views.md). Se puede llamar al método [[yii\base\Widget::widget()]] para usar un _widget_ en una vista. El método toma un _array_ de [configuración](concept-configurations.md) para inicializar el _widget_ y devuelve la representación resultante del _widget_. Por ejemplo, el siguiente código inserta un _widget_ de selección de fecha configurado para usar el idioma ruso y guardar la selección en el atributo `from_date` de `$model`. ```php $model, 'attribute' => 'from_date', 'language' => 'ru', 'dateFormat' => 'php:Y-m-d', ]) ?> ``` Algunos _widgets_ pueden coger un bloque de contenido que debería encontrarse entre la invocación de [[yii\base\Widget::begin()]] y [[yii\base\Widget::end()]]. Por ejemplo, el siguiente código usa el _widget_ [[yii\widgets\ActiveForm]] para generar un formulario de inicio de sesión. El _widget_ generará las etiquetas `
` de apertura y cierre donde se llame a `begin()` y `end()` respectivamente. Cualquier cosa que este en medio se representará tal cual. ```php 'login-form']); ?> field($model, 'username') ?> field($model, 'password')->passwordInput() ?>
``` Hay que tener en cuenta que, a diferencia de [[yii\base\Widget::widget()]] que devuelve la representación resultante del _widget_, el método [[yii\base\Widget::begin()]] devuelve una instancia del _widget_, que se puede usar para generar el contenido del _widget_. > Nota: Algunos _widgets_ utilizan un [búfer de salida](http://php.net/manual/es/book.outcontrol.php) > para ajustar el contenido rodeado al invocar [[yii\base\Widget::end()]]. Por este motivo se espera > que las llamadas a [[yii\base\Widget::begin()]] y [[yii\base\Widget::end()]] tengan lugar en el > mismo fichero de vista. > No seguir esta regla puede desembocar en una salida distinta a la esperada. ### Configuración de las variables globales predefinidas Las variables globales predefinidas de un _widget_ se pueden configurar por medio del contenedor de inyección de dependencias: ```php \Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]); ``` Consulte la [sección "Uso práctico" de la Guía del contenedor de inyección de dependencias](concept-di-container.md#practical-usage) para más detalles. ## Creación de _widgets_ Para crear un _widget_, extienda la clase [[yii\base\Widget]] y sobrescriba los métodos [[yii\base\Widget::init()]] y/o [[yii\base\Widget::run()]]. Normalmente el método `init()` debería contener el código que inicializa las propiedades del _widget_, mientras que el método `run()` debería contener el código que genera la representación resultante del _widget_. La representación resultante del método `run()` puede pasarse directamente a `echo` o devolverse como una cadena. En el siguiente ejemplo, `HelloWidget` codifica en HTML y muestra el contenido asignado a su propiedad `message`. Si la propiedad no está establecida, mostrará «Hello World» por omisión. ```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); } } ``` Para usar este _widget_, simplemente inserte el siguiente código en una vista: ```php 'Good morning']) ?> ``` Abajo se muestra una variante de `HelloWidget` que toma el contenido insertado entre las llamadas a `begin()` y `end()`, lo codifica en HTML y posteriormente lo muestra. ```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); } } ``` Como se puede observar, el búfer de salida de PHP es iniciado en `init()` para que toda salida entre las llamadas de `init()` y `run()` puede ser capturada, procesada y devuelta en `run()`. > Info: Cuando llame a [[yii\base\Widget::begin()]], se creará una nueva instancia del _widget_ y se > llamará a su método `init()` al final del constructor del _widget_. Cuando llame a > [[yii\base\Widget::end()]], se invocará el método `run()` y el resultado que devuelva será pasado > a `echo` por `end()`. El siguiente código muestra cómo usar esta nueva variante de `HelloWidget`: ```php contenido que puede contener s ``` A veces, un _widget_ puede necesitar representar un gran bloque de contenido. Aunque que se podría incrustar el contenido dentro del método `run()`, es preferible ponerlo dentro de una [vista](structure-views.md) y llamar al método [[yii\base\Widget::render()]] para representarlo. Por ejemplo: ```php public function run() { return $this->render('hello'); } ``` Por omisión, las vistas para un _widget_ deberían encontrarse en ficheros dentro del directorio `WidgetPath/views`, donde `WidgetPath` representa el directorio que contiene el fichero de clase del _widget_. Por lo tanto, el ejemplo anterior representará el fichero de vista `@app/components/views/hello.php`, suponiendo que la clase del _widget_ se encuentre en `@app/components`. Se puede sobrescribir el método [[yii\base\Widget::getViewPath()]] para personalizar el directorio que contiene los ficheros de vista del _widget_. ## Buenas prácticas Los _widgets_ son una manera orientada a objetos de reutilizar código de las vistas. Al crear _widgets_, debería continuar suguiendo el patrón MVC. En general, se debería mantener la lógica en las clases del widget y la presentación en las [vistas](structure-views.md). Los _widgets_ deberían diseñarse para ser autosuficientes. Es decir, cuando se use un _widget_, se debería poder ponerlo en una vista sin hacer nada más. Esto puede resultar complicado si un _widget_ requiere recursos externos, tales como CSS, JavaScript, imágenes, etc. Afortunadamente Yii proporciona soporte para [paquetes de recursos](structure-asset-bundles.md) (_asset bundles_) que se pueden utilizar para resolver este problema. Cuando un _widget_ sólo contiene código de vista, es muy similar a una [vista](structure-views.md). De hecho, en este caso, su única diferencia es que un _widget_ es una clase redistribuible, mientras que una vista es sólo un simple script PHP que prefiere mantener dentro de su aplicación.