danielspk/tornado

PHP的精简工作核心

v2.0.0 2015-06-20 14:35 UTC

README

Build Status Latest Stable Version Total Downloads License

ScreenShot

TORNADO 是一个PHP的精简工作框架,允许实现HMVC模式和/或RESTful服务

更多详细信息请访问其网站 http://tornado-php.com

哲学

TORNADO 并非试图成为一个全栈PHP框架。相反,它试图
是一个非常精简的工作核心,用于实现HMVC模式和/或REST服务,具有最少的参数化和代码使用,并基于一个组织项目、配置和错误管理的简单核心。

TORNADO 不包括数据库访问、模板管理、邮件发送等常见任务的库。使用Composer根据要开发的项目特定需求包括第三方包。

灵感

TORNADO 吸收了几个PHP微框架的灵感,包括

目标

TORNADO 的开发试图遵守以下目标

  • 快速
  • 易于理解 (包括其API和内部结构)
  • API中方法尽可能少
  • 允许使用钩子进行扩展
  • 轻松包含第三方库/包
  • 代码行数尽可能少
  • 是一个工作核心 (绝不是框架)

特性

  • 用于使用HMVC模式和/或REST服务的路由(基于友好的URL)
  • 应用程序的常规配置
  • 用于扩展核心特性的钩子
  • 错误和异常捕获
  • 依赖注入

编码

TORNADO 支持PHP框架互操作小组的倡议,并实现了PSR-2和PSR-4标准。

更多信息请访问 http://www.php-fig.org/

安装

推荐的安装方式需要使用Composer。

{
    "require": {
        "danielspk/tornado" : "2.*"
    }
}
  • 启动命令行并执行以下命令
composer install

使用手册

当前版本与初始版本 1.0.0 完全不同

如果您要更新应用程序,请详细阅读更改日志文件 CHANGELOG.md

基本用法

基本用法示例(使用两种类型的路由)

<?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

获取核心实例
    $app = \DMS\Tornado\Tornado::getInstance();
执行核心
	// 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();
设置配置
    $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'
    ]);
读取配置
    $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'];
Tornado的配置变量

Tornado 允许配置应用程序的工作环境。这样就可以改变核心的内部行为

    // 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);

其他配置

    // - 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);
        
钩子使用

存在6种类型的钩子

  • init: 在解析URL以查找匹配的路由之前
  • before: 在执行匹配的路由之前
  • after: 在执行匹配的路由之后
  • end: 在请求执行结束时
  • 404: 无法找到与URL匹配的路由
  • 错误:在应用程序中捕获到错误或异常
    $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';
    });
    

也可以创建自定义钩子。以下是一个使用用户类的示例

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

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

通过代码执行钩子的方式如下

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

    $app->hook('fueraDeLinea');
    

可以创建多个具有相同名称的钩子。它们将按定义的顺序依次执行。您可以可选地通过明确指定所需顺序来更改此顺序

    $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);
    

如果您声明了多个同名钩子,可能会阻止后续钩子的执行,使钩子在执行时返回 false。

除了 init 钩子外,您可以通过以下方式查询正在执行或即将执行的路径

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

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

这将返回一个包含以下信息的数组

  • 请求方法(GET、POST等)
  • 路由
  • 回调
  • 参数
钩子和执行流程

核心的执行顺序如下

  • 执行 init 钩子
  • 解析 URL 以查找匹配的路由
    • 如果没有匹配项,则执行
      • 404 钩子
      • end 钩子
      • 结束执行
  • 执行 before 钩子
    • 如果其中一个返回 false,则执行
      • end 钩子
      • 结束执行
  • 执行匹配的路由
  • 执行 after 钩子
  • 执行 end 钩子
定义路由

路由可以是

  • (空) - 任何类型的请求
  • GET - 通过 GET 方法实现的 RESTful
  • POST - 通过 POST 方法实现的 RESTful
  • PUT - 通过 PUT 方法实现的 RESTful
  • DELETE - 通过 DELETE 方法实现的 RESTful

如果服务器不支持 PUT 和 DELETE 方法,可以通过发送一个包含“REST_METHOD”变量的 POST 请求来模拟这些方法,该变量的值为 PUT 或 DELETE。

存在四种类型的参数用于路由 URL

  • :string - 只接受字母
  • :number - 只接受数字
  • :alpha - 接受数字和字母
  • :* - 接受任何数量和类型的参数(只能包含一个,且位于末尾)

如果包含可选参数,则语法如下

  • [/: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');
    

也可以定义具有名称的参数。在这种情况下,可以在 HMVC 模块的匿名函数或方法中省略输入参数。示例

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

可以添加以下形式的辅助参数类型

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

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

注意:唯一的必选路由是根节点路由,因为它指示默认的回调函数,当进入应用程序时将执行该回调。

委托

可以将模块/路由的操作委托给另一个模块/路由,而无需进行 HTTP 重定向。这种委托在同一个请求中调用其他模块/路由。示例

    // 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');
    

如果服务器上安装了 FPM,可以以以下方式将结果返回给客户端并继续在后台处理当前的请求

    $app->finishRequest();
 
注解

一些操作可以通过 DocBlocks 注解来设置。

路由

在 HMVC 模块的控制器中,可以使用 @T_ROUTE 标记来设置路由。这将生成一个名为 "route_serialize.php" 的配置文件。

只要应用程序处于开发模式(配置变量 "tornado_environment_development" 设置为 true),就会遍历控制器的所有方法来更新此配置文件。

示例

    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';
        }
    }
视图

可以以下面的方式在由闭包处理的路径中包含视图/模板文件

    $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

传递给视图/模板的参数处理方式与传递给 HMVC 模块视图的参数相同。

错误和异常管理

错误和异常管理默认启用。您可以通过以下方式更改其行为

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

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

可以通过以下方式访问最后抛出的异常:

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

    $exc = $app->error();
    
依赖注入

可以通过注入新的类来扩展核心。注册新依赖项的方式如下:

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

此注册将为 'DateTime' 类创建一个名为 'fecha' 的依赖项。您可以按以下方式使用它:

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

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

默认情况下,所有注入的依赖项都会创建类的实例。可以通过将第三个可选参数设置为 true 来将服务注册为 Singleton。

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

如果依赖项的构造函数需要参数,可以按以下方式定义它们:

    $app->register('fecha.config', '2014-12-31');
    
    $app->register('fecha', function(\DMS\Tornado\Service $c){
        return new \DateTime($c->get('fecha.config'));
    });
    
项目组织

存在一个项目,它提供了一个基础应用骨架。您可以从以下链接下载:https://github.com/danielspk/TornadoSkeletonApplication

模块

Tornado PHP 允许结合使用 HMVC 模块和匿名函数。

如果您使用 Composer,建议在 autoload 中注册模块的位置。示例:

    "autoload": {
        "psr-4": {
            "App\\Modules\\": "app/modules/"
        }
    },
控制器

所有控制器都必须从 \DMS\Tornado\Controller 继承,并必须定义一个遵守 PSR-4 规范的命名空间。示例:

假设 HMVC 模块位于 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>';
        }
    }
    

控制器拥有一个 tornado PHP 实例作为其自身的属性。您可以通过以下方式访问它:

    // permite acceder a una instancia de Tornado
    $app = $this->app;
    
模型

所有控制器都必须定义一个遵守以下层次结构的命名空间:App\Modules[Modulo HMVC]\Model

    namespace App\Modules\Demo\Model;

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

由于控制器拥有一个 Tornado 实例,因此可以使用 render() 方法调用视图。

方法摘要

DMS\Tornado\Tornado

DMS\Tornado\Service

DMS\Tornado\Controller

许可协议

本项目遵循 MIT 许可协议。

单元测试

要运行测试,需要下载 PHPUnit。位于 Tornado 的根目录下,通过以下命令行指令执行:

    phpunit.phar

对于错误或建议,请发送电子邮件至联系地址。

建议和协作

邮箱:info@daniel.spiridione.com.ar