Widgets
=======

Os widgets são blocos de construção reutilizáveis usados nas 
[views (visões)](structure-views.md) para criar e configurar complexos elementos 
de interface do usuário sob uma modelagem orientada a objetos. Por exemplo, um 
widget datapicker pode gerar um calendário que permite aos usuários selecionarem 
uma data que desejam inserir em um formulário. Tudo o que você precisa fazer é 
apenas inserir um código na view (visão) conforme o seguinte:

```php
<?php
use yii\jui\DatePicker;
?>
<?= DatePicker::widget(['name' => 'date']) ?>
```

Existe uma quantidade considerável de widgets empacotados no Yii, como o 
[[yii\widgets\ActiveForm|active form]], o [[yii\widgets\Menu|menu]], o 
[jQuery UI widgets](widget-jui.md), o [Twitter Bootstrap widgets](widget-bootstrap.md), etc.
A seguir, iremos introduzir os conhecimentos básicos sobre os widgets. Por favor,
consulte a documentação de classes da API se você quiser saber mais sobre o uso de um determinado widget.


## Usando Widgets <a name="using-widgets"></a>

Os widgets são usados principalmente nas [views (visões)](structure-views.md). 
Você pode chamar o método [[yii\base\Widget::widget()]] para usar um widget em 
uma view (visão). O método possui um array de [configuração](concept-configurations.md) 
para inicializar o widget e retornar o resultado da renderização do widget. Por 
exemplo, o código a seguir insere um widget datapicker configurado para usar o 
idioma Russo e manter a data selecionada no atributo `from_date` do `$model`.

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

Alguns widgets podem ter um bloco de conteúdo que deve ser colocado entre as 
chamadas dos métodos [[yii\base\Widget::begin()]] e [[yii\base\Widget::end()]]. 
Por exemplo, o código a seguir usa o widget [[yii\widgets\ActiveForm]] para gerar
um formulário de login. O widget irá gerar as tags de abertura e de fechamento 
do `<form>` respectivamente nos lugares onde os métodos `begin()` e `end()` foram 
chamados. Qualquer conteúdo entre estes métodos serão renderizados entre as tags 
de abertura e de fechamento do `<form>`.

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

Observe que ao contrário do [[yii\base\Widget::widget()]] que retorna a 
renderização de um widget, o método [[yii\base\Widget::begin()]] retorna uma 
instância do widget que pode ser usado para construir o seu conteúdo.


## Criando Widgets <a name="creating-widgets"></a>

Para criar um widget, estenda a classe [[yii\base\Widget]] e sobrescreva os 
métodos [[yii\base\Widget::init()]] e/ou [[yii\base\Widget::run()]]. Normalmente, 
o método `init()` deve conter os códigos que normalizam as propriedade do widget, 
enquanto o método `run()` deve conter o código que gera o resultado da renderização 
do widget. O resultado da renderização pode ser feito diretamente dando "echo" ou 
pelo retorno de uma string no método `run()`.

No exemplo a seguir, o `HelloWidget` codifica o HTML e exibe o conteúdo atribuído 
à sua propriedade `message`. Se a propriedade não for definida, será exibido 
"Hello World" como padrão.

```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, simplesmente insira o código a seguir em uma view (visão):

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

O `HelloWidget` abaixo é uma variante que pega o conteúdo entre as chamadas de 
`begin()` e `end()`, codifica o HTML e em seguida os exibe.

```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 você pode ver, o buffer de saída do PHP é iniciado no método `init()` para 
que qualquer conteúdo entre as chamadas de `init()` e `run()` possam ser capturadas, 
processadas e retornadas em `run()`.

> Informação: Ao chamar o [[yii\base\Widget::begin()]], uma nova instância do 
  widget será criada e o método `init()` será chamado logo ao final de seu construtor.
  Ao chamar o [[yii\base\Widget::end()]], o método `run()` será chamado cujo o 
  resultado da renderização será dado *echo* pelo `end()`.

O código a seguir mostra como você pode usar esta nova variante do `HelloWidget`:

```php
<?php
use app\components\HelloWidget;
?>
<?php HelloWidget::begin(); ?>

    um conteúdo qualquer...

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

Algumas vezes, um widget pode precisar renderizar um grande conteúdo. Enquanto 
você pode inserir todo este conteúdo no método `run()`, uma boa prática é 
colocá-lo em uma [view (visão)](structure-views.md) e chamar o 
[[yii\base\Widget::render()]] para renderizá-lo. Por exemplo,

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

Por padrão, as views (visões) para um widget devem ser armazenadas em arquivos 
sob o diretório `WidgetPath/views`, onde o `WidgetPath` significa o diretório 
que contém os arquivo da classe do widget. Portanto, o exemplo anterior irá 
renderizar o arquivo de view (visão) `@app/components/views/hello.php`, assumindo 
que a classe widget está localizada sob o diretório `@app/components`. Você pode 
sobrescrever o método [[yii\base\Widget::getViewPath()]] para personalizar o 
diretório que conterá os arquivos de views (visões) do widget.


## Boas Práticas <a name="best-practices"></a>

Os widgets são uma maneira orientada a objetos de reutilizar códigos de view (visão).

Ao criar os widgets, você ainda deve seguir o padrão MVC. Em geral, você deve 
manter a lógica nas classes widgets e manter as apresentações nas 
[views (visões)](structure-views.md).

Os widgets devem ser projetados para serem autossuficientes. Isto é, ao utilizar 
um widget, você deverá ser capaz de removê-lo de uma view (visão) sem fazer 
qualquer outra coisa. Isto pode ser complicado se um widget requerer recursos 
externos, tais como CSS, JavaScript, imagens, etc. Felizmente, o Yii fornece o 
suporte para [asset bundles](structure-assets.md), que pode ser utilizado para 
resolver este problema.

Quando um widget contiver somente código de view (visão), será bem semelhante a 
uma [view (visão)](structure-views.md). Na verdade, neste caso, a única diferença 
é que um widget é uma classe para ser redistribuída, enquanto uma view é apenas 
um simples script PHP que você preferirá manter em sua aplicação
