# 节点

DCE定义了节点的概念,所谓节点,简单来说就是一个请求路径与控制器方法的映射关系,收到用户请求后,DCE会找到请求地址对应的路由方法,执行并返回结果。

节点配置会被缓存,Dce启动时会扫描项目下的节点文件,如果文件有改动则从配置文件取节点,否则直接用缓存。你也可以开启节点缓存配置来强制使用节点缓存,但这种形式下节点配置改动时缓存不会自动更新,需要你手动清除缓存来自动重建缓存。

节点配置于对应项目下的config/nodes.php,以数组的形式定义配置项,配置项数组下标皆以蛇底形式书写,DCE载入配置后,会自动转为小驼峰式的节点对象属性。下述为一个示例节点配置文件:

<?php
// [SomeProject]/config/nodes.php
return [
    [ // 项目根节点,若未定义则DCE会自动生成
        'methods' => 'cli', // 允许的请求方式,会被子节点继承
        'path' => 'db', // 请求路径
    ],
    [
        'path' => 'extend', // 请求路径(此为省略写法,完整定义为"db/extend",DCE解析时会自动补充完整)
        'controller' => 'MysqlShardingController->extend', // 控制器方法,以 -> 分割控制器类与方法名
        'enable_coroutine' => true, // 是否开启协程容器
    ],
];
1
2
3
4
5
6
7
8
9
10
11
12
13

# 注解式节点

注解式节点是指可以在控制器方法中配置节点,这种方式可以让你编写接口更加便捷直观,可以省略控制器相关配置项。但注解式节点需要通过扫描全部控制器文件(默认最深4层)来解析,如果你是Cgi式应用,每次请求都会扫描解析全部控制器方法,比较浪费IO,你可以在生产环境开启节点缓存配置来提升性能。如果你是常驻内存服务的应用,则无需担心IO浪费,因为Dce仅在载入时(服务启动前)会扫描节点。

Dce未在项目下找到config/nodes.php文件时,则视其为注解式节点项目,会扫描控制器方法的注解来解析节点配置。下面是一个注解节点配置示例:

<?php
namespace app\controller;
// 从名字空间可以看出当前控制器所属一个叫 app 的项目

use dce\project\node\Node; // 引入注解式节点配置类
use dce\project\Controller;

class TestController extends Controller {
    #[Node('app', 'cli', omissiblePath: true)] // 配置可省略项目级"app"路径 (凡是以 __ 开头的方法, Dce不会当其为控制器方法, 即在该方法的注解配置的节点未指定控制器方法)
    public function __init() {}

    #[Node] // 配置注解式节点, 并未配置路径及控制器, 未配置路径时以方法名作为路径, 且Dce能自动解析对应控制器方法. 
    public function index() {
        $this->print('哈哈');
    }

    #[Node(extra: ['a' => '哈哈'])] // 配置了扩展属性, 你可以以此做一些特殊的工作, 如鉴权
    public function test() {
        $this->print($this->request->node->extra);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 注解式节点参数

参数名与配置相对应,可以点击跳转到对应配置项的说明

string|null $path = null节点路径(若未指定,则将以方法名的蛇底形式作为当前节点路径,否则直接使用指定的路径。若控制器处于子级目录中,则以其所有父目录作为父路径。)
string|array|null $methods = null
string|null $id = null
string|null $name = null
bool|null $enableCoroutine = null
bool|null $hookCoroutine = null
string|null $render = null
string|null $templateLayout = null
array|null $corsOrigins = null
array|null $projectHosts = null
int|null $renderCache = null
bool|null $omissiblePath = null
array|null $urlArguments = null
bool|null $urlPlaceholder = null
array|null $urlSuffix = null
bool|null $lazyMatch = null
string|null $http301 = null
string|null $http302 = null
string|null $jsonpCallback = null
array|null $extra = null
bool $controllerPath = false 是否为控制器级路径(若设为真,则作为控制器级节点,该节点将作为该控制器下所有节点的父节点)

# \dce\project\node\Node

节点类,类属性通过节点配置定义,DCE会自动将其转为节点对象属性。下述所有属性示例皆为节点配置示例。

# ->id

string 节点ID,全应用唯一,若未定义则会自动生成

# ->name

string 节点名

# ->pathName

string 节点路径名,DCE自动提取

# ->methods

string[] 允许的请求类型(会被继承,子节点可以自定义覆盖继承的值),支持值如下:

类型
get GET请求(默认)
post POST请求
put PUT请求
delete DELETE请求
cli 命令行式访问
tcp TCP请求
udp UDP请求
websocket Websocket请求
'methods' => 'get',
// 配置支持字符串的形式,转为对象时会自动转为数组属性
'methods' => ['get', 'cli'],
// 也支持直接定义为数组形式
1
2
3
4

# ->path

string 节点路径,多级之间以 / 隔开

'path' => 'home',
'path' => 'home/gallery',
1
2

# ->pathFormat

string 格式化的路径,用户可能省略了项目路径部分,DCE解析时会自动补全并格式化然后填充到该属性。

# ->projectName

string 节点所属项目名

# ->controller

string 节点映射的控制器方法,类与方法名之间以 -> 分隔。

'controller' => 'GalleryController->list',
// 普通的控制器方法,最终会解析为 (new \[PROJECT_NAME]\controller\GalleryController)->list()
'controller' => 'gallery\\GalleryController->list',
// 若控制器在子目录下,则可以在前面加上子目录名,会解析为 (new \[PROJECT_NAME]\controller\gallery\GalleryController)->list()
1
2
3
4

# ->enableCoroutine

bool 是否开启协程容器,默认为false。若在Swoole Server环境,则是通过Server配置控制(会被继承,子类可自定义以覆盖父节点的定义)

# ->hookCoroutine

bool 是否协程化IO操作,当$enableCoroutine=true时此参数将默认为true(会被继承,子类可自定义以覆盖父节点的定义)

# ->render

string 渲染器或PHP模板文件路径(相对于 [PROJECT_NAME]/template/目录),调用控制器的render()方法时会以该配置方式渲染数据(非模板值会被继承,子类可自定义以覆盖父节点的定义)

名称 说明
json 使用JSON渲染响应内容(默认)
jsonp 使用JSONP渲染响应内容
xml 使用XML格式渲染响应内容
[other.php] 解析渲染PHP模板并响应(可以以此来渲染复杂结构数据,如HTML、XML等)
'render' => 'json',
// 使用json编码数据并响应
'render' => 'gallery/list.php',
// 子目录的模板,将会解析为 [PROJECT_NAME]/template/gallery/list.php,然后渲染结果并响应
1
2
3
4

# ->templateLayout

string 模板布局文件路径(相对于 [PROJECT_NAME]/template/目录),留空则不使用布局(会被继承,子类可自定义以覆盖父节点的定义)

# ->renderCache

int = 0 渲染缓存(支持位或组合配置,仅对HTTP请求有效)

位元 类型 说明
0 不缓存 不对接口/页面缓存
1 缓存Api数据 缓存控制器方法中assign的数据,下次进入直接取缓存而不再执行控制器方法,直到缓存失效
2 缓存模板 不论模板是否被修改,直接取缓存渲染直到缓存失效
4 缓存渲染页面 缓存最终的渲染内容,下次进入若Api数据无变化,则直接输出缓存,除非无缓存或已失效

# ->omissiblePath

bool = false 当前节点路径是否可省略。

'omissible_path' => false,
// 不可省略时可能得这么访问 /home/gallery/
'omissible_path' => true,
// 可省略时允许这么访问 /gallery/,使用Url类生成的url也会自动省略对应节点的路径部分
1
2
3
4

# ->urlArguments

NodeArgument[] = [] Url参数配置集(Url参数指伪装在Url路径部分的参数、伪静态地址中的参数,如 /news/1.html中,其实含有参数id = 1),以纯数组配置,DCE会将其转为对象数组。

// 下述配置可以通过 \dce\project\request\Url::make() 生成伪静态地址,用户请求该伪静态地址时,也能正确的匹配到对应的节点并解析出伪装的参数
'url_arguments' => [
    ['name' => 'id', 'match' => '/^\d+$/',]
],
1
2
3
4

# ->urlPlaceholder

bool = true 参数位未传时是否保留分隔符,默认为true(此配置设为false时需要用户保证多个参数的匹配不会混淆,不会把a匹配为b参数,否则会导致错误提参)

'url_placeholder' => false,
// 假设有四个参数三个未传,则设false时可能是这样 /news/1.html
'url_placeholder' => true,
// 设true时是这样 /news/1---.html
1
2
3
4

# ->urlSuffix

array = ['', '/'] 允许的后缀

'url_suffix' => '.html',
// 配置时可以使用字符串,DCE会自动转为数组,该配置能解析类似这样的地址 /news/1.html
'url_suffix' => ['', '/'],
// 同时支持多种后缀,如 /news 及 /news/
1
2
3
4

# ->http301

string 301永久转移目标地址,路由匹配到该节点时会自动301重定向

# ->http302

string 302临时跳转目标地址,路由匹配到该节点时会自动302重定向

# ->jsonpCallback

string = 'callback' Jsonp请求时的回调方法url参数名

# ->lazyMatch

bool = false 是否惰性匹配(匹配到此及命中,不再继续匹配剩余路径)

# ->corsOrigins

array 允许跨域的主机,若配置了,则自动允许所配的主机访问(会被继承,子类可自定义以覆盖父节点的定义)

# ->isDir

bool 是否目录节点,DCE自动判断生成

# ->projectHosts

array 项目绑定域名(只在项目根节点配置有效,当访问绑定的域名时,会自动路由到相应项目下)

# ->extra

array 用户自定义参数,如'extra' => ['attr1' => 1],

# ->genPathInfo()

解析path取组成部件

  • 返回array

# ->arrayify()

数组化当前节点

  • 返回array

# \dce\project\node\NodeArgument

节点Url参数类,配置伪静态式Url参数的提取方式

# ->name

string 参数名,提取的参数会以该值作为下标存入$_GET数组(如'name' => 'id',则路径/news/1.html可能提取为$_GET['id'] = 1)。

# ->prefix

string 参数标识前缀,帮助更准确的匹配提取参数。

# ->match

string|array|callable|null 参数匹配器,支持下述类型的值:

类型 用法
regexp 正则表达式,如'/^\d+$/'
array 数组,会用来做in_array匹配检查,如[1,2,3]/news/3.html能匹配提取,/news/4.html不能匹配
callable 回调函数,返回非false则为匹配,否则不匹配
null 无匹配器,参数默认匹配按顺序提取
其他 抛出无效匹配器的异常

# ->required

bool 参数是否必须

# ->separator

string 参数分隔符,默认为-

# ->autoGet

bool 生成url时是否自动从当前url中提取应入