Reducido n煤cleo de trabajo para PHP


Keywords
framework, microframework, php, rest, mvc, dms, hmvc, core, tornado, danielspk
License
MIT

Documentation

TORNADO

Build Status Latest Stable Version Total Downloads License

ScreenShot

TORNADO es un reducido marco de trabajo para PHP que permite implementar el patr贸n HMVC y/o servicios RESTfull

Puede obtener m谩s informaci贸n en su web http://tornado-php.com

Filosofia:

TORNADO no intenta ser un framework PHP full-stack. Contrariamente intenta ser
un n煤cleo de trabajo muy reducido para implementar patrones de arquitectura HMVC y/o servicios REST, con la menor parametrizaci贸n y utilizaci贸n de c贸digo posible, apoyado en un core que organice su proyecto junto a un sistema de configuraci贸n y gesti贸n de errores simple.

TORNADO no incluye librer铆as de soporte para tareas comunes como acceso a base de datos, gesti贸n de plantillas, env铆o de mais, etc. Utilice Composer para incluir paquetes de terceros de acuerdo a las necesidades particulares del proyecto a desarrollar.

Inspiraci贸n:

TORNADO se inspiro en varios microframeworks PHP, entre ellos cabe mencionar:

Metas:

TORNADO se desarrollo tratando de respetar las siguiente metas:

  • ser r谩pido
  • f谩cil de entender (tanto su API como su construcci贸n interna)
  • tener la menor cantidad de m茅todos posibles dentro de su API
  • permitir el uso de ganchos para extender el mismo
  • incluir librer铆as/paquetes de terceros con suma facilidad
  • tener la menor cantidad de l铆neas de c贸digo posible
  • ser un core de trabajo (NUNCA un framework)

Caracter铆sticas:

  • Enrutamientos para utilizar m贸dulos HMVC y/o servicios REST (apoyado en URL amigables)
  • Configuraci贸n general de la aplicaci贸n
  • Ganchos para extender las caracter铆sticas del core
  • Captura de errores y excepciones
  • Inyecci贸n de dependencias

Codificaci贸n:

TORNADO apoya la iniciativa del PHP Framework Interop Group e implementa los est谩ndares PSR-2 y PSR-4.

Puede obtener m谩s informaci贸n en聽http://www.php-fig.org/

Instalaci贸n:

La instalaci贸n recomendada requiere el uso de Composer.

{
    "require": {
        "danielspk/tornado" : "2.*"
    }
}
  • Inicie la consola de comando y ejecute el siguiente comando:
composer install

Manual de uso:

La versi贸n actual difiere totalmente de la versi贸n inicial 1.0.0

Si va a actualizar su aplicaci贸n lea en detalle el archivo de cambios CHANGELOG.md

Uso b谩sico:

Ejemplo de uso b谩sico (con dos tipos de enrutamientos)

<?php

    // incluir el autoload
    require 'vendor/autoload.php';
    
    // obtener una instancia del core
    $app = \DMS\Tornado\Tornado::getInstance();
    
    // enrutamiento a m贸dulo desde ra铆z
    $app->route('/', 'demo|demo|index');
    
    // enrutamiento a funci贸n an贸nima
    $app->route(array(
        '/saludar/:string'	=> function($pNombre = null){
            echo 'Hola ' . $pNombre;
        }
    ));

    // ejecutar la aplicaci贸n
    $app->run();
    

API:

Obtener Instancia del core:
    $app = \DMS\Tornado\Tornado::getInstance();
Ejecutar el core:
	// con una instancia del core en una variable
    $app = \DMS\Tornado\Tornado::getInstance();
    $app->run();

    // sin ninguna instancia anterior del core
    \DMS\Tornado\Tornado::getInstance()->run();
Setear configuraciones:
    $app = \DMS\Tornado\Tornado::getInstance();

    // configuraci贸n simple
    $app->config('nombre', 'valor del nombre');
    $app->config('nombres', array('nombre1'=>'valor1', 'nombre2'=>'valor2'));
    
    // configuraci贸n m煤ltiple
    $app->config([
        'clave1' => 'valor uno',
        'clave2' => 'valor dos'
    ]);
Leer configuraciones:
    $app = \DMS\Tornado\Tornado::getInstance();

    // configuraci贸n simple
    echo $app->config('nombre');

    // configuraci贸n array
    $nombres = $app->config('nombres');
    echo $nombres[0]['nombre1'];
    echo $nombres[1]['nombre2'];
Variables de configuraci贸n propias de Tornado:

Tornado permite configurar el ambiente de trabajo de la aplicaci贸n. De esta forma se puede cambiar el comportamiento interno del core:


    // configurar la aplicaci贸n para un ambiente de desarrollo
    // - errores visibles
    // - parse de anotaciones en m贸dulos HMVC para generar enrutamientos autom谩ticos
    $app->config('tornado_environment_development', true);

Otras configuraciones:


    // - indica si se van a utilizar m贸dulos hmvc
    $app->config('tornado_hmvc_use', true);

    // - ruta donde se alojar谩n los m贸dulos hmvc
    // (relativa a donde se inicia Tornado)
    $app->config('tornado_hmvc_module_path', true);
        
    // - ruta donde se serializaran las rutas de los m贸dulos hmvc
    // (relativa a donde se inicia Tornado)
    $app->config('tornado_hmvc_serialize_path', true);
        
Uso de Hooks:

Existen 6 tipos de hooks:

  • init: antes de parsear la url en busca de una ruta coincidente
  • before: antes de ejecutar la ruta coincidente
  • after: despues de ejecutar la ruta coincidente
  • end: al finalizar la ejecuci贸n de la petici贸n
  • 404: al no encontrarse una ruta coincidente con la url
  • error: al atraparse un error o excepci贸n en aplicaci贸n

    $app = \DMS\Tornado\Tornado::getInstance();

    // utilizando una clase / m茅todo / par谩metros
    $app->hook('error', array('ErrorUser', 'display', array()));

    // utilizando una funci贸n an贸nima
    $app->hook('404', function(){
        echo '404';
    });
    

Tambi茅n es posible crear ganchos personalizados. Ejemplo usando una clase de usuario:


    class Saludador
    {
        public function persona($nombre, $apellido)
        {
            echo 'Hola ' . $nombre . ', ' . $apellido;
        }
    }

    $app->hook('saludar', array('Saludador', 'persona', array('Tornado', 'PHP')));
    

La forma de ejecutar un gancho por c贸digo es la siguiente:


    $app = \DMS\Tornado\Tornado::getInstance();

    $app->hook('fueraDeLinea');
    

Pueden crearse n cantidad de hooks con un mismo nombre. Los mismos se ejecutar谩n secuencialmente en el orden en que fueron definidos. Puede, opcionalmente, alterar este orden indicando explicitamente el orden deseado:


    $app = \DMS\Tornado\Tornado::getInstance();

    $app->hook('before', function(){
        echo 'Declarado primero - ejecutado despues';
    }, 1);
    
    $app->hook('before', function(){
        echo 'Declarado despues - ejecutado primero';
    }, 0);
    

Si declara m谩s de un hook con el mismo nombre puede impedir que se ejecuten los hooks subsiguientes haciendo que el hook devuelva false en su ejecuci贸n.

A excepci贸n de los hook init puede consultar que ruta se va o se esta ejecutandose de la siguiente forma:


    $app = \DMS\Tornado\Tornado::getInstance();

    $app->hook('before', function() use ($app){
        $ruta = $app->getRouteMatch()
    });
    

Esto devolver谩 un array con la siguiente informaci贸n:

  • M茅todo de la petici贸n (GET, POST, etc)
  • Ruta
  • Callback
  • Par谩metros
Hooks y flujo de ejecuci贸n:

La secuencia de ejecuci贸n del core es la siguiente:

  • se ejecutan los hooks init
  • se parsea la url en busca de la ruta coincidente
    • si no hay coincidencias se ejecuta:
      • hooks 404
      • hooks end
      • se finaliza la ejecuci贸n
  • se ejecutan los hooks before
    • si alguno devuelve false se ejecuta:
      • hooks end
      • se finaliza la ejecuci贸n
  • se ejecuta la ruta coincidente
  • se ejecutan los hooks after
  • se ejecutan los hooks end
Definir Enrutamientos:

Los enrutamientos pueden ser:

  • (vacio) - cualquier tipo de petici贸n
  • GET - RESTfull por m茅todo GET
  • POST - RESTfull por m茅todo POST
  • PUT - RESTfull por m茅todo PUT
  • DELETE - RESTfull por m茅todo DELETE

En caso de que el servidor no soporte los m茅todos PUT y DELETE se pueden simular los mismos enviando una petici贸n POST con una variable "REST_METHOD" cuyo valor sea PUT o DELETE

Existen cuatro tipos de par谩metros para enrutar una URL:

  • :string - s贸lo acepta letras
  • :number - s贸lo acepta n煤meros
  • :alpha - acepta n煤meros y letras
  • :* - acepta cualquier cantidad y tipo de par谩metros (s贸lo puede incluirse uno solo y al final)

En caso de incluir par谩metros opcionales la sintaxis es la siguiente:

  • [/:string]
  • [/:number]
  • [/:alpha]

    $app = \DMS\Tornado\Tornado::getInstance();

    // utilizando un m贸dulo y cualquier tipo de petici贸n
    $app->route('/', 'demo|demo|index');

    // utilizando una funci贸n an贸nima y cualquier tipo de petici贸n
    $app->route('/saludar/:alpha', function($pNombre = null) {
        echo 'Hola ' . $pNombre;
    });

    // utilizando par谩metros opcionales y cualquier tipo de petici贸n
    $app->route('/mostrar[/:alpha][/:number]', function ($pNombre = null, $pEdad = null) {
        echo 'Hola ' . $pNombre . ', ' . $pEdad;
    });

    // utilizando un comod铆n (n cantidad de par谩metros) y cualquier tipo de petici贸n
    $app->route('/felicitador/:*', function () {
        $params = func_get_args();
        echo 'Felicitaciones ' . (isset($params[0]) ? $params[0] : '');
    });

    // utilizando un m贸dulo y petici贸n POST
    $app->route('POST /', 'demo|demo|guardar');

    // utilizando un m贸dulo y petici贸n GET o POST
    $app->route('GET|POST /', 'demo|demo|listar');
    

Tambi茅n es posible definir par谩metros con nombre. En dicho caso puede omitirse el uso de par谩metros de entrada en las funciones an贸nimas o m茅todos de los m贸dulos HMVC. Ejemplo:


    $app->route('/bienvenida/@nombre:alpha/tornado/@edad:number', function () use ($app) {
        echo 'Hola ' . $app->param('nombre') . ', Edad: ' . $app->param('edad');
    });
    

Puede agregar tipos de par谩metros auxiliares de la siguiente forma:


    $app = \DMS\Tornado\Tornado::getInstance();

    $app->addTypeParam(':custom', '([123]+)');
    
    $app->route('/personalizado/:custom', function ($pCustom = null) {
        echo 'Parametro personalizado ' . $pCustom;
    });
    

Nota: El 煤nico enrutamiento obligatorio es el del nodo ra铆z ya que indica cu谩l ser谩 el callback a ejecutar por defecto al ingresar a la aplicaci贸n.

Delegaciones:

Es posible delegar la acci贸n de un m贸dulo/ruta hacia otro sin necesidad de realizar una redirecci贸n por http. Esta delegaci贸n invoca al otro m贸dulo/ruta dentro del mismo request original. Ejemplo:


    // a m贸dulo sin par谩metros
    $app->forwardModule('modulo|clase|metodo');

    // a m贸dulo con par谩metros
    $app->forwardModule('modulo|clase|metodo', array('param1', 'param2'));

    // a url (par谩metros incluidos en la url)
    $app->forwardUrl('/otra/ruta/1234');
    

Si se encuentra instalado FPM en el Servidor puede devolver el resultado al cliente y continuar con la ejecuci贸n de la petici贸n actual en segundo plano de la siguiente forma:


    $app->finishRequest();
 
Anotaciones:

Algunas acciones pueden ser establecidas mediante anotaciones DocBlocks.

Enrutamientos:

En los controladores de los m贸dulos HMVC puede utilizar el tag @T_ROUTE para setear un enrutamiento. Esto generar谩 un archivo de configuraci贸n denominado "route_serialize.php".

Siempre que la aplicaci贸n se encuentre en modo de desarrollo (variable de configuraci贸n "tornado_environment_development" en true) se recorrer谩n los m茅todos de los controladores para actualizar este archivo de configuraci贸n.

Ejemplo:


    class Demo extends \DMS\Tornado\Controller
    {
        /**
         * Ejemplo de enrutamientos mediante anotaciones
         * @T_ROUTE /demo/anotacion
         * @T_ROUTE GET|POST /demo/otra/anotacion
         */
        public function index()
        {
            echo 'Hola Mundo Tornado';
        }
    }
Vistas

Puede incluir archivos de vistas/templates dentro de una ruta manejada por clousures de la siguiente forma:

    $app = \DMS\Tornado\Tornado::getInstance();

    $app->render('ruta/archivo.php');  // vista sin par谩metros
    $app->render('ruta/archivo.php', array('nombre'=>'valor')); // vista con par谩metros

Los par谩metros pasados a la vista/template se manejan de la misma forma que los par谩metros pasados a una vista de un m贸dulo HMVC.

Gesti贸n de errores y excepciones:

El manejo de errores y excepciones viene habilitado por defecto. Puede alterar su comportamiento de la siguiente forma:


    $app = \DMS\Tornado\Tornado::getInstance();

    $app->error(true);  // habilita el manejador
    $app->error(false); // deshabilita el manejador
    

Puede acceder a la 煤ltima excepci贸n lanzada de la siguiente forma:


    $app = \DMS\Tornado\Tornado::getInstance();

    $exc = $app->error();
    
Inyecci贸n de Dependencias:

Es posible extender el core mediante la inyecci贸n de nuevas clases. La forma de registrar una nueva dependencia es:


    $app->register('fecha', function($fecha = '2014-12-31'){
        return new \DateTime($fecha);
    });
    

Este registro crear谩 un dependencia para la clase 'DateTime' denominada 'fecha'. Podr谩 hacer uso de la misma de la siguiente forma:


    $app = \DMS\Tornado\Tornado::getInstance();

    echo $app->container('fecha')->format('d/m/Y') . '<br />';
    

Por defecto todas las dependencias inyectadas crean una nueva instancia de la clase. Puede registrar el servicio como Singleton seteando el tercer par谩metro opcional en true:


    $app->register('fecha', function(){
        return new \DateTime('2014-12-31');
    }, true);
    

Si las dependencias requieren par谩metros en sus constructores puede definir los mismos de la siguiente forma:


    $app->register('fecha.config', '2014-12-31');
    
    $app->register('fecha', function(\DMS\Tornado\Service $c){
        return new \DateTime($c->get('fecha.config'));
    });
    
Organizaci贸n de proyecto:

Existe un proyecto que dispone de un esqueleto para una aplicaci贸n base. Puede descargar el mismo desde https://github.com/danielspk/TornadoSkeletonApplication

M贸dulos:

Tornado PHP permite utilizar m贸dulos HMVC de forma conjunta con las funciones an贸nimas.

Si utiliza Composer, se recomienda registrar la ubicaci贸n de los m贸dulos en el autoload. Ejemplo:

    "autoload": {
        "psr-4": {
            "App\\Modules\\": "app/modules/"
        }
    },
Controladores:

Todos los controladores deben extender de \DMS\Tornado\Controller y deben definir un namespace que respete la especificaci贸n PSR-4. Ejemplo:

Asumiendo que los m贸dulos HMVC se encuentran en App\Modules[Modulo HMVC]\Controller


    namespace App\Modules\Demo\Controller;

    use \DMS\Tornado\Controller;
    
    class Demo extends Controller {
        public function index($param = null){
            echo ' Hola ' . $param . '<br>';
        }
    }
    

Los Controladores poseen una instancia de tornado PHP como propiedad propia. Puede acceder a la misma de la siguiente forma:


    // permite acceder a una instancia de Tornado
    $app = $this->app;
    
Modelos:

Todos los controladores deben definir un namespace que respete la siguiente jerarqu铆a: App\Modules[Modulo HMVC]\Model


    namespace App\Modules\Demo\Model;

    class Demo {
        public function getDemos($param = null){
            return true;
        }
    }
    
Vistas:

Dado que el controlador posee una instancia de Tornado es posible usar el m茅todo render() para invocar a una vista.

Resumen de M茅todos:

DMS\Tornado\Tornado

M茅todo Detalle
getInstance() Devuelve la instancia de Tornado (si no existe la crea)
run() Arranca el core
config(string) Devuelve el valor de la variable de configuraci贸n
config(array) Setea un array de configuraci贸n
config(string, mixed) Setea el valor en la variable de configuraci贸n
error() Devuelve la 煤ltima excepci贸n atrapada
error(bool) Habilita/deshabilita el manejador interno de errores y excepciones
hook(string) Ejecuta el gancho indicado
hook(string mixed) Registra un gancho y su callback
route(string, mixed) Registra un enrutamiento y su callback
addTypeParam(string, string) Registra un nuevo tipo de par谩metro
register(string, callable, [bool]) Registra una clase/servicio para extender la aplicaci贸n
container(string) Devuelve un servicio o par谩metro
render(string) Incluye una vista/template
render(string, array) Incluye una vista/template junto a un array de variables
param(string) Devuelve el valor de un par谩metro del enrutamiento
getRouteMatch() Devuelve la ruta que se esta procesando
forwardModule(string) Delega la acci贸n hacia otro m贸dulo
forwardModule(string, array) Delega la acci贸n hacia otro m贸dulo
forwardUrl(string) Delega la acci贸n hacia otra ruta
finishRequest() Devuelve el request al cliente y continua la ejecuci贸n del script actual

DMS\Tornado\Service

M茅todo Detalle
get Devuelve un servicio o par谩metro

DMS\Tornado\Controller

Atributo Detalle
app Instancia de Tornado

Licencia:

El proyecto se distribuye bajo la licencia MIT.

Tests unitarios:

Para ejecutar los test es necesario descargar PHPUnit. Sit煤ese en la carpeta ra铆z de Tornado y ejecute la siguiente instrucci贸n por l铆nea de comando:

    phpunit.phar

Ante errores o sugerencias escriba a la direcci贸n de email de contacto.

Sugerencias y colaboraci贸n:

Email: info@daniel.spiridione.com.ar