first commit

This commit is contained in:
liu
2026-07-13 15:23:29 +08:00
commit 50885a98c8
473 changed files with 33772 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
<?php
namespace Modules\AnnoRoute;
interface AnnoRoute
{
/**
* register route
*
* @param string $path
* @return void
*/
public function register(string $path): void;
}
+93
View File
@@ -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 = [],
)
{
}
}
+28
View File
@@ -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 = [],
)
{
}
}
+28
View File
@@ -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 = [],
)
{
}
}
+28
View File
@@ -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
)
{
}
}
+84
View File
@@ -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/userMapping 的 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 为 adminMapping 的 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,
]);
}
}
+147
View File
@@ -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);
}
}