# Controllers (Controladores) ¶

Os controllers (controladores) fazem parte da arquitetura MVC. São objetos de classes que estendem de yii\base\Controller e são responsáveis pelo processamento das requisições e por gerar respostas. Em particular, após assumir o controle de applications, controllers analisarão os dados de entradas obtidos pela requisição, passarão estes dados para os models (modelos), incluirão os resultados dos models (modelos) nas views (visões) e finalmente gerarão as respostas de saída.

## Actions (Ações) ¶

Os controllers são compostos por unidades básicas chamadas de ações que podem ser tratados pelos usuários finais a fim de realizar a sua execução.

No exemplo a seguir mostra um controller `post` com duas ações: `view` e `create`:

    namespace app\controllers;

    use Yii;
    use app\models\Post;
    use yii\web\Controller;
    use yii\web\NotFoundHttpException;

    class PostController extends Controller
    {
        public function actionView($id)
        {
            $model = Post::findOne($id);
            if ($model === null) {
                throw new NotFoundHttpException;
            }

            return $this->render('view', [
                'model' => $model,
            ]);
        }

        public function actionCreate()
        {
            $model = new Post;

            if ($model->load(Yii::$app->request->post()) && $model->save()) {
                return $this->redirect(['view', 'id' => $model->id]);
            } else {
                return $this->render('create', [
                    'model' => $model,
                ]);
            }
        }
    }

Na ação `view` (definido pelo método `actionView()`), o primeiro código carrega o model conforme o ID solicitado; Se o model for devidamente carregado, a ação irá exibi-lo utilizado a view chamada de `view`. Caso contrário, a ação lançará uma exceção.

Na ação `create` (definido pelo método `actionCreate()`), o código é parecido. Primeiro ele tenta popular o model usando os dados da requisição em seguida os salva. Se ambos forem bem sucedidos, a ação redirecionará o navegador para a ação `view` com o novo ID criado pelo model. Caso contrário, a ação exibirá a view `create` na qual os usuário poderão fornecer os dados necessários.

## Routes (Rotas) ¶

Os usuários finais abordarão as ações por meio de rotas. Uma rota é uma string composta pelas seguintes partes:

- um ID do módulo: serve apenas se o controller pertencer a um módulo que não seja da aplicação;
- um ID do controller: uma string que identifica exclusivamente o controller dentre todos os controllers da mesma aplicação (ou do mesmo módulo, caso o controller pertença a um módulo);
- um ID da ação: uma string que identifica exclusivamente uma ação dentre todas as ações de um mesmo controller.

As rotas seguem o seguinte formato:

    IDdoController/IDdoAction

ou o seguinte formato se o controller estiver em um módulo:

    IDdoModule/IDdoController/IDdoAction

Portanto, se um usuário fizer uma requisição com a URL `http://hostname/index.php?r=site/index`, a ação `index` do controller `site` será executada. Para mais detalhes sobre como as ações são resolvidas pelas rotas, por favor consulte a seção Roteamento e Criação de URL.

## Criando Controllers ¶

Em aplicações Web, os controllers devem estender de yii\web\Controller ou de suas classes filhas. De forma semelhante, em aplicaçoes console, os controllers devem estender de yii\console\Controller ou de suas classes filhos. O código a seguir define um controller `site`:

    namespace app\controllers;

    use yii\web\Controller;

    class SiteController extends Controller
    {
    }

### IDs de Controllers ¶

Normalmente, um controller é projetado para tratar as requisições relativos a um determinado tipo de recurso. Por esta razão, os IDs dos controllers geralmente são substantivos que referenciam-se ao tipo de recurso que será tratado. Por exemplo, você pode usar o `article` como o ID do um controller para tratar dados de artigos.

Por padrão, os IDs dos controllers devem conter apenas esses caracteres: letras inglesas em caixa baixa, números, underscores (underline), hífens e barras. Por exemplo, `article` e `post-comment` são ambos IDs de controllers válidos, enquanto `article?`, `PostComment`, `admin\post` não são.

Um ID de controller também pode conter um prefixo para o subdiretório. Por exemplo, `admin/article` representa um controller `article` em um subdiretório `admin` sob o namespace do controller Os caracteres válidos para os prefixos de subdiretórios incluem: letras inglesas em caixa alto ou caixa baixa, números, underscores (underline) e barras, onde as barras são usadas para separar os níveis dos subdiretórios (por exemplo, `panels/admin`).

### Nomenclatura da Classe do Controller ¶

Os nomes da classes dos controllers podem ser derivadas dos IDs dos controllers de acordo com as seguintes procedimentos:

1. Colocar em caixa alta a primeira letra de cada palavra separadas por traço. Observe que se o ID do controller possuir barras, a regra é aplicada apenas na parte após a última barra no ID.
2. Remover os traços e substituir todas as barras por barras invertidas.
3. Adicionar `Controller` como sufixo.
4. Preceder ao namespace do controller.

Segue alguns exemplos, assumindo que o namespace do controller tenha por padrão o valor `app\controllers`:

- `article` torna-se `app\controllers\ArticleController`;
- `post-comment` torna-se `app\controllers\PostCommentController`;
- `admin/post-comment` torna-se `app\controllers\admin\PostCommentController`;
- `adminPanels/post-comment` torna-se `app\controllers\adminPanels\PostCommentController`.

As classes dos controllers devem ser autoloadable. Por esta razão, nos exemplos anteriores, o controller `article` deve ser salvo no arquivo cuja alias é `@app/controllers/ArticleController.php`; enquanto o controller `admin/post-comment` deve ser salvo no `@app/controllers/admin/PostCommentController.php`.

> Informação: No último exemplo `admin/post-comment`, mostra como você pode colocar um controller em um subdiretório do namespace controller. Isto é útil quando você quiser organizar seus controllers em diversas categorias e não quiser usar módulos.

### Mapeando Controllers ¶

Você pode configurar um mapeamento de controllers para superar as barreiras impostas pelos IDs de controllers e pelos nomes de classes descritos acima. Isto é útil principalmente quando quiser esconder controllers de terceiros na qual você não tem controle sobre seus nomes de classes.

Você pode configurar o mapeamento de controllers na configuração da aplicação. Por exemplo:

    [
        'controllerMap' => [
            // declara o controller "account" usando um nome de classe
            'account' => 'app\controllers\UserController',

            // declara o controller "article" usando uma configuração em array
            'article' => [
                'class' => 'app\controllers\PostController',
                'enableCsrfValidation' => false,
            ],
        ],
    ]

### Controller Padrão ¶

Cada aplicação tem um controller padrão que é especificado pela propriedade yii\base\Application::$defaultRoute. Quando uma requisição não especificar uma rota, será utilizada a rota especificada pela propriedade. Para as aplicações Web, este valor é `'site'`, enquanto para as aplicações console é `help`. Portanto, se uma URL for `http://hostname/index.php`, o controller `site` será utilizado nesta requisição.

Você pode alterar o controller padrão como a seguinte configuração da aplicação:

    [
        'defaultRoute' => 'main',
    ]

## Criando Ações ¶

Criar ações pode ser tão simples como a definição dos chamados métodos de ação em uma classe controller. Um método de ação é um método público cujo nome inicia com a palavra `action`. O valor de retorno representa os dados de resposta a serem enviados aos usuário finais. O código a seguir define duas ações, `index` e `hello-world`:

    namespace app\controllers;

    use yii\web\Controller;

    class SiteController extends Controller
    {
        public function actionIndex()
        {
            return $this->render('index');
        }

        public function actionHelloWorld()
        {
            return 'Hello World';
        }
    }

### IDs de Actions ¶

Uma ação muitas vezes é projetada para realizar uma manipulação em particular sobre um recurso. Por esta razão, os IDs das ações geralmente são verbos, tais como `view`, `update`, etc.

Por padrão, os IDs das ações devem conter apenas esses caracteres: letras inglesas em caixa baixa, números, underscores (underline) e traços. Os traços em um ID da ação são usados para separar palavras. Por exemplo, `view`, `update2` e `comment-post` são IDs válidos, enquanto `view?` e `Update` não são.

Você pode criar ações de duas maneiras: ações inline (em sequência) e ações standalone (autônomas). Uma ação inline é definida pelo método de uma classe controller, enquanto uma ação standalone é uma classe que estende de yii\base\Action ou de uma classe-filha. As ações inline exigem menos esforço para serem criadas e muitas vezes as preferidas quando não se tem a intenção de reutilizar estas ações. Ações standalone, por outro lado, são criados principalmente para serem utilizados em diferentes controllers ou para serem distribuídos como extensions.

### Ações Inline ¶

As ações inline referem-se a os chamados métodos de ação, que foram descritos anteriormente.

Os nomes dos métodos de ações são derivadas dos IDs das ações de acordo com os seguintes procedimentos:

1. Colocar em caixa alta a primeira letra de cada palavra do ID da ação;
2. Remover os traços;
3. Adicionar o prefixo `action`.

Por exemplo, `index` torna-se `actionIndex` e `hello-world` torna-se `actionHelloWorld`.

> Observação: Os nomes dos métodos de ações são case-sensitive. Se você tiver um método chamado `ActionIndex`, não será considerado como um método de ação e como resultado, o pedido para a ação `index` lançará uma exceção. Observe também que os métodos de ações devem ser públicas. Um método privado ou protegido NÃO será definido como ação inline.

As ações inline normalmente são as mais utilizadas pois demandam pouco esforço para serem criadas. No entanto, se você deseja reutilizar algumas ações em diferentes lugares ou se deseja distribuir uma ação, deve considerar defini-la como uma ação standalone.

### Ações Standalone ¶

Ações standalone são definidas por classes de ações que estendem de yii\base\Action ou de uma classe-filha. Por example, nas versões do Yii, existe a yii\web\ViewAction e a yii\web\ErrorAction, ambas são ações standalone.

Para usar uma ação standalone, você deve mapear as ações sobrescrevendo o método yii\base\Controller::actions() em suas classes controllers como o seguinte:

    public function actions()
    {
        return [
            // declara a ação "error" usando um nome de classe
            'error' => 'yii\web\ErrorAction',

            // declara a ação "view" usando uma configuração em array
            'view' => [
                'class' => 'yii\web\ViewAction',
                'viewPrefix' => '',
            ],
        ];
    }

Como pode ver, o método `actions()` deve retornar um array cujas chaves são os IDs das ações e os valores correspondentes ao nome da classe da ação ou configurações. Ao contrário das ações inline, os IDs das ações standalone podem conter caracteres arbitrários desde que sejam mapeados no método `actions()`.

Para criar uma classe de ação standalone, você deve estender de yii\base\Action ou de duas classes filhas e implementar um método público chamado `run()`. A regra para o método `run()` é semelhante ao de um método de ação. Por exemplo,

    <?php
    namespace app\components;

    use yii\base\Action;

    class HelloWorldAction extends Action
    {
        public function run()
        {
            return "Hello World";
        }
    }

### Resultados da Ação ¶

O valor de retorno do método de ação ou do método `run()` de uma ação standalone são importantes. Eles representam o resultado da ação correspondente.

O valor de retorno pode ser um objeto de resposta que será enviado como resposta aos usuários finais.

- Para aplicações Web, o valor de retorno também poder ser algum dado arbitrário que será atribuído à propriedade yii\web\Response::$data e ainda ser convertido em uma string para representar o corpo da resposta.
- Para aplicações console, o valor de retorno também poder ser um inteiro representando o exit status (status de saída) da execução do comando.

Nos exemplos acima, todos os resultados são strings que serão tratados como o corpo das respostas para serem enviados aos usuários finais. No exemplo a seguir, mostra como uma ação pode redirecionar o navegador do usuário para uma nova URL retornando um objeto de resposta (o método redirect() retorna um objeto de resposta):

    public function actionForward()
    {
        // redireciona o navegador do usuário para http://example.com
        return $this->redirect('http://example.com');
    }

### Parâmetros da Ação ¶

Os métodos de ações para as ações inline e os métodos `run()` para as ações standalone podem receber parâmetros, chamados parâmetros da ação. Seus valores são obtidos a partir das requisições. Para aplicações Web, o valor de cada parâmetro da ação são obtidos pelo `$_GET` usando o nome do parâmetro como chave; para aplicações console, eles correspondem aos argumentos da linha de comando.

No exemplo a seguir, a ação `view` (uma ação inline) possui dois parâmetros declarados: `$id` e `$version`.

    namespace app\controllers;

    use yii\web\Controller;

    class PostController extends Controller
    {
        public function actionView($id, $version = null)
        {
            // ...
        }
    }

A seguir, os parâmetros da ação serão populados em diferentes requisições:

- `http://hostname/index.php?r=post/view&id=123`: o parâmetro `$id` receberá o valor `'123'`, enquanto o `$version` continuará com o valor nulo porque não existe o parâmetro `version` na URL.
- `http://hostname/index.php?r=post/view&id=123&version=2`: os parâmetros `$id` e `$version` serão receberão os valores `'123'` e `'2'`, respectivamente.
- `http://hostname/index.php?r=post/view`: uma exceção yii\web\BadRequestHttpException será lançada porque o parâmetro obrigatório `$id` não foi informado na requisição.
- `http://hostname/index.php?r=post/view&id[]=123`: uma exceção yii\web\BadRequestHttpException será lançada porque o parâmetro `$id` foi informado com um valor array `['123']` na qual não era esperado.

Se você quiser que um parâmetro da ação aceite valores arrays, deverá declara-lo explicitamente com `array`, como mostro a seguir:

    public function actionView(array $id, $version = null)
    {
        // ...
    }

Agora, se a requisição for `http://hostname/index.php?r=post/view&id[]=123`, o parâmetro `$id` receberá o valor `['123']`. Se a requisição for `http://hostname/index.php?r=post/view&id=123`, o parâmetro `$id` ainda receberá um array como valor pois o valor escalar `'123'` será convertido automaticamente em um array.

Os exemplo acima mostram, principalmente, como os parâmetros da ação trabalham em aplicações Web. Para aplicações console, por favor, consulte a seção Comandos de Console para mais detalhes.

### Default Action ¶

Cada controller tem uma ação padrão especificado pela propriedade yii\base\Controller::$defaultAction. Quando uma rota contém apenas o ID do controller, implica que a ação padrão do controller seja solicitada.

Por padrão, a ação padrão é definida como `index`. Se quiser alterar o valor padrão, simplesmente sobrescreva esta propriedade na classe controller, como o seguinte:

    namespace app\controllers;

    use yii\web\Controller;

    class SiteController extends Controller
    {
        public $defaultAction = 'home';

        public function actionHome()
        {
            return $this->render('home');
        }
    }

## Ciclo de Vida do Controller ¶

Ao processar uma requisição, a aplicação criará um controller baseada na rota solicitada. O controller, então, se submeterá ao seguinte ciclo de vida para concluir a requisição:

1. O método yii\base\Controller::init() é chamado após o controller ser criado e configurado.
2. O controller cria um objeto da ação baseada no ID da ação solicitada:
   - Se o ID da ação não for especificado, o ID da ação padrão será utilizada.
   - Se o ID da ação for encontrada no mapeamento das ações, uma ação standalone será criada;
   - Se o ID da ação for encontrada para corresponder a um método de ação, uma ação inline será criada;
   - Caso contrário, uma exceção yii\base\InvalidRouteException será lançada.
3. De forma sequencial, o controller chama o método `beforeAction()` da aplicação, o módulo (se o controller pertencer a um módulo) e o controller.
   - Se uma das chamadas retornar `false`, o restante dos métodos subsequentes `beforeAction()` serão ignoradas e a execução da ação será cancelada.
   - Por padrão, cada método `beforeAction()` desencadeia a execução de um evento chamado `beforeAction` na qual você pode associar a uma função (handler).
4. O controller executa a ação:
   - Os parâmetros da ação serão analizados e populados a partir dos dados obtidos pela requisição;
5. De forma sequencial, o controller chama o método `afterAction()` do controller, o módulo (se o controller pertencer a um módulo) e a aplicação.
   - Por padrão, cada método `afterAction()` desencadeia a execução de um evento chamado `afterAction` na qual você pode associar a uma função (handler).
6. A aplicação obterá o resultado da ação e irá associá-lo na resposta.

## Boas Práticas ¶

Em uma aplicação bem projetada, frequentemente os controllers são bem pequenos na qual cada ação possui poucas linhas de códigos. Se o controller for um pouco complicado, geralmente indica que terá que refaze-lo e passar algum código para outro classe.

Segue algumas boas práticas em destaque. Os controllers:

- podem acessar os dados de uma requisição;
- podem chamar os métodos dos models e outros componentes de serviço com dados da requisição;
- podem usar as views para compor as respostas;
- NÃO devem processar os dados da requisição - isto deve ser feito na camada model (modelo);
- devem evitar inserir códigos HTML ou outro código de apresentação - é melhor que sejam feitos nas views.