Secciones

Aplicación


Resumen

Phalcon\Mvc\Application es un componente que encapsula todas las operaciones complejas tras instanciar cada componente necesario para ejecutar una aplicación MVC. Esta es una aplicación de pila completa (full stack) integrada con todos los servicios adicionales necesarios para permitir que el patrón MVC funcione como se desee.

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Application;

$container   = new FactoryDefault();
$application = new Application($container);

try {
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );

    $response->send();
} catch (\Exception $e) {
    echo $e->getMessage();
}

Métodos

public function __construct(
    DiInterface $container = null
)

Constructor. Acepta un contenedor DI con los servicios relevantes

public function getDefaultModule(): string

Devuelve el nombre de módulo por defecto

public function getEventsManager(): ManagerInterface

Devuelve el administrador de eventos interno

public function getModule(
    string $name
): array | object

Obtiene la definición de módulo registrada en la aplicación a través del nombre del módulo

public function getModules(): array

Devuelve los módulos registrados en la aplicación

public function registerModules(
    array $modules, 
    bool $merge = false
): AbstractApplication

Registra un vector de módulos presente en la aplicación

$this->registerModules(
    [
        "front" => [
            "className" => \Multi\Front\Module::class,
            "path"      => "../apps/front/Module.php",
        ],
        "back" => [
            "className" => \Multi\Back\Module::class,
            "path"      => "../apps/back/Module.php",
        ],
    ]
);
public function setDefaultModule(
    string $defaultModule
): AbstractApplication

Establece el nombre del módulo que se utilizará si el router no devuelve un módulo válido

public function setEventsManager(
    ManagerInterface $eventsManager
): void

Establece el administrador de eventos

public function handle(
    string $uri
): ResponseInterface | bool

Gestiona una petición MVC. Acepta la URL del servidor (normalmente $_SERVER['REQUEST_URI]`)

public function sendCookiesOnHandleRequest(
    bool $sendCookies
): Application

Habilita o deshabilita el envío de cookies para cada gestión de solicitud

public function sendHeadersOnHandleRequest(
    bool $sendHeaders
): Application

Habilita o deshabilita el envío de cabeceras para cada gestión de solicitud

public function useImplicitView(
    bool $implicitView
): Application

Está habilitado por defecto. La vista está almacenando implícitamente en buffer toda la salida. Puede deshabilitar completamente el componente vista usando este método

Activación

Phalcon\Mvc\Application realiza todo el trabajo necesario para unir todos los componentes necesarios para que se pueda ejecutar la aplicación. Hay varias maneras de arrancar su aplicación. La manera más común para arrancar la aplicación es:

<?php

use Phalcon\Di\FactoryDefault();
use Phalcon\Mvc\Application;

$container = new FactoryDefault();

// Services
// ...

$application = new Application($container);

try {
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );

    $response->send();
} catch (\Exception $e) {
    echo 'Exception: ', $e->getMessage();
}

El núcleo de todo el trabajo del controlador ocurre cuando se invoca handle():

<?php

$response = $application->handle(
    $_SERVER["REQUEST_URI"]
);

Arranque manual

Si no desea usar Phalcon\Mvc\Application, el código anterior se puede modificar de la siguiente manera:

<?php

use Phalcon\Di\FactoryDefault();
use Phalcon\Mvc\Application;

$container = new FactoryDefault();

$router = $container['router'];

$router->handle(
    $_SERVER["REQUEST_URI"]
);

$view = $container['view'];

$dispatcher = $container['dispatcher'];

$dispatcher->setControllerName(
    $router->getControllerName()
);

$dispatcher->setActionName(
    $router->getActionName()
);

$dispatcher->setParams(
    $router->getParams()
);

// View
$view->start();

// Dispatcher
$dispatcher->dispatch();

// View 
$view->render(
    $dispatcher->getControllerName(),
    $dispatcher->getActionName(),
    $dispatcher->getParams()
);

// View
$view->finish();

$response = $container['response'];

$response->setContent(
    $view->getContent()
);

$response->send();

El siguiente reemplazo de Phalcon\Mvc\Application no tiene la vista, haciéndola apropiada para aplicaciones API REST:

<?php

use Phalcon\Di\FactoryDefault();
use Phalcon\Http\ResponseInterface;
use Phalcon\Mvc\Application;

$container = new FactoryDefault();

$router = $container['router'];

$router->handle(
    $_SERVER["REQUEST_URI"]
);

$dispatcher = $container['dispatcher'];

$dispatcher->setControllerName(
    $router->getControllerName()
);

$dispatcher->setActionName(
    $router->getActionName()
);

$dispatcher->setParams(
    $router->getParams()
);

$dispatcher->dispatch();

$response = $dispatcher->getReturnedValue();

if ($response instanceof ResponseInterface) {
    $response->send();
}

Otra forma de capturar las excepciones generadas en la redirección a otras acciones en el despachador es la siguiente:

<?php

use Phalcon\Di\FactoryDefault();
use Phalcon\Http\ResponseInterface;
use Phalcon\Mvc\Application;

$container = new FactoryDefault();

// Get the 'router' service
$router = $container['router'];

$router->handle(
    $_SERVER["REQUEST_URI"]
);

$dispatcher = $container['dispatcher'];

$dispatcher->setControllerName(
    $router->getControllerName()
);

$dispatcher->setActionName(
    $router->getActionName()
);

$dispatcher->setParams(
    $router->getParams()
);

try {
    $dispatcher->dispatch();
} catch (Exception $e) {
    // 503
    $dispatcher->setControllerName('errors');
    $dispatcher->setActionName('action503');

    $dispatcher->dispatch();
}

$response = $dispatcher->getReturnedValue();

if ($response instanceof ResponseInterface) {
    $response->send();
}

Dependiendo de las necesidades de su aplicación, podría querer tener el control total de lo que se debe instanciar o no, o sustituir ciertos componentes por los suyos propios para extender la funcionalidad predeterminada. El método de arranque que elija depende de las necesidades de su aplicación.

Único - Multi Módulo

Phalcon\Mvc\Application ofrece dos formas de estructuras MVC: Único y Multi módulo.

Módulo Único

Las aplicaciones MVC de módulo único consisten en un sólo módulo. El espacio de nombres se puede usar pero no es necesario. La estructura de dicha aplicación suele ser la siguiente:

single/
    app/
        controllers/
        models/
        views/
    public/
        css/
        img/
        js/

Si no se usa espacio de nombres, se podría usar el siguiente fichero de arranque:

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Loader;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\View;

$loader = new Loader();
$loader->registerDirs(
    [
        '../apps/controllers/',
        '../apps/models/',
    ]
);

$loader->register();

$container = new FactoryDefault();

$container->set(
    'view',
    function () {
        $view = new View();
        $view->setViewsDir(
            '../apps/views/'
        );

        return $view;
    }
);

$application = new Application($container);

try {
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );

    $response->send();
} catch (\Exception $e) {
    echo $e->getMessage();
}

Si se usa espacio de nombres, el arranque cambia claramente:

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Loader;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\View;

$loader = new Loader();
$loader->registerNamespaces(
    [
        'Single\Controllers' => '../apps/controllers/',
        'Single\Models'      => '../apps/models/',
    ]
);

$loader->register();

$container = new FactoryDefault();

$container->set(
    'dispatcher',
    function () {
        $dispatcher = new Dispatcher();
        $dispatcher->setDefaultNamespace(
            'Single\Controllers'
        );

        return $dispatcher;
    }
);

$container->set(
    'view',
    function () {
        $view = new View();
        $view->setViewsDir(
            '../apps/views/'
        );

        return $view;
    }
);

$application = new Application($container);

try {
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );

    $response->send();
} catch (\Exception $e) {
    echo $e->getMessage();
}

Multi Módulo

Una aplicación multi-módulo usa la misma raíz de documentos (document root) para más de un módulo. Los módulos son grupos de componentes/ficheros que ofrecen funcionalidad pero incrementan el mantenimiento y aíslan la funcionalidad si es necesario. Cada módulo debe implementar Phalcon\Mvc\ModuleDefinitionInterface, para asegurar una correcta funcionalidad. Una estructura de directorio de ejemplo puede verse a continuación:

multiple/
  apps/
    front/
       controllers/
       models/
       views/
       Module.php
    back/
       controllers/
       models/
       views/
       Module.php
  public/
    css/
    img/
    js/

Cada subdirectorio en el directorio apps/ tiene su propia estructura MVC. Existe un fichero Module.php en cada directorio de módulo, para configurar ajustes específicos de cada módulo, como autocargadores, servicios personalizados, etc.

<?php

namespace Multi\Back;

use Phalcon\Loader;
use Phalcon\Di\DiInterface;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Mvc\ModuleDefinitionInterface;
use Phalcon\Mvc\View;

class Module implements ModuleDefinitionInterface
{
    public function registerAutoloaders(
        DiInterface $container = null
    )
    {
        $loader = new Loader();
        $loader->registerNamespaces(
            [
                'Multi\Back\Controllers' => '../apps/back/controllers/',
                'Multi\Back\Models'      => '../apps/back/models/',
            ]
        );

        $loader->register();
    }

    public function registerServices(DiInterface $container)
    {
        // Registering a dispatcher
        $container->set(
            'dispatcher',
            function () {
                $dispatcher = new Dispatcher();
                $dispatcher->setDefaultNamespace(
                    'Multi\Back\Controllers'
                );

                return $dispatcher;
            }
        );

        // Registering the view component
        $container->set(
            'view',
            function () {
                $view = new View();
                $view->setViewsDir(
                    '../apps/back/views/'
                );

                return $view;
            }
        );
    }
}

Se requiere un archivo de arranque ligeramente modificado para una arquitectura MVC multimódulo

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\Router;

$container = new FactoryDefault();

$container->set(
    'router',
    function () {
        $router = new Router();

        $router->setDefaultModule('front');

        $router->add(
            '/login',
            [
                'module'     => 'back',
                'controller' => 'login',
                'action'     => 'index',
            ]
        );

        $router->add(
            '/admin/products/:action',
            [
                'module'     => 'back',
                'controller' => 'products',
                'action'     => 1,
            ]
        );

        $router->add(
            '/products/:action',
            [
                'controller' => 'products',
                'action'     => 1,
            ]
        );

        return $router;
    }
);

$application = new Application($container);

$application->registerModules(
    [
        'front' => [
            'className' => \Multi\Front\Module::class,
            'path'      => '../apps/front/Module.php',
        ],
        'back'  => [
            'className' => \Multi\Back\Module::class,
            'path'      => '../apps/back/Module.php',
        ]
    ]
);

try {
    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );

    $response->send();
} catch (\Exception $e) {
    echo $e->getMessage();
}

Si quiere mantener la configuración del módulo en su fichero de arranque, puede usar una función anónima para registrar el módulo.

<?php

use Phalcon\Mvc\View;

$view = new View();

// ...

$application->registerModules(
    [
        'front' => function ($container) use ($view) {
            $container->setShared(
                'view',
                function () use ($view) {
                    $view->setViewsDir(
                        '../apps/front/views/'
                    );

                    return $view;
                }
            );
        },
        'back' => function ($container) use ($view) {
            $container->setShared(
                'view',
                function () use ($view) {
                    $view->setViewsDir(
                        '../apps/back/views/'
                    );

                    return $view;
                }
            );
        }
    ]
);

Cuando Phalcon\Mvc\Application tiene módulos registrados, es esencial que cada ruta coincidente devuelva un módulo válido. Cada módulo registrado tiene una clase asociada que expone métodos para la configuración del módulo.

Las clases de definición de módulo deben implementar dos métodos: - registerAutoloaders() y - registerServices()

En consecuencia, se llamarán desde Phalcon\Mvc\Application.

Excepciones

Cualquier excepción lanzada en el componente Phalcon\Mvc\Application será del tipo Phalcon\Mvc\Application\Exception o Phalcon\Application\Exception. Puede usar esta excepción para capturar selectivamente sólo las excepciones lanzadas por este componente.

<?php

use Phalcon\Di\FactoryDefault;
use Phalcon\Mvc\Application;
use Phalcon\Mvc\Application\Exception;

try {
    $container   = new FactoryDefault();

    // ...

    $application = new Application($container);
    $application->registerModules(
        [
            'front' => false,
        ]
    );

    $response = $application->handle(
        $_SERVER["REQUEST_URI"]
    );

    $response->send();
} catch (Exception $e) {
    echo $e->getMessage();
}

Eventos

Phalcon\Mvc\Application es capaz de enviar eventos al EventsManager (si existe). Los eventos son disparados usando el tipo application. Se soportan los siguientes eventos:

Nombre de Evento Disparado
boot Cuando la aplicación gestiona su primer solicitud
beforeStartModule Antes de inicializar un módulo, sólo cuando los módulos están registrados
afterStartModule Después de inicializar un módulo, sólo cuando los módulos están registrados
beforeHandleRequest Antes de ejecutar el bucle de despacho
afterHandleRequest Después de ejecutar el bucle de despacho

En el ejemplo siguiente se muestra cómo adjuntar oyentes (listeners) a este componente:

<?php

use Phalcon\Events\Event;
use Phalcon\Events\Manager;

$manager = new Manager();

$application->setEventsManager($manager);

$manager->attach(
    'application',
    function (Event $event, $application) {
        // ...
    }
);

Recursos externos