A free and open-source book on ZF3 for beginners

Translation into this language is not yet finished. You can help this project by translating the chapters and contributing your changes.

4.9. Registro de los Controladores

Todas las clases controladoras que pertenecen a un módulo deben ser registradas en el archivo de configuración module.config.php. Si nuestra clase controladora no necesita usar servicios (no tiene dependencias) podemos registrarla de la siguiente manera:

<?php
use Zend\ServiceManager\Factory\InvokableFactory;

return [
    // ...

    'controllers' => [
        'factories' => [
            Controller\IndexController::class => InvokableFactory::class
            // Put other controllers registration here
        ],
    ],

    // ...
];

En la línea 7 tenemos la llave controllers que contiene la subllave factories. Para registrar una clase controladora agregamos una línea que tenga la forma de un par: llave => valor. La llave será el nombre completo (fully qualified name) de la clase controladora, como \Application\Controller\IndexController (usamos la palabra clave de PHP ::class para la resolución de nombre de clase), y el valor será el nombre de una clase fábrica que creará la clase controladora que necesitamos usar. En nuestro caso usamos la InvokableFactory estándar pero podemos crear una propia si es necesario.

Al usar la InvokableFactory decimos a Zend Framework que puede invocar el controlador instanciandolo con el operador new. Esta es la manera más simple de instaciar el controlador. Como una alternativa, podemos registrar nuestra propia fábrica para crear la instancia del controlador e inyectar las dependencias dentro del él.

4.9.1. Registrar una Fábrica para el Controlador

Si nuestra clase controladora necesita llamar a algún servicio (lo que sucede muy a menudo), necesitamos pedirlo al administrador de servicios (discutimos sobre el administrador de servicios en el capítulo Website Operation) y luego pasarlo al constructor del controlador para que el controlador guarde el servicio que pasamos en una propiedad privada para su uso interno (a esto se llama inyección de dependencia).

Este procedimiento se implementa típicamente dentro de la clase fábrica. Por ejemplo, asumiendo que nuestra clase controladora necesita usar el servicio CurrencyConverter que convierte dinero de USD a EUR. La clase fábrica de nuestro controlador tendrá el siguiente aspecto:

<?php
namespace Application\Controller\Factory;

use Zend\ServiceManager\Factory\FactoryInterface;
use Application\Service\CurrencyConverter;
use Application\Controller\IndexController;

// Factory class
class IndexControllerFactory implements FactoryInterface
{
    public function __invoke(ContainerInterface $container,
                     $requestedName, array $options = null)
    {
        // Get the instance of CurrencyConverter service from the service manager.
        $currencyConverter = $container->get(CurrencyConverter::class);

        // Create an instance of the controller and pass the dependency
        // to controller's constructor.
        return new IndexController($currencyConverter);
    }
}

Luego registramos el controlador de la misma manera que antes pero especificando la clase fábrica que hemos escrito antes:

<?php
return [
    // ...

    'controllers' => [
        'factories' => [
            Controller\IndexController::class => Controller\Factory\IndexControllerFactory::class
        ],
    ],

    // ...
];

Si tenemos alguna experiencia con Zend Framework 2 podemos notar que las cosas ahora son un poco diferentes que antes. En ZF2 había un método getServiceLocator() en la clase base AbstractActionController que permitía traer las dependencias al controlador incluso sin la clase fábrica. En ZF3 tenemos que pasar las dependencias explícitamente. Esto es un poco más aburrido pero elimina las dependencias "ocultas" y hace a nuestro código más claro y fácil de entender.

4.9.2. LazyControllerAbstractFactory

Escribir una fábrica para cada controlador puede parecer aburrido en un primer momento. Si somos muy flojos para querer hacerlo podemos usar la clase fábrica por defecto LazyControllerAbstractFactory.

La fábrica LazyControllerAbstractFactory usa reflexión para determinar que servicios necesita usar nuestro controlador. Solo necesitamos obligar las dependencias (typehint) colocando los servicios como argumentos del constructor del controlador y la fábrica recuperará por si misma los servicios necesarios y los pasará al constructor.

Por ejemplo, para inyectar el servicio CurrencyConverter en nuestro controlador nos aseguramos de que el constructor se vea de esta manera:

namespace Application\Controller;

use Application\Service\CurrencyConverter;

class IndexController extends AbstractActionController
{
    // Here we will save the service for internal use.
    private $currencyConverter;

    // Typehint the arguments of constructor to get the dependencies.
    public function __construct(CurrencyConverter $currencyConverter)
    {
        $this->currencyConverter = $currencyConverter;
    }
}

Luego registramos el controlador de la misma manera pero especificando la fábrica LazyControllerAbstractFactory:

<?php
use Zend\Mvc\Controller\LazyControllerAbstractFactory;

return [
    // ...

    'controllers' => [
        'factories' => [
            Controller\IndexController::class => LazyControllerAbstractFactory::class
        ],
    ],

    // ...
];

Top