webman 注解插件

webman annotation 注解插件
本插件使用 doctrine/annotation 對(duì)注釋解析
PHP版本要求 >= 8.0
支持注釋注解 和 PHP8注解方式
目前支持的功能
- 路由注解
- 中間件注解
- 驗(yàn)證器注解
- 自定義注解
- 注解繼承
v1.0.5
版本開(kāi)始支持 - 依賴注入
v1.0.7
版本開(kāi)始支持
安裝
composer require linfly/annotation=1.x
配置
配置文件路徑:/plugin/linfly/annotation/annotation.php
<?php
return [
// 注解掃描路徑
'include_paths' => [
// 應(yīng)用目錄 支持通配符: * , 例如: app/*, app/*.php
'app',
],
// 掃描排除的路徑 支持通配符: *
'exclude_paths' => [
'app/model',
],
// 路由設(shè)置
'route' => [
// 如果注解路由 @Route() 未傳參則默認(rèn)使用方法名作為path
'use_default_method' => true,
],
// 驗(yàn)證器注解
'validate' => [
// 驗(yàn)證器驗(yàn)證處理類 (該功能需要自行安裝對(duì)應(yīng)的驗(yàn)證器擴(kuò)展包),目前只支持 think-validate
'handle' => LinFly\Annotation\Validate\Handle\ThinkValidate::class,
// 驗(yàn)證失敗處理方法
'fail_handle' => function (Webman\Http\Request $request, string $message) {
return json(['code' => 500, 'msg' => $message]);
}
],
];
使用
注解路由
支持的注解方式:
@Route
@GetRoute
@PostRoute
@PutRoute
@DeleteRoute
@PatchRoute
@HeadRoute
@OptionsRoute
除
@Route
注解外,其他注解都是v1.0.5版本開(kāi)始支持除
@Route
注解外,其他注解都是@Route
的別名,使用方式一致
use LinFly\Annotation\Route\Controller;
use LinFly\Annotation\Route\Route;
/**
* 控制器注解
* @param string|array $prefix 路由分組路徑
*
* @Controller(prefix="/api")
*/
// PHP8注解方式
#[Controller(prefix: '/api')]
class ApiController
{
/**
* 注解路由
* @param string|array $path 路由路徑 使用"/"開(kāi)始則忽略控制器分組路徑
* @param array $methods 請(qǐng)求方法 例:GET 或 ['GET', 'POST'],默認(rèn)為所有方法
* @param string $name 路由名稱 用于生成url的別名
* @param array $params 路由參數(shù)
*
* @Route(path="get", methods="get")
*/
// PHP8注解方式
#[Route(path: 'get', methods: 'get')]
public function get()
{
return 'get';
}
}
注解中間件
use LinFly\Annotation\Route\Controller;
use LinFly\Annotation\Route\Middleware;
use LinFly\Annotation\Route\Route;
/**
* @Controller(prefix="/api")
*
*
* 注解中間件 需要和注解路由一起使用
* @param string|array $middlewares 路由中間件 支持多個(gè)中間件
* @param array $only 指定需要走中間件的方法, 不指定則全部走中間件, 與except互斥 只支持在控制器上使用
* @param array $except 指定不需要走中間件的方法, 不指定則全部走中間件, 與only互斥 只支持在控制器上使用
*
* @Middleware(middlewares=AuthMiddleware::class, only={"get"})
*/
// PHP8注解方式
#[Middleware(middlewares=AuthMiddleware::class, only: ['get'])]
class ApiController
{
/**
* @Route(path="get", methods="get")
* @Middleware(middlewares={TokenCheckMiddleware::class})
*/
// PHP8注解方式
#[Middleware(middlewares=[TokenCheckMiddleware::class])]
public function get()
{
return 'get';
}
}
注解驗(yàn)證器
驗(yàn)證器注解需要配合驗(yàn)證器擴(kuò)展包使用,目前只支持 think-validate
驗(yàn)證器驗(yàn)證成功會(huì)繼續(xù)執(zhí)行,驗(yàn)證失敗則調(diào)用配置的 fail_handle 方法終止執(zhí)行
use app\validate\UserValidate;
use LinFly\Annotation\Validate\Validate;
use support\Request;
use support\Response;
class IndexController
{
/**
* @access public
*
* 注解驗(yàn)證器參數(shù)說(shuō)明
* @param string|array $params 驗(yàn)證器參數(shù) 支持多個(gè),例如: {"$get.id", "$post.name", "$post.title"}
* 驗(yàn)證器參數(shù) 支持:
* $post 獲取所有 POST 參數(shù)
* $get 獲取所有 GET 參數(shù)
* $all 獲取所有 REQUEST 參數(shù)
* $post.xx 自定義 POST 參數(shù)名稱 xx為實(shí)際的參數(shù)名稱
* $get.xx 自定義 GET 參數(shù)名稱 xx為實(shí)際的參數(shù)名稱
* xx 自定義 REQUEST 參數(shù)名稱 xx為實(shí)際的參數(shù)名稱
* @param string $validate 驗(yàn)證器類名
* @param string $scene 驗(yàn)證場(chǎng)景
*
*
* @Validate(validate=UserValidate::class)
* @param Request $request
* @return Response
*/
// PHP8注解方式
//#[Validate(validate: UserValidate::class)]
public function index(Request $request)
{
return response('hello webman');
}
}
綁定原生路由
綁定Webman原生路由后,在不使用注解路由的情況下,也能使用注解中間件、驗(yàn)證器等功能
注解類
@BindRoute
無(wú)參數(shù)綁定原生路由
v1.0.7
版本開(kāi)始支持
use LinFly\Annotation\Route\BindRoute;
use LinFly\Annotation\Route\Middleware;
use LinFly\Annotation\Validate\Validate;
use support\Request;
use support\Response;
use app\validate\UserValidate;
class IndexController
{
#[BindRoute]
#[Validate(validate: UserValidate::class)]
#[Middleware(middlewares=[TokenCheckMiddleware::class])]
public function index(Request $request)
{
return response('hello webman');
}
}
注解繼承
注解繼承可以讓你的注解更加簡(jiǎn)潔,減少重復(fù)代碼
參數(shù)說(shuō)明
/**
* 指定需要繼承的方法, 不指定則全部繼承, 與except互斥; 如果為false, 則不繼承任何注解
* @param array|false $only
* 指定不需要繼承的方法, 不指定則全部繼承, 與only互斥
* @param array $except
* 參數(shù)為true時(shí), 則合并父類的注解, 參數(shù)為false時(shí), 則覆蓋父類的注解
* @param bool $merge
*/
public function __construct(public array|false $only = [], public array $except = [], public bool $merge = true);
使用例子
父類:UserAuthController.php
<?php
namespace app\controller;
use app\middleware\UserAuthMiddleware;
use app\validate\UserValidate;
use LinFly\Annotation\Annotation\Inherit;
use LinFly\Annotation\Route\Controller;
use LinFly\Annotation\Route\Middleware;
use LinFly\Annotation\Route\Route;
use LinFly\Annotation\Validate\Validate;
use support\Request;
#[
// 用戶授權(quán)中間件
Middleware(middlewares: UserAuthMiddleware::class),
Validate(validate: UserValidate::class),
// 讓所有子類都繼承父類的注解(父類使用了繼承注解, 子類可選使用繼承注解)
Inherit,
// 讓所有子類只繼承父類的中間件注解
// Inherit(only: [Middleware::class]),
]
abstract class UserAuthController
{
}
子類:TestController.php
<?php
namespace app\controller;
use LinFly\Annotation\Route\Controller;
use LinFly\Annotation\Route\GetRoute;
#[
Controller(prefix: 'user'),
// 不繼承父類的注解
// Inherit(only: false),
// 繼承父類的所有注解
// Inherit(only: []),
// 只繼承父類的中間件注解
// Inherit(only: [Middleware::class]),
// 不繼承父類的驗(yàn)證器注解
// Inherit(except: [Validate::class]),
]
class TestController extends UserAuthController
{
#[GetRoute]
public function info()
{
return json([
'user_id' => 1,
'username' => 'test',
]);
}
}
依賴注入
配置
修改config/container.php
文件,修改后內(nèi)容如下:
$container = \LinFly\FacadeContainer::getInstance();
$container->definition(config('dependence', []));
return $container;
參數(shù)說(shuō)明
/**
* @param string|array $name 實(shí)例或者別名
* @param array $parameters 參數(shù)
*/
public function __construct(protected string $name = '', protected array $parameters = []);
使用例子
需要注入的類:TestService.php
<?php
namespace app\service;
use LinFly\Annotation\Annotation\Inject;
class TestService
{
public function test()
{
return true;
}
}
調(diào)用類:TestController.php
<?php
namespace app\controller;
use LinFly\Annotation\Annotation\Inject;
use app\service\TestService;
class TestController
{
/**
* @Inject()
*
* 可以使用var注解指定注入的類, 或者聲明屬性類型來(lái)指定注入的類
* 更推薦使用聲明屬性類型的方式,優(yōu)先級(jí)高于var注解
* @var TestService
*/
// PHP8注解方式
#[Inject]
protected TestService $testService;
public function test() {
var_dump($this->testService->test());
// true
}
}
實(shí)驗(yàn)性功能
1. 循環(huán)依賴
依賴注入支持循環(huán)依賴,即A依賴B,B依賴A,但是需要注意的是,依賴注入的類必須是單例模式,否則會(huì)報(bào)錯(cuò)。
構(gòu)造函數(shù)支持注入自身實(shí)例,注入自身的實(shí)例是單例實(shí)例,不會(huì)重復(fù)創(chuàng)建。
自定義注解類
第一步:創(chuàng)建注解類
注解類需要繼承
LinFly\Annotation\Annotation\Annotation
類注解類需要聲明
@Annotation
、@Target
、#[\Attribute()]
注解
測(cè)試代碼:annotation-example
控制器注解類
use Doctrine\Common\Annotations\Annotation\Target;
use LinFly\Annotation\AbstractAnnotation;
/**
* @Annotation
* @Target({"CLASS"})
*/
#[\Attribute(\Attribute::TARGET_CLASS)]
class TestControllerParams extends AbstractAnnotation
{
/**
* 第一個(gè)參數(shù)必須包含array類型,用來(lái)接收注解的參數(shù)
* @param string|array $controller
*/
public function __construct(public string|array $controller = '')
{
$this->paresArgs(func_get_args(), 'controller');
}
}
方法注解類
use Doctrine\Common\Annotations\Annotation\Target;
use LinFly\Annotation\AbstractAnnotation;
/**
* @Annotation
* @Target({"METHOD"})
*/
#[\Attribute(\Attribute::TARGET_METHOD)]
class TestMethodParams extends AbstractAnnotation
{
/**
* 第一個(gè)參數(shù)必須包含array類型,用來(lái)接收注解的參數(shù)
* @param string|array $method
*/
public function __construct(public string|array $method = '')
{
$this->paresArgs(func_get_args(), 'method');
}
}
第二步:使用注解類
use app\annotation\params\TestControllerParams;
use app\annotation\params\TestMethodParams;
use support\Request;
/**
* 自定義類的注解類
* @TestControllerParams(controller=IndexController::class)
*/
// PHP8原生注解
// #[TestControllerParams(controller: IndexController::class)]
class IndexController
{
/**
* 自定義方法的注解類
* @TestMethodParams(method="index")
*/
// PHP8原生注解
// #[TestMethodParams(method: __METHOD__)]
public function index(Request $request)
{
// 業(yè)務(wù)代碼 ...
}
}
第三步:獲取注解類的參數(shù)
方法一:通過(guò) LinFly\Annotation\Annotation\Annotation::yieldParseClassAnnotations() 方法獲取
use app\annotation\params\TestControllerParams;
use app\annotation\params\TestMethodParams;
use LinFly\Annotation\Annotation;
// 獲取指定類的注解列表 包括:類注解、屬性注解、方法注解、方法參數(shù)注解
$generator = Annotation::yieldParseClassAnnotations(IndexController::class);
/**
* @var string $annotationName 注解類類名
* @var array $items 注解類參數(shù)列表
*/
foreach ($generator as $annotationName => $items) {
switch ($annotationName) {
case TestControllerParams::class:
case TestMethodParams::class:
foreach ($items as $item) {
var_dump($item['type'] . ' -> ' . $item['annotation']);
}
break;
}
}
方法二:通過(guò) AnnotationHandle 獲取
程序啟動(dòng)時(shí)會(huì)掃描所有的注解類,掃描完成后會(huì)調(diào)用已綁定注解類的回調(diào)事件
- 新建Handle類
注意:Handle類需要繼承LinFly\Annotation\Handle\Handle
類
namespace app\annotation\handle;
use LinFly\Annotation\Interfaces\IAnnotationHandle;
class TestHandle implements IAnnotationHandle
{
public static function handle(array $item): void
{
switch ($item['type']) {
case 'class':
case 'method':
var_dump($item['type'] . ' -> ' . $item['annotation']);
break;
}
}
}
- 新建Bootstrap類
參考資料:webman業(yè)務(wù)初始化
namespace app\bootstrap;
use app\annotation\handle\TestHandle;
use app\annotation\params\TestControllerParams;
use app\annotation\params\TestMethodParams;
use LinFly\Annotation\Annotation;
use Webman\Bootstrap;
class CreateAnnotationHandle implements Bootstrap
{
/**
* start
* @access public
* @param $worker
* @return void
*/
public static function start($worker)
{
// monitor進(jìn)程不執(zhí)行
if ($worker?->name === 'monitor') {
return;
}
// 添加測(cè)試控制器注解類處理器
Annotation::addHandle(TestControllerParams::class, TestHandle::class);
// 添加測(cè)試控制器方法注解類處理器
Annotation::addHandle(TestMethodParams::class, TestHandle::class);
}
}
- 配置隨進(jìn)程啟動(dòng)
打開(kāi)config/bootstrap.php
將CreateAnnotationHandle
類加入到啟動(dòng)項(xiàng)中。
return [
// ...這里省略了其它配置...
app\bootstrap\CreateAnnotationHandle::class,
];
更新日志
v1.0.7
- 新增依賴注入功能
- 新增綁定原生路由注解
v1.0.6
- 修復(fù)部署模式調(diào)用STDOUT報(bào)錯(cuò)。
v1.0.5
- 修正注解路由請(qǐng)求方法大小寫問(wèn)題。
- 新增注解繼承功能。
- 新增
@GetRoute
@PostRoute
等注解路由類。 - 新增
include_paths
注解掃描路徑參數(shù)支持通配符。 - 新增支持掃描單個(gè)文件中寫入多個(gè)類的文件。
v1.0.4
- 修復(fù)注解路由可選參數(shù)解析問(wèn)題。
v1.0.3
- 修復(fù)中間件注解和驗(yàn)證器注解執(zhí)行順序問(wèn)題。
- 新增中間件only和except參數(shù), 用于指定中間件只在指定的方法執(zhí)行。
- 新增在控制器上使用驗(yàn)證器注解。