Lo básico sobre controladores

A nivel básico, los Controladores son el código que se ejecuta al visitar una página en XF. Los Controladores son responsables, generalmente, del manejo de las entradas del usuario y de pasarlas al lugar apropiado que, en general, sería para realizar algún tipo de ordenación de acciones de la base de datos (Model) o cargar el contenido visual (View).

Cuando un usuario hace clic en algún vínculo, la URL solicitada es enrutada a un controlador y acción específicos. Vésase Lo básico sobre rutas. Por ejemplo, en XF si se hace clic en una URL como index.php?conversations/add se enrutará al controlador XF\Pub\Controller\Conversation y a la acción add.

Si se mira esta clase en el sistema de archivos (véase Autoinicio para mejor definición de cómo las clases y rutas de archivo representan a cada una de las demás) se advertirá que existe un número de métodos denominados con un prefijo de acción action. Cada uno de estos métodos indica una acción específica del controlador. Por ello, para ver el código envuelto al visionar la página conversations/add mencionada arriba, mira en este archivo la función public function actionAdd().

Los controladores de XF son responsables de devolver un objeto respuesta que, generalmente, consiste en uno de los siguientes tipos:

Respuesta View

Esta es una de las respuestas más comunes con la que se que tratará durante el desarrollo de XF. Un controlador que devuelve una respuesta View requerirá, usualmente, que se le pasen hasta tres argumentos. Una clase View (más sobre esto, abajo), un nombre de plantilla y una matríz $viewParams que son los datos que deben de estar disponibles para la plantilla.

Éste es el ejemplo típico de una acción de controlador que devuelve una respuesta View:


public function actionExample()
{
    $hello = 'Hola';
    $world = 'Mundo';
    $viewParams = [
        'hello' => $hello,
        'world' => $world
    ];
    return $this->view(
        'Demo:Example', 
        'demo_example', 
        $viewParams
    );
}

                

El primer argumento es un nombre corto de clase para una clase View específica. Esta clase puede o no existir (a menudo no necesitará existir, cubriremos las clases View más adelante) y que debe tener un nombre casi único de controlador y de acción. como los demás nombres cortos de clase, el nombre corto de clase de arriba se resolverá a Demo\Pub\View\Example. De nuevo, Pub se deduce automáticamente del tipo de controlador.

El segundo argumento es el nombre de plantilla. En este caso, miraremos en una plantilla denominada demo_example.

El tercer argumento es una matríz de parámetros/variables de plantilla que deben estar disponibles para View. Esta matríz, consiste genralmente en pares de clave => valor. En el ejemplo de arriba se pasan dos parámetros de plantilla a la plantilla. La parte clave como parte de una matríz indica el nombre de la variable disponible en la plantilla. La parte valorcomo parte de una matríz indica el valor.

por ello, si se tiene el siguiente contenido en la plantilla demo_example:

¡{$hello} {$world}! 
                

La plantilla devolvería lo siguiente:

¡Hola Mundo! 
                

Respuesta de Redirección

Se devuelve esta respuesta cuando se quiere redireccionar a un usuario a una URL diferente tras haber completado alguna clase de acción.

Un caso de uso común aquí es cuando se desea redireccionar al usuario a una página diferente tras remitir los datos mediante un formulario y por ejemplo, devolverlo a una lista de elementos.

Éste es un ejemplo de una típica acción de controlador que realiza una redirección:


public function actionRedirect()
{
    return $this->redirect(
        $this->buildLink('demo/example'),
        'Esto es un mensaje de redirección.',
        'permanent'
    );
}

                

El primer argumento es la URL a la que se redirecciona. Este ejemplo redireccionará al usuario a la URL index.php?demo/example.

El segundo argumento sólo mostrará si el formulario se remite sobre una solicitud AJAX que opta por evitar la redirección. El resultado será un "mensaje flash" que aparece desde arriba de la pantalla con el mensaje elegido. No hay que envíar un mensaje propio. Si no se ha provisto por defecto será un mensaje "Se han guardado los cambios".

El tercer argumento predeterminado es temporary, pero se ha elegido configurar esto a permanente en este ejemplo. La única diferencia aquí es el tipo de código de respuesta HTTP provisto por el servidor. Temporal es ideal la mayoría de veces y responderá con un código 303. permanent dará un código 301 de respuesta.

A pesar de poder lanzarse una redirección permanente por esta vía, existe actualmente un método específico para esto, que puede usarse como sigue. También toma una argumento 'mensaje', pero es opcional, tal y como arriba.


public function actionRedirect()
{
    return $this->redirectPermanently($this->buildLink('demo/example'));
}

                

Respuesta de Error

Como sugiere el nombre, esta es la respuesta que se devolverá si se precisa mostrar un error al usuario. Es algo sencillo, he aquí un ejemplo:


public  function actionError()
{
return $this->error(
    'Por desgracia, la cosa que andas buscando no la encontramos.',
    404);
}

                

Aquí solo existen dos argumentos soportados. El primero es el mensaje de error que se quiere mostrar y el segundo es el código de respuesta HTTP que se desea envíe el servidor. 404 representa una respuesta adecuada para algo que no se encuentra.

Respuesta de Mensaje

Esta respuesta es muy similar a la respuesta de error y soporta los mismos argumentos. La principal diferencia es en términos de aspecto,el mensaje que se muestra no lo hace como un error.

Respuesta de Excepción

A veces es necesario interrumpir el fujo normal de un código de controlador y responder con una excepción en su lugar. Las respuestas de Excepción no tienen que representar un error necesariamente; Por ejemplo, pueden usarse para para forzar al controlador a realizar una redirección. Sin embargo, típicamente, a menudo se usan para detener el flujo del controlador y mostrar un error, como en el ejemplo siguiente:


publicfunction actionException()
{
    throw $this->exception(
        $this->error('Ha ocurrido un error inesperado')
    );
}

                

Las respuestas de excepción solo aceptan un único argumento y, en realidad, ese argumento debe ser alguna otra forma de objeto de respuesta, como una Respuesta de Error. Este particular ejemplo lanza una excepción y el código del controlador se detiene por completo en este punto, mostrándose un error estandar.

Advertir que las respuestas de Excepción deben "lanzarse" usando throw en vez de devolverse con return.

Respuesta de Re-ruta

Bajo ciertas condiciones, si es necesario reenrutar un usuario a un controlador o acción completamente diferente, sin realizar una redirección completa, sin cambiar la URL que ha hecho el usuario y sin tener que duplicar el código de la acción de destino.

public function actionReroute()
{
    return $this->rerouteController(__CLASS__, 'error');
}

public function actionError()
{
    return $this->error('Oops! ¡Algo va mal!');
}

                

En este ejemplo en particular, si un usuario ha navegado a la URL index.php?demo/reroute, podrá ver la respuesta de Error desde el método actionError(). No se redireccionarán ni habrá cambios en la URL que figura en su navegadore; simplemente recibirán la respuesta desde la acción del error.

La respuesta de reruta también soporta un tercer argumento que permite transmitir varios parámetros desde una acción de controlador a otra. Esto suele ser una matríz o un objeto ParameterBag (más, más tarde).

Modificar la respuesta de acción de un controlador (correctamente)

En la sección Extender clases, ya hemos visto cuán simple es extender una clase, aunque hay que tener un cuidado extra al extender una acción de un controlador que ya existe.

A menos que se tenga que sobreescribir enteramente una acción existente por necesidad específica y se reemplace con algo nuevo (generalmente no recomendado), lo que debiera hacerse en su lugar es modificar la respuesta existente de la clase padre. Esto se hace simplemente como ejemplo, y vamos a modificar la respuesta de Vista de la Respuesta de View del ejemplo anterior.


public function actionExample()
{
    $reply = parent::actionExample();
    return $reply;
}

                

Suponiendo que lo anterior se añada a un controlador extendido cuando el método actionExample() ya existe, lo anterior no hace nada más que devolver la respuesta de View original. Ahora cambiemos el parámetro existente hello para que lea "Bonjour" en vez de "Hola".


public function actionExample()
{
    $reply = parent::actionExample();
    if($reply instanceof \XF\Mvc\Reply\View)
    {
        $reply->setParam('hello', 'Bonjour');
    }

    return $reply;
}

                

Ya que una respuesta de controlador puede representar a diferentes objetos con diferentes comportamientos y métodos, es imperativo el intentar extender solo el tipo de respuesta correcto. Lo hacemos en el ejemplo anterior de la Respuesta de View comprobando si el objeto $reply padre es actualmente del tipo View. Si lo es, se extiende esta acción y la respuesta de acción del controlador configurando la variable (parámetro de plantilla) hello a Bonjour en su lugar, por lo que es probable que no haya un error.

Al visitar esta página antes de extender esta acción, se mostraría "¡Hola Mundo!". Tras extenderla, la vista mostrará ahora "¡Bonjour Mundo!".