## 仓库 - [hyperf_rbac_framework_server_ctexthuang](https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git) - git远程仓库地址 ## 特性 - **最新技术栈**:使用 PHP8.3/hyperf3.1/swoole5.1.4/phpredis 6.0.2 等后端前沿技术开发 ## 文档 [文档地址 Github](https://hyperf.wiki/3.1/) ## 前序准备 - [php8.3](https://www.php.net/) 和 [git](https://git-scm.com/) - 项目开发环境 - [swoole](https://www.swoole.com/) - 熟悉 swoole 特性 - [php8.3](https://www.php.net/) - 熟悉 php 基础语法 - [hyperf](https://hyperf.wiki/3.1/) - 熟悉 `hyperf` 基本语法 ## 安装和使用 - 安装 swoole 和 phpredis 扩展 ``` 自行搜索安装教程 ``` - 获取代码 ```bash git clone https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git ``` - vendor ```bash composer install ``` - 运行 ```bash cp .env.example .env vim .env php bin/hyperf.php start ``` - command 函数 ```bash #框架自有 php bin/hyperf.php + 以下 gen:amqp-consumer Create a new amqp consumer class gen:amqp-producer Create a new amqp producer class gen:aspect Create a new aspect class gen:class Create a new class gen:command Create a new command class gen:constant Create a new constant class gen:controller Create a new controller class gen:job Create a new job class gen:kafka-consumer Create a new kafka consumer class gen:listener Create a new listener class gen:middleware Create a new middleware class gen:migration Generate a new migration file gen:model Create new model classes. gen:nats-consumer Create a new nats consumer class gen:nsq-consumer Create a new nsq consumer class gen:process Create a new process class gen:repository Create a new repository class gen:request Create a new form request class gen:resource create a new resource gen:seeder Create a new seeder class gen:service Create a new service class #新增命令 php bin/hyperf.php gen:service LoginService php bin/hyperf.php gen:repository OssRepository ``` ## Git 贡献提交规范 - `feat` 新功能 - `fix` 修补 bug - `docs` 文档 - `style` 格式、样式(不影响代码运行的变动) - `refactor` 重构(即不是新增功能,也不是修改 BUG 的代码) - `perf` 优化相关,比如提升性能、体验 - `test` 添加测试 - `build` 编译相关的修改,对项目构建或者依赖的改动 - `ci` 持续集成修改 - `chore` 构建过程或辅助工具的变动 - `revert` 回滚到上一个版本 - `workflow` 工作流改进 - `mod` 不确定分类的修改 - `wip` 开发中 - `types` 类型 ## 日志(合理安排) | 分组名称 | 用途 | 日志级别 | 保留天数 | 备注 | |---------|---------|------------|------|----------| | app | 应用业务日志 | DEBUG/INFO | 7 | 主要业务逻辑日志 | | error | 错误日志 | ERROR | 30 | 只记录错误 | | cache | CACHE日志 | DEBUG | 3 | 开发调试用 | | request | 请求访问日志 | INFO | 15 | 记录所有请求 | | cron | 定时任务日志 | INFO | 30 | 定时任务执行记录 | | payment | 支付相关日志 | INFO | 90 | 重要财务数据 | | audit | 审计日志 | INFO | 365 | 重要操作记录 |\ ```php //注入这个类 use App\Lib\Log\Logger; $this->logger->cache()->error(...), ``` ## 缓存 ```php //注入这个类 use App\Cache\Redis\RedisCache $this->redis->with($poolName)->exists($key) //$poolName 配置在 config/autoload/redis.php 在 default下面追加即可 看官网 //lua调用涉及多文件请看示例 $this->redis->with($poolName ?? 'default')->lua(RateLimit::class)->check($argument); //lua()里面是App\Cache\Redis\Lua\*文件 后面跟的方法是 该文件的方法 //我做了返回类型补全 可以直接IDE跳转查看参数 ``` ## tips 1.AdminService类必须继承BaseAdminService ```php //例子 app/Service/Admin/AdminUser/UserService class UserService extends \App\Service\Admin\BaseAdminService { } //由于在 app/Controller/Admin/AdminUserController 中 service 是 注解注入的 所以 BaseAdminService只会实例化一次(单例) class AdminUserController extends AbstractController { /** * @var UserService */ #[Inject] protected UserService $service; /** * @return array */ #[RequestMapping(path: "getInfo", methods: "GET")] public function getInfo(): array { return $this->service->handle(); } } //所以在service中获取上下文的数据必须重置获取而不能存入BaseService属性中拿取 //假设在 Api目录中写 BaseApiService请务必注意 class UserService extends \App\Service\Admin\BaseAdminService { /** * @param string $name * @return \current_admin_id|mixed */ public function __get(string $name) { if ($name === 'adminId') return Context::get('current_admin_id',0); if (!property_exists($this, $name)) throw new ErrException('属性未定义'); return $this->$name; } } class UserService extends BaseAdminService{ public function handle() { return $this->adminId; } } // 或者在controller中实例化去调用 class AdminUserController extends AbstractController { /** * @return array */ #[RequestMapping(path: "getInfo", methods: "GET")] public function getInfo(): array { return (new UserService)->handle(); } } ``` 2.controller必须增加ResponseFormat注解 ```php //示例 : app/Controller/Admin/AdminUserController #[Controller(prefix: "admin/adminUser")] #[ResponseFormat('admin')] #[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)] #[Middleware(middleware: PermissionMiddleware::class, priority: 99)] class AdminUserController extends \App\Controller\AbstractController{ } //因为在涉及到公有抛出 ErrException或者 验证器抛出 的时候 会根据不同的注解 返回不同的 Return class BaseErrExceptionHandler extends ExceptionHandler{ public function handle() { // 从注解获取响应格式(优先于路径解析) $format = $this->request->getAttribute('response_format') ?? $this->repairResponseFormatByPath(); // 动态选择策略 $returnClass = match ($format) { 'admin', 'common' => AdminReturn::class, 'api' => ApiReturn::class, default => null, }; } } // 通过切面存入 class ResponseFormatAspect extends AbstractAspect { // 获取注解定义的格式 $annotation = $proceedingJoinPoint->getAnnotationMetadata()->class[ResponseFormat::class] ?? $proceedingJoinPoint->getAnnotationMetadata()->method[ResponseFormat::class] ?? null; if ($annotation) { // 将注解格式存入请求属性(覆盖中间件的默认值) $request = $proceedingJoinPoint->arguments['request'] ?? null; if ($request instanceof Request) { $request->withAttribute('response_format', $annotation->format); } } } ``` 3.token的使用要分模块 ```php //示例 app/Service/Admin/Login/LoginService use App\Service\BaseTokenService $tokenService class LoginService extends \App\Service\Admin\BaseAdminService{ public function handle() { $jwtHandle = $this->tokenService->setJwt('admin')->getJwt(); return $this->adminReturn->success('success',[ 'access_token' => $jwtHandle->builderAccessToken((string) $adminInfo->id)->toString(), 'refresh_token' => $jwtHandle->builderRefreshToken((string) $adminInfo->id)->toString(), 'expire_at' => (int) $jwtHandle->getConfig('ttl', 0), ]); } } //setJwt函数里面类似$poolName 设置在 config/autoload/jwt.php 未设置属性可复用 default 设置 ``` 4.引入 Repository层架构 解放 model层压力 model 只管理数据模型和关联 ```php //详细请看app/Common/Repository 文件下的文件 示例 app/Service/Admin/Login/LoginService class LoginService extends \App\Service\Admin\BaseAdminService{ /** * 需要提前注入 * @var AdminUserRepository */ #[Inject] protected AdminUserRepository $userRepository; public function handle() { $adminInfo = $this->userRepository->findByUserName((string)$this->request->input('username')); } } ``` 5.公用类都在 app/Common 下面 包括 `Interface`、`Macros`、`Repository`、`Trait` 6.后台权限注解 #[Permission] 和 #[PermissionMiddleware]