# Widgets ¶

Los widgets son bloques de código reutilizables que se usan en las vistas 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
    use yii\jui\DatePicker;
    ?>
    <?= DatePicker::widget(['name' => 'date']) ?>

Yii incluye un buen número de widgets, tales como formulario activo, menú, widgets de jQuery UI, y widgets de Twitter 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. 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 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
    use yii\jui\DatePicker;
    ?>
    <?= DatePicker::widget([
        'model' => $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 `<form>` de apertura y cierre donde se llame a `begin()` y `end()` respectivamente. Cualquier cosa que este en medio se representará tal cual.

    <?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(); ?>

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 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:

    \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 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.

    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
    use app\components\HelloWidget;
    ?>
    <?= HelloWidget::widget(['message' => '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.

    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()`.

> Información: 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
    use app\components\HelloWidget;
    ?>
    <?php HelloWidget::begin(); ?>

        contenido que puede contener <etiqueta>s

    <?php HelloWidget::end(); ?>

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 y llamar al método yii\base\Widget::render() para representarlo. Por ejemplo:

    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.

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 (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. 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.