0 follower

Controladores

Los controladores son parte del patrón o arquitectura MVC. Son objetos que extienden de yii\base\Controller y se encargan de procesar los requests (consultas) generando responses (respuestas). Particularmente, después de tomar el control desde las aplicaciones, los controladores analizarán los datos que entran en el request, los pasan a los modelos, inyectan los modelos resultantes a las vistas, y finalmente generan los responses (respuestas) de salida.

Acciones

Los Controladores están compuestos por acciones que son las unidades más básicas a las que los usuarios pueden dirigirse y solicitar ejecución. Un controlador puede tener una o múltiples acciones.

El siguiente ejemplo muestra un controlador post con dos acciones: view y 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,
            ]);
        }
    }
}

En la acción view (definida en el método actionView()), el código primero carga el modelo de acuerdo el ID del modelo solicitado; Si el modelo es cargado satisfactoriamente, lo mostrará usando una vista llamada view. Si no, arrojará una excepción.

En la acción create (definida por el método actionCreate()), el código es similar. Primero intenta poblar el modelo usando datos del request y guardarlo. Si ambas cosas suceden correctamente, se redireccionará el navegador a la acción view con el ID del modelo recientemente creado. De otro modo mostrará la vista create a través de la cual el usuario puede completar los campos necesarios.

Routes

Los usuarios ejecutan las acciones a través de las llamadas routes (rutas). una ruta es una cadena que consiste en las siguientes partes:

  • un ID de módulo: este existe solamente si el controlador pertenece a un módulo que no es de la aplicación;
  • un ID de controlador: una cadena que identifica exclusivamente al controlador entre todos los controladores dentro de la misma aplicación (o el mismo módulo si el controlador pertenece a uno);
  • un ID de acción: una cadena que identifica exclusivamente a la acción entre todas las acciones del mismo controlador.

Las rutas pueden usar el siguiente formato:

ControllerID/ActionID

o el siguiente formato si el controlador pertenece a un módulo:

ModuleID/ControllerID/ActionID

Entonces si un usuario solicita la URL http://hostname/index.php?r=site/index, la acción index del controlador site será ejecutado. Para más detalles acerca de cómo las son resueltas en acciones, por favor consulta la sección Routing.

Creando Controladores

En aplicaciones Web, los controladores deben extender de yii\web\Controller o cualquier clase hija. De forma similar los controladores de aplicaciones de consola, deben extender de yii\console\Controller o cualquier clase hija de esta. El siguiente código define un controlador site:

namespace app\controllers;

use yii\web\Controller;

class SiteController extends Controller
{
}

IDs de Controladores

Normalmente, un controlador está diseñado para manejar los requests de acuerdo a un tipo de recurso. Por esta razón, los IDs de controladores son a menudo sustantivos de los tipos de recurso que están manejando. Por ejemplo, podrías utilizar article como el ID de un controlador que maneja datos de artículos.

Por defecto, los IDs de controladores deberían contener sólo estos caracteres: letras del Inglés en minúscula, dígitos, guiones bajos y medios, y barras. Por ejemplo, article, post-comment, admin/post-comment son todos IDs de controladores válidos, mientras que article?, PostComment, admin\post no lo son.

Los guiones en un ID de controlador son utilizados para separar palabras, mientras que las barras diagonales lo son para organizar los controladores en sub-directorios.

Nombres de Clases de Controladores

Los nombres de clases de controladores pueden ser derivados de los IDs de acuerdo a las siguientes reglas:

  • Transforma la primera letra de cada palabra separada por guiones en mayúscula. Nota que si el ID del controlador contiene barras, esta regla sólo aplica a la porción después de la última barra dentro del ID.
  • Elimina guiones y reemplaza cualquier barra diagonal por barras invertidas.
  • Agrega el sufijo Controller.
  • Agrega al principio el controller namespace.

A continuación mostramos algunos ejemplos, asumiendo que el controller namespace toma el valor por defecto: app\controllers:

  • article deriva en app\controllers\ArticleController;
  • post-comment deriva en app\controllers\PostCommentController;
  • admin/post-comment deriva en app\controllers\admin\PostCommentController.

Las clases de controladores deben ser autocargables. Por esta razón, en los ejemplos anteriores, la clase del controlador article debe ser guardada en un archivo cuyo alias alias es @app/controllers/ArticleController.php; mientras que el controlador admin/post-comment debería estar en @app/controllers/admin/PostCommentController.php.

Información: En el último ejemplo, admin/post-comment, demuestra cómo puedes poner un controlador bajo un sub-directorio del controller namespace. Esto es útil cuando quieres organizar tus controladores en varias categorías pero sin utilizar módulos.

Controller Map

Puedes configurar controller map (mapeo de controladores) para superar las restricciones de los IDs de controladores y sus nombres de clase descritos arriba. Esto es principalmente útil cuando estás utilizando un controlador de terceros del cual no tienes control alguno sobre sus nombres de clase.

Puedes configurar controller map en la configuración de la aplicación de la siguiente manera:

[
    'controllerMap' => [
        [
            // declara el controlador "account" usando un nombre de clase
            'account' => 'app\controllers\UserController',

            // declara el controlador "article" utilizando un array de configuración
            'article' => [
                'class' => 'app\controllers\PostController',
                'enableCsrfValidation' => false,
            ],
        ],
    ],
]

Controller por Defecto

Cada aplicación tiene un controlador por defecto especificado a través de la propiedad yii\base\Application::$defaultRoute. Cuando un request no especifica una ruta, se utilizará la ruta especificada en esta propiedad. Para aplicaciones Web, el valor es 'site', mientras que para aplicaciones de consola es help. Por lo tanto, si la URL es http://hostname/index.php, significa que el request será manejado por el controlador site.

Puedes cambiar el controlador por defecto con la siguiente configuración de la aplicación:

[
    'defaultRoute' => 'main',
]

Creando Acciones

Crear acciones puede ser tan simple como definir un llamado método de acción en una clase controlador. Un método de acción es un método public cuyo nombre comienza con la palabra action. El valor de retorno de uno de estos métodos representa los datos de respuesta (response) a ser enviado a los usuarios. El siguiente código define dos acciones: index y hello-world:

namespace app\controllers;

use yii\web\Controller;

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

    public function actionHelloWorld()
    {
        return 'Hola Mundo!';
    }
}

IDs de Acciones

Una acción está a menudo diseñada para realizar una manipulación particular de un recurso. Por esta razón, los IDs de acciones son usualmente verbos, como view (ver), update (actualizar), etc.

Por defecto, los IDs de acciones deberían contener estos caracteres solamente: letras en Inglés en minúsculas, dígitos, guiones bajos y barras. Los guiones en un ID de acción son utilizados para separar palabras. Por ejemplo, view, update2, comment-post son todos IDs válidos, mientras que view? y Update no lo son.

Puedes crear acciones de dos maneras: acciones en línea (inline) o acciones independientes (standalone). Una acción en línea es definida como un método en la clase del controlador, mientras que una acción independiente es una clase que extiende yii\base\Action o sus clases hijas. Las acciones en línea son más fáciles de crear y por lo tanto preferidas si no tienes intenciones de volver a utilizarlas. Las acciones independientes, por otro lado, son principalmente creadas para ser reutilizadas en otros controladores o para ser redistribuidas como extensiones.

Acciones en Línea

Como acciones en línea nos referimos a acciones que son definidas en términos de métodos como acabamos de describir.

Los nombre de métodos de acciones derivan de los IDs de acuerdo al siguiente criterio:

  • Transforma la primera letra de cada palabra del ID de la acción a mayúscula;
  • Elimina guiones;
  • Prefija la palabra action.

Por ejemplo, index se vuelve actionIndex, y hello-world se vuelve actionHelloWorld.

Nota: Los nombres de los métodos de acción son case-sensitive (distinguen entre minúsculas y mayúsculas). Si tienes un método llamado ActionIndex, no será considerado como un método de acción, y como resultado, solicitar la acción index resultará en una excepción. También ten en cuenta que los métodos de acción deben ser public. Un método private o protected NO define un método de acción.

Las acciones en línea son las más comúnmente definidas ya que requieren muy poco esfuerzo de creación. De todos modos, si planeas reutilizar la misma acción en diferentes lugares, o quieres redistribuir una acción, deberías considerar definirla como un acción independiente.

Acciones Independientes

Las acciones independientes son acciones definidas en términos de clases de acción que extienden de yii\base\Action o cualquiera de sus clases hijas. Por ejemplo, en Yii se encuentran las clases yii\web\ViewAction y yii\web\ErrorAction, de las cuales ambas son acciones independientes.

Para utilizar una acción independiente, debes declararla en el action map (mapeo de acciones) sobrescribiendo el método yii\base\Controller::actions() en tu controlador de la siguiente manera:

public function actions()
{
    return [
        // declara la acción "error" utilizando un nombre de clase
        'error' => 'yii\web\ErrorAction',

        // declara la acción "view" utilizando un array de configuración
        'view' => [
            'class' => 'yii\web\ViewAction',
            'viewPrefix' => '',
        ],
    ];
}

Como puedes ver, el método actions() debe devolver un array cuyas claves son los IDs de acciones y sus valores los nombres de clases de acciones o configuraciones. Al contrario de acciones en línea, los IDs de acciones independientes pueden contener caracteres arbitrarios, mientras sean declarados en el método actions().

Para crear una acción independiente, debes extender de yii\base\Action o una clase hija, e implementar un método public llamado run(). El rol del método run() es similar al de un método de acción. Por ejemplo:

<?php
namespace app\components;

use yii\base\Action;

class HelloWorldAction extends Action
{
    public function run()
    {
        return "Hola Mundo!";
    }
}

Resultados de Acción

El valor de retorno de una método de acción o del método run() de una acción independiente son significativos. Este se refiere al resultado de la acción correspondiente.

El valor devuelto puede ser un objeto response que será enviado como respuesta a los usuarios.

En los ejemplos mostrados arriba, los resultados de las acciones son todas cadenas que serán tratadas como el cuerpo de la respuesta a ser enviado a los usuarios. El siguiente ejemplo demuestra cómo una acción puede redirigir el navegador del usuario a una nueva URL devolviendo un objeto response (debido a que el método redirect() devuelve un objeto response):

public function actionForward()
{
    // redirige el navegador del usuario a http://example.com
    return $this->redirect('http://example.com');
}

Parámetros de Acción

Los métodos de acción para acciones en línea y el método run() de acciones independientes pueden tomar parámetros, llamados parámetros de acción. Sus valores son obtenidos del request. Para aplicaciones Web, el valor de cada parámetro de acción es tomado desde $_GET usando el nombre del parámetro como su clave; para aplicaciones de consola, estos corresponden a los argumentos de la línea de comandos.

En el siguiente ejemplo, la acción view (una acción en línea) declara dos parámetros: $id y $version.

namespace app\controllers;

use yii\web\Controller;

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

Los parámetros de acción serán poblados como se muestra a continuación para distintos requests:

  • http://hostname/index.php?r=post/view&id=123: el parámetro $id tomará el valor '123', mientras que $version queda como null debido a que no hay un parámetro version en la URL.
  • http://hostname/index.php?r=post/view&id=123&version=2: los parámetros $id y $version serán llenados con '123' y '2', respectivamente.
  • http://hostname/index.php?r=post/view: se lanzará una excepción yii\web\BadRequestHttpException dado que el parámetro $id es requerido pero no es provisto en el request.
  • http://hostname/index.php?r=post/view&id[]=123: una excepción yii\web\BadRequestHttpException será lanzada porque el parámetro $id está recibiendo un valor inesperado, el array ['123'].

Si quieres que un parámetro de acción acepte un array como valor, deberías utilizar el type-hinting (especificación de tipo) array, como a continuación:

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

Ahora si el request es http://hostname/index.php?r=post/view&id[]=123, el parámetro $id tomará el valor de ['123']. Si el request es http://hostname/index.php?r=post/view&id=123, el parámetro $id recibirá aún el mismo array como valor ya que el valor escalar '123' será convertido automáticamente en array.

Los ejemplos de arriba muestran principalmente como funcionan los parámetros de acción de una aplicación Web. Para aplicaciones de consola, por favor consulta la sección Comandos de Consola para más detalles.

Acción por Defecto

Cada controlador tiene una acción por defecto especificada a través de la propiedad yii\base\Controller::$defaultAction. Cuando una ruta contiene sólo el ID del controlador, implica que se está solicitando la acción por defecto del controlador especificado.

Por defecto, la acción por defecto (valga la redundancia) definida es index. Si quieres cambiar dicho valor, simplemente sobrescribe esta propiedad en la clase del controlador, como se muestra a continuación:

namespace app\controllers;

use yii\web\Controller;

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

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

Ciclo de Vida del Controlador

Cuando se procesa un request, la aplicación creará un controlador basado en la ruta solicitada. El controlador entonces irá a través del siguiente ciclo de vida para completar el request:

  1. El método yii\base\Controller::init() es llamado después de que el controlador es creado y configurado.
  2. El controlador crea un objecto action basado en el ID de acción solicitado:
  3. El controlador llama secuencialmente al método beforeAction() de la aplicación, al del módulo (si el controlador pertenece a uno) y al del controlador.
    • Si alguna de las llamadas devuelve false, el resto de los llamados subsiguientes a beforeAction() serán saltados y la ejecución de la acción será cancelada.
    • Por defecto, cada llamada al método beforeAction() lanzará un evento beforeAction al cual le puedes conectar un manejador.
  4. El controlador ejecuta la acción:
    • Los parámetros de la acción serán analizados y poblados con los datos del request;
  5. El controlador llama secuencialmente al método afterAction() del controlador, del módulo (si el controlador pertenece a uno) y de la aplicación.
    • Por defecto, cada llamada al método afterAction() lanzará un evento afterAction al cual le puedes conectar un manejador.
  6. La aplicación tomará el resultado de la acción y lo asignará al response.

Buenas Prácticas

En una aplicación bien diseñada, los controladores son a menudo muy pequeños con cada acción conteniendo unas pocas líneas de código. Si tu controlador se torna muy complejo, es usualmente un indicador de que deberías realizar una refactorización y mover algo de código a otras clases.

En resumen, los controladores

  • pueden acceder a los datos del request;
  • puede llamar a métodos del modelo y otros componentes con data del request;
  • pueden utilizar vistas para componer responses;
  • NO debe procesar datos del `request - esto debe ser realizado en los modelos;
  • deberían evitar insertar HTML o cualquier código de presentación - para esto están las vistas.

Found a typo or you think this page needs improvement?
Edit it on github !