2025-09-18 17:26:45 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-18 17:26:45 +08:00
2025-09-12 15:23:08 +08:00
2025-09-17 17:18:18 +08:00
2025-09-12 15:23:08 +08:00
2025-09-14 22:33:32 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-17 17:18:18 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-12 15:23:08 +08:00
2025-09-17 17:18:18 +08:00

仓库

特性

  • 最新技术栈:使用 PHP8.3/hyperf3.1/swoole5.1.4/phpredis 6.0.2 等后端前沿技术开发

文档

文档地址 Github

前序准备

  • php8.3git - 项目开发环境
  • swoole - 熟悉 swoole 特性
  • php8.3 - 熟悉 php 基础语法
  • hyperf - 熟悉 hyperf 基本语法

安装和使用

  • 安装 swoole 和 phpredis 扩展
自行搜索安装教程
  • 获取代码
git clone https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git
  • vendor
composer install
  • 运行
cp .env.example .env

vim .env

php bin/hyperf.php start
  • command 函数
#框架自有 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 重要操作记录
//注入这个类
use App\Lib\Log\Logger;

$this->logger->cache()->error(...),

缓存

//注入这个类
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

//例子 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注解

//示例 :  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的使用要分模块

//示例 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 只管理数据模型和关联

//详细请看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 下面 包括 InterfaceMacrosRepositoryTrait

6.后台权限注解 #[Permission] 和 #[PermissionMiddleware]

Description
No description provided
Readme MIT 303 KiB
Languages
PHP 98.6%
Dockerfile 1.2%
Lua 0.2%