first commit
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute;
|
||||
|
||||
interface AnnoRoute
|
||||
{
|
||||
|
||||
/**
|
||||
* register route
|
||||
*
|
||||
* @param string $path
|
||||
* @return void
|
||||
*/
|
||||
public function register(string $path): void;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
class AnnoRouteService implements AnnoRoute
|
||||
{
|
||||
|
||||
/**
|
||||
* register route
|
||||
* @param string|array $path
|
||||
* @return void
|
||||
*/
|
||||
public function register($path): void
|
||||
{
|
||||
$paths = is_array($path) ? $path : [$path];
|
||||
|
||||
foreach ($paths as $p) {
|
||||
$this->registerFromPath($p);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从指定路径注册路由
|
||||
*/
|
||||
private function registerFromPath(string $path): void
|
||||
{
|
||||
if (!is_dir($path)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->files()
|
||||
->in($path)
|
||||
->name('*Controller.php');
|
||||
|
||||
foreach ($finder as $controller) {
|
||||
$className = $this->getClassNameFromFile(
|
||||
$controller->getRealPath(),
|
||||
$controller->getPath()
|
||||
);
|
||||
if ($className && class_exists($className)) {
|
||||
RouteRegisterService::register($className);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 从文件路径和所在目录解析类名
|
||||
*/
|
||||
private function getClassNameFromFile(string $filePath, string $fileDir): ?string
|
||||
{
|
||||
// 读取文件内容获取命名空间
|
||||
$content = file_get_contents($filePath);
|
||||
|
||||
if (!preg_match('/namespace\s+([^;]+);/', $content, $namespaceMatch)) {
|
||||
// 没有命名空间,尝试使用 PSR-0 规则
|
||||
return $this->guessClassNameFromPath($filePath, $fileDir);
|
||||
}
|
||||
|
||||
$namespace = trim($namespaceMatch[1]);
|
||||
$className = basename($filePath, '.php');
|
||||
|
||||
return $namespace . '\\' . $className;
|
||||
}
|
||||
|
||||
/**
|
||||
* 当文件没有命名空间时,通过路径猜测类名
|
||||
*/
|
||||
private function guessClassNameFromPath(string $filePath, string $fileDir): ?string
|
||||
{
|
||||
// 获取相对于项目根目录的路径
|
||||
$basePath = base_path();
|
||||
$relativePath = str_replace($basePath, '', $fileDir);
|
||||
|
||||
// 将路径转换为命名空间
|
||||
$namespace = str_replace('/', '\\', ltrim($relativePath, '/'));
|
||||
|
||||
// 移除开头的反斜杠并转换路径分隔符
|
||||
$namespace = trim($namespace, '\\');
|
||||
|
||||
$className = basename($filePath, '.php');
|
||||
|
||||
// 如果命名空间为空,直接返回类名
|
||||
if (empty($namespace)) {
|
||||
return $className;
|
||||
}
|
||||
|
||||
return $namespace . '\\' . $className;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute\Attribute;
|
||||
|
||||
use Attribute;
|
||||
use Modules\AnnoRoute\BaseAttribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class DeleteRoute extends BaseAttribute
|
||||
{
|
||||
/** @var string 请求方法 */
|
||||
public string $httpMethod = 'DELETE';
|
||||
|
||||
/**
|
||||
* @param string $route 路由地址
|
||||
* @param string|bool $authorize 权限字段
|
||||
* @param string|array $middleware 中间件
|
||||
* @param array $where 路由参数约束
|
||||
*/
|
||||
public function __construct(
|
||||
public string $route = '',
|
||||
public string|bool $authorize = true,
|
||||
public string | array $middleware = '',
|
||||
public array $where = [],
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute\Attribute;
|
||||
|
||||
use Attribute;
|
||||
use Modules\AnnoRoute\BaseAttribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class GetRoute extends BaseAttribute
|
||||
{
|
||||
/** @var string 请求方法 */
|
||||
public string $httpMethod = 'GET';
|
||||
|
||||
/**
|
||||
* @param string $route 路由地址
|
||||
* @param string|bool $authorize 权限字段
|
||||
* @param string|array $middleware 中间件
|
||||
* @param array $where 路由参数约束
|
||||
*/
|
||||
public function __construct(
|
||||
public string $route = '',
|
||||
public string|bool $authorize = true,
|
||||
public string | array $middleware = '',
|
||||
public array $where = [],
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute\Attribute;
|
||||
|
||||
use Attribute;
|
||||
use Modules\AnnoRoute\BaseAttribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class PostRoute extends BaseAttribute
|
||||
{
|
||||
/** @var string 请求方法 */
|
||||
public string $httpMethod = 'POST';
|
||||
|
||||
/**
|
||||
* @param string $route 路由地址
|
||||
* @param string|bool $authorize 权限字段
|
||||
* @param string|array $middleware 中间件
|
||||
* @param array $where 路由参数约束
|
||||
*/
|
||||
public function __construct(
|
||||
public string $route = '',
|
||||
public string|bool $authorize = true,
|
||||
public string | array $middleware = '',
|
||||
public array $where = [],
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute\Attribute;
|
||||
|
||||
use Attribute;
|
||||
use Modules\AnnoRoute\BaseAttribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class PutRoute extends BaseAttribute
|
||||
{
|
||||
/** @var string 请求方法 */
|
||||
public string $httpMethod = 'PUT';
|
||||
|
||||
/**
|
||||
* @param string $route 路由地址
|
||||
* @param string|bool $authorize 权限字段
|
||||
* @param string|array $middleware 中间件
|
||||
* @param array $where 路由参数约束
|
||||
*/
|
||||
public function __construct(
|
||||
public string $route = '',
|
||||
public string|bool $authorize = true,
|
||||
public string | array $middleware = '',
|
||||
public array $where = [],
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute\Attribute;
|
||||
|
||||
use Attribute;
|
||||
|
||||
#[Attribute(Attribute::TARGET_CLASS)]
|
||||
class RequestAttribute
|
||||
{
|
||||
/**
|
||||
* @param string $routePrefix 路由前缀
|
||||
* @param string $abilitiesPrefix 权限前缀
|
||||
* @param string | array $middleware 控制器中间件
|
||||
* @param string | null $authGuard 用户提供程序
|
||||
*/
|
||||
public function __construct(
|
||||
public string $routePrefix = '',
|
||||
public string $abilitiesPrefix = '',
|
||||
public string | array $middleware = '',
|
||||
public ?string $authGuard = null
|
||||
)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute;
|
||||
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Modules\Common\Enum\ShowType as ShopTypeEnum;
|
||||
|
||||
abstract class BaseAttribute
|
||||
{
|
||||
/**
|
||||
* 路由地址,使用该属性来指定路由地址,完整的路由地址由 RequestAttribute 的 routePrefix 和 route 拼接而成,例如:
|
||||
* RequestAttribute 的 routePrefix 为 /admin/user,Mapping 的 route 为 /create,那么完整的路由地址为 /admin/user/create
|
||||
*
|
||||
* Routing address, use this attribute to specify the routing address. The complete routing address is composed
|
||||
* of the routePrefix of RequestAttribute and the route concatenated, for example: If the routePrefix of RequestAttribute
|
||||
* is /admin/user and the route of Mapping is /create, then the complete routing address is /admin/user/create
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $route = '';
|
||||
|
||||
/**
|
||||
* 路由中间件,该属性用于指定路由中间件,多个中间件以数组形式传递,例如:['auth', 'admin']
|
||||
*
|
||||
* Route middleware, this attribute is used to specify the route middleware, multiple middleware are passed in
|
||||
* as an array, for example: ['auth', 'admin']
|
||||
*
|
||||
* @var string|array
|
||||
*/
|
||||
public string | array $middleware = '';
|
||||
|
||||
/**
|
||||
* HTTP 的请求方法
|
||||
*
|
||||
* HTTP request method
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $httpMethod = 'POST';
|
||||
|
||||
/**
|
||||
* 权限字符串,该属性用于指定权限【能力】字符串,用于权限【能力】认证,完整的能力字符串由 RequestAttribute 的 abilitiesPrefix 和 authorize
|
||||
* 拼接而成,例如:RequestAttribute 的 abilitiesPrefix 为 admin,Mapping 的 authorize 为 user,那么完整的权限【能力】字符串为 admin.user
|
||||
*
|
||||
* Permission string, this attribute is used to specify the permission string, used for permission authentication,
|
||||
* the complete permission string is composed of the abilitiesPrefix of RequestAttribute and the authorize concatenated,
|
||||
* for example: If the abilitiesPrefix of RequestAttribute is admin and the authorize of Mapping is user, then the complete
|
||||
* permission string is admin.user
|
||||
*
|
||||
* @var string | bool
|
||||
*/
|
||||
public string | bool $authorize = true;
|
||||
|
||||
/**
|
||||
* 路由参数约束,该属性用于指定路由参数的正则约束,例如:['id' => '[0-9]+']
|
||||
*
|
||||
* Route parameter constraints, this attribute is used to specify regex constraints for route parameters,
|
||||
* for example: ['id' => '[0-9]+']
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public array $where = [];
|
||||
|
||||
/**
|
||||
* 成功响应
|
||||
* @param $msg array|string
|
||||
* @return JsonResponse
|
||||
*/
|
||||
protected static function success(array|string $msg = ''): JsonResponse
|
||||
{
|
||||
if (is_array($msg)) {
|
||||
$data = $msg;
|
||||
$msg = '';
|
||||
} else {
|
||||
$data = [];
|
||||
}
|
||||
return response()->json([
|
||||
'success' => true,
|
||||
'data' => $data,
|
||||
'showType' => ShopTypeEnum::SUCCESS_MESSAGE->value,
|
||||
'msg' => $msg,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\AnnoRoute;
|
||||
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Illuminate\Support\Str;
|
||||
use Modules\AnnoRoute\Attribute\DeleteRoute;
|
||||
use Modules\AnnoRoute\Attribute\GetRoute;
|
||||
use Modules\AnnoRoute\Attribute\PostRoute;
|
||||
use Modules\AnnoRoute\Attribute\PutRoute;
|
||||
use Modules\AnnoRoute\Attribute\RequestAttribute;
|
||||
use ReflectionClass;
|
||||
use ReflectionException;
|
||||
|
||||
class RouteRegisterService
|
||||
{
|
||||
/**
|
||||
* @var array|string[]
|
||||
*/
|
||||
private static array $mapping = [
|
||||
GetRoute::class,
|
||||
PostRoute::class,
|
||||
PutRoute::class,
|
||||
DeleteRoute::class
|
||||
];
|
||||
|
||||
/**
|
||||
* register 注册路由
|
||||
*/
|
||||
public static function register(string $className): void
|
||||
{
|
||||
try {
|
||||
$classRef = new ReflectionClass($className);
|
||||
|
||||
$classAttr = collect($classRef->getAttributes());
|
||||
if($classAttr->isEmpty()) return;
|
||||
|
||||
$classAttrName = $classAttr->map->getName();
|
||||
if(! $classAttrName->contains(RequestAttribute::class)) {
|
||||
return;
|
||||
}
|
||||
$requestMapping = $classAttr->first(fn ($item) => $item->getName() == RequestAttribute::class);
|
||||
$routeInstance = $requestMapping->newInstance();
|
||||
// 默认参数
|
||||
$routePrefix = $routeInstance->routePrefix ?? '';
|
||||
$authGuard = $routeInstance->authGuard ?? null;
|
||||
$abilitiesPrefix = $routeInstance->abilitiesPrefix ?? '';
|
||||
$middleware = self::registerMiddleware($routeInstance->middleware);
|
||||
|
||||
$methods = $classRef->getMethods();
|
||||
|
||||
foreach ($methods as $method) {
|
||||
// 方法注解
|
||||
$attributes = $method->getAttributes();
|
||||
if(empty($attributes)) {
|
||||
continue;
|
||||
}
|
||||
$methodName = $method->getName();
|
||||
|
||||
foreach ($attributes as $attribute) {
|
||||
if (in_array($attribute->getName(), self::$mapping)) {
|
||||
$instance = $attribute->newInstance();
|
||||
self::registerRoute(
|
||||
$instance,
|
||||
$methodName,
|
||||
$className,
|
||||
$authGuard,
|
||||
$middleware,
|
||||
$routePrefix,
|
||||
$abilitiesPrefix,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ReflectionException $e) {
|
||||
echo $e->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册路由
|
||||
* @param BaseAttribute $instance
|
||||
* @param string $method
|
||||
* @param string $className
|
||||
* @param string|null $authGuard
|
||||
* @param array $middleware
|
||||
* @param string $routePrefix
|
||||
* @param string $abilitiesPrefix
|
||||
* @return void
|
||||
*/
|
||||
private static function registerRoute(
|
||||
BaseAttribute $instance,
|
||||
string $method,
|
||||
string $className,
|
||||
string $authGuard = null,
|
||||
array $middleware = [],
|
||||
string $routePrefix = '',
|
||||
string $abilitiesPrefix = ''
|
||||
): void
|
||||
{
|
||||
$authorize = $instance->authorize;
|
||||
|
||||
$authMiddleware = [];
|
||||
if (!empty($authorize)) {
|
||||
$authMiddleware[] = 'auth:sanctum';
|
||||
if(! empty($authGuard) ) {
|
||||
$authMiddleware[] = 'authGuard:' . $authGuard;
|
||||
} else {
|
||||
$authMiddleware[] = 'authGuard';
|
||||
}
|
||||
if (is_string($authorize) && !empty($abilitiesPrefix)) {
|
||||
$authMiddleware[] = 'abilities:' . $abilitiesPrefix . '.' . $authorize;
|
||||
} else if ($authorize !== true) {
|
||||
$authMiddleware[] = 'abilities:' . $authorize;
|
||||
}
|
||||
}
|
||||
|
||||
$middleware = array_merge($authMiddleware, self::registerMiddleware($instance->middleware), $middleware);
|
||||
$route = Route::{Str::lower($instance->httpMethod)}(
|
||||
$routePrefix . $instance->route,
|
||||
[$className, $method]
|
||||
)->middleware(array_unique($middleware));
|
||||
|
||||
if (!empty($instance->where)) {
|
||||
$route->where($instance->where);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取中间件
|
||||
* @param $middleware
|
||||
* @return string[]
|
||||
*/
|
||||
private static function registerMiddleware($middleware): array
|
||||
{
|
||||
if(empty($middleware)) {
|
||||
return [];
|
||||
}
|
||||
if(is_array($middleware)) {
|
||||
return $middleware;
|
||||
}
|
||||
if (is_string($middleware)) {
|
||||
return [$middleware];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
namespace Modules\AnnoRoute;
|
||||
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class RouteServiceProvider extends ServiceProvider
|
||||
{
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind(AnnoRoute::class, AnnoRouteService::class);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user