Controladores

Uso de Controladores

Las acciones son métodos en un controlador que manejan las solicitudes. Por defecto todos los métodos públicos en un controlador son acciones y son accesibles por una URL. Las acciones son responsables de interpretar la consulta y crear una respuesta. Las respuestas son generalmente en forma de una vista renderizada, pero también hay otras formas de crear respuestas.

Por ejemplo, cuando usted accede a una URL como esta: http://localhost/blog/posts/show/2015/the-post-title Phalcon, por defecto, descompondrá cada parte de la siguiente manera:

Descripción Slug
Phalcon Directory blog
Controller posts
Action show
Parameter 2015
Parameter the-post-title

En este caso, el controlador PostsController se encargará de esta solicitud. Hay no hay un lugar especial para poner los controladores en una aplicación, ellos son cargados con Phalcon\Loader, así que eres libre de organizar los controladores como desees.

Los controladores deben tener el sufijo Controller y las acciones deben tener el sufijo Action. A continuación un ejemplo de un controlador:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function showAction($year, $postTitle)
    {

    }
}

Los parámetros adicionales del URI se definen como parámetros de acción, por lo que se puede acceder fácilmente usando variables locales. Un controlador puede, opcionalmente, extender de Phalcon\Mvc\Controller. Haciendo esto, el controlador puede tener fácil acceso a los servicios de la aplicación.

Los parámetros sin un valor predeterminado son manejados como obligatorios. Establecer parámetros con valores opcionales, se realiza como de costumbre en PHP:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function showAction($year = 2015, $postTitle = 'some default title')
    {

    }
}

Los parámetros son asignados en el mismo orden al que son pasados en la ruta. Puede obtener cualquier parámetro, desde su nombre, de la siguiente manera:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function showAction()
    {
        $year      = $this->dispatcher->getParam('year');
        $postTitle = $this->dispatcher->getParam('postTitle');
    }
}

Bucle de Despacho

El bucle de despacho se ejecutará dentro del Dispatcher hasta que no haya ninguna acción para ser ejecutada. En el ejemplo anterior se ha ejecutado sólo una acción. Ahora vamos a ver cómo el método forward() puede proporcionar un flujo más complejo de la operación en el bucle de despacho, enviando la ejecución a un controlador y acción diferente.

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function showAction($year, $postTitle)
    {
        $this->flash->error(
            "Ud. no tiene permisos para acceder a esta área"
        );

        // Cambiamos el flujo a otra acción
        $this->dispatcher->forward(
            [
                'controller' => 'users',
                'action'     => 'signin',
            ]
        );
    }
}

Si los usuarios no tienen permiso para acceder a una determinada acción entonces ellos se remitirán a la acción signin en el controlador UsersController.

<?php

use Phalcon\Mvc\Controller;

class UsersController extends Controller
{
    public function indexAction()
    {

    }

    public function signinAction()
    {

    }
}

No hay un límite de forwards que pueda tener en su aplicación, siempre y cuando no den lugar a referencias circulares, en tal caso se detendrá la aplicación. Si hay no hay otras acciones para ser despachadas por el bucle de despacho, el dispatcher llamará automáticamente a la capa vista del MVC que es administrada por Phalcon\Mvc\View.

Inicialización de Controladores

Phalcon\Mvc\Controller ofrece el método initialize(), que se ejecuta en primer lugar, antes de cualquier acción que se ejecute en un controlador. No se recomienda el uso del método __construct().

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public $settings;

    public function initialize()
    {
        $this->settings = [
            'mySetting' => 'value',
        ];
    }

    public function saveAction()
    {
        if ($this->settings['mySetting'] === 'value') {
            // ...
        }
    }
}

Si desea ejecutar cierta lógica de inicialización justo después de que se construye el objeto controlador puede implementar el método onConstruct():

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function onConstruct()
    {
        // ...
    }
}

Inyección de servicios

Si un controlador extiende de Phalcon\Mvc\Controller, será muy fácil acceder al contenedor de servicios en la aplicación. Por ejemplo, si tenemos registrado un servicio como este:

<?php

use Phalcon\Di;

$di = new Di();

$di->set(
    'storage',
    function () {
        return new Storage(
            '/some/directory'
        );
    },
    true
);

Entonces, podemos acceder a ese servicio de diferentes maneras:

<?php

use Phalcon\Mvc\Controller;

class FilesController extends Controller
{
    public function saveAction()
    {
        // Inyección de servicios, simplemente accedemos por la propiedad con el mismo nombre
        $this->storage->save('/some/file');

        // Acceso al servicio desde el DI
        $this->di->get('storage')->save('/some/file');

        // Otra forma de acceder al servicio es utilizando los métodos mágicos
        $this->di->getStorage()->save('/some/file');

        // Otra forma válida de utilizar los métodos mágicos
        $this->getDi()->getStorage()->save('/some/file');

        // Utilizando la sintaxis de array
        $this->di['storage']->save('/some/file');
    }
}

Si usas Phalcon como un framwork full-stack, puedes leer los servicios proporcionados por defecto en el framework.

Request y Response

Suponiendo que el framework proporciona un conjunto de servicios previamente registrados. Explicaremos cómo interactuar con el entorno HTTP. El servicio request contiene una instancia de Phalcon\Http\Request y response contiene Phalcon\Http\Response que representa lo que va a ser enviado al cliente.

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function saveAction()
    {
        // Chequeamos si la consulta fue hecha por POST
        if ($this->request->isPost()) {
            // Accedemos al los datos POST
            $customerName = $this->request->getPost('name');
            $customerBorn = $this->request->getPost('born');
        }
    }
}

El objeto response, generalmente, no se utiliza directamente, pero se construye antes de la ejecución de la acción, a veces (como en un evento afterDispatch) puede ser útil para acceder directamente a la respuesta:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function indexAction()
    {

    }

    public function notFoundAction()
    {
        // Enviar la cabecera de respuesta HTTP 404
        $this->response->setStatusCode(404, 'Not Found');
    }
}

Más información sobre el entorno de HTTP en los artículos dedicados para request y response.

Datos de Sesión

Las sesiones nos ayudan a mantener la persistencia de datos entre consultas. Puedes acceder al Phalcon\Session\Bag desde cualquier controlador para encapsular los datos que deben ser persistentes:

<?php

use Phalcon\Mvc\Controller;

class UserController extends Controller
{
    public function indexAction()
    {
        $this->persistent->name = 'Michael';
    }

    public function welcomeAction()
    {
        echo 'Welcome, ', $this->persistent->name;
    }
}

Utilizando Servicios como Controladores

Los servicios pueden actuar como controladores, las clases controladoras siempre son requeridas desde el contenedor de servicios. En consecuencia, cualquier otra clase registrada con su nombre, puede reemplazar fácilmente un controlador:

<?php

// Registrar un controlador como servicio
$di->set(
    'IndexController',
    function () {
        $component = new Component();

        return $component;
    }
);

// Registrar un controlador con su namespace como servicio
$di->set(
    'Backend\Controllers\IndexController',
    function () {
        $component = new Component();

        return $component;
    }
);

Eventos en Controladores

Los controladores automáticamente actúan como detectores de eventos del dispatcher, implementando métodos con los nombres de evento adecuados, permiten implementar puntos de anclaje para antes/después de ejecutar las acciones:

<?php

use Phalcon\Mvc\Controller;

class PostsController extends Controller
{
    public function beforeExecuteRoute($dispatcher)
    {
        // Este método se ejecuta antes de cada acción
        if ($dispatcher->getActionName() === 'save') {
            $this->flash->error(
                "Ud. no tiene permisos para guardar publicaciones"
            );

            $this->dispatcher->forward(
                [
                    'controller' => 'home',
                    'action'     => 'index',
                ]
            );

            return false;
        }
    }

    public function afterExecuteRoute($dispatcher)
    {
        // Ejecutado después de cada acción
    }
}