hashwallet/hyperf-skeleton

一个专注于超高速和灵活的协程框架,特别用于构建微服务和中间件。

dev-main 2022-08-27 09:56 UTC

This package is auto-updated.

Last update: 2024-09-25 06:17:23 UTC


README

基于hyperf 框架封装的骨架

谈谈项目分层架构

如果不想看,直接跳到下面看使用方法

回顾我的开发历史,我经历了几种项目分层

v1.0 controller -> model -> view (MVC)

那时前端是 jQuery + Bootstrap 的天下,也是后端编写前端代码的痛苦时期。拿到前端同事写好的页面后,后端需要自己填写页面数据或通过 AJAX 渲染数据,但页面往往还需要前端再次调整。

那时除了公司定义的代码规范,还会要求“胖模型瘦控制器”。

当然有很多问题,我就不一一列举了,但至少有两点可以赞扬,那就是页面缓存和 SEO。

v2.0 controller -> service -> model

前后端饱受混合编码的折磨,后来就分化出前端使用 AJAX 来对接页面数据,这样各司其职,后端就安心地提供接口。

MSC 和 MVC 类似,只是把 view 换成了 service,把业务逻辑放到服务层去实现

v2.1 controller -> serviceInterface -> serviceImpl -> model

这个变异版本的原因是项目负责人是 Java 转到 PHP 的,把 Java 的一些思想带过来,所以搞得有点不伦不类

这个版本,美其名曰“面向接口开发”。说实话,还不如 MSC 写得简单

2.2 controller -> service -> dao -> model

随着项目业务复杂度的提高,MySQL 无法满足需求,加入了 ES、MongoDB 等其他数据库类型,dao 层也是参照 Java 来的,做了一层数据驱动接口

上述两个版本仍然存在一些问题

  • 在单体应用、多端服务时,在共同使用 service 层后,各种兼容性问题
  • service 层各种依赖注入,蜘蛛网般复杂,还可能出现死循环
  • 接口文档只有请求参数,大部分没有返回参数

当然也有人会说,你给每个端各写一个 service,不就行了,自己控制业务逻辑就可以避免出现死循环,接口文档可以手动编写。马后炮,这是我经历的痛苦

3.0 controller -> logic -> service -> dao -> model

当前这个骨架就是基于此分层,支持多服务、多数据库类型。

logic 层为每个应用的独立业务逻辑层

service 层为公共服务层,serviceInterface 用于定义 RPC

同时定义请求实体和返回实体

请求实体用于验证请求字段,同时过滤不是请求实体的属性字典

返回实体用于实现接口文档返回数据,同时自动翻译字典数据

这个版本很好,就是创建文件有点多,10 多个文件,如果不使用模板生成,会把人写崩溃

接口我也经历了几个版本

  • get,post
  • RESTful API 接口规范
  • 万能 post

当前这个骨架就是使用万能 post,如果不喜欢或不习惯,通过代码生成后,去控制把请求方式修改一下就可以了,对吧。

如何使用

安装

composer create-project hashwallet/hyperf-skeleton:3.1.x-dev demo

当前这个骨架是 hyperf 3.0 版本,php8

代码生成器命令

php bin/hyperf.php gen:code

1,代码生成器是基于数据库表实现的,所以执行此命令之前,先确认一下数据库是否创建了表。如果想使用我二次封装的 model,在表里面需要添加至少 3 个字段

  • enable 是否能使用(类似软删字段)默认为 1
  • create_at 创建时间戳,默认为 0
  • update_at 更新时间戳,默认为 0

2,生成器配置文件在 config/autoload/generate.php

return [
    // 定义应用端
    'applications' => [
        'app',
        'platform',
    ],
    // 是否通过 表名(下划线分割)来生成 ddd 目录结构, 
    'for_table_ddd' => false,
    // 模块,定义模块顺序
    'modules' => [],
];

3,php bin/hyperf.php gen:code --help 查看命令参数

4,会自动生成 CURD 代码,同时会生成一个常量访问接口

目录结构

普通目录

DDD 目录结构

自定义错误字典合并

composer error

项目启动

composer start
    
//  会自动启动 swagger 服务,访问http://127.0.0.1:9501/swagger, 如果不需要 可以再 config/autoload/api_docs.php 关闭

比较常用用法提示

1,枚举

在没有使用 php8.1 的时候官方自带 enum,先使用 marc-mabe/php-enum 封装的枚举类对象

<?php

declare(strict_types=1);

namespace Lengbin\Hyperf\Common\Constants;

use Lengbin\ErrorCode\AbstractEnum;
use Lengbin\ErrorCode\Annotation\EnumMessage;

/**
 * 基础状态
 * @method static BaseStatus FROZEN()
 * @method static BaseStatus NORMAL()
 */
class BaseStatus extends AbstractEnum
{
    /**
     * @Message("禁用")
     */
    #[EnumMessage("禁用")]
    const FROZEN = 0;

    /**
     * @Message("正常")
     */
    #[EnumMessage("正常")]
    const NORMAL = 1;
}


// 使用
    $status = BaseStatus::NORMAL();
    var_dump($status->getValue()); // 获取数字值
    var_dump($status->getMessage()); // 获取关联信息
// 具体用法 查看 `marc-mabe/php-enum` 库

2 BaseObject

/**
 * Class SystemHelpItem.
 */
class SystemHelpItem extends BaseObject
{
    #[ApiModelProperty('ID')]
    public int $id;

    #[ApiModelProperty('名称')]
    public string $name;

    #[ApiModelProperty('名称'), Integer]
    public BaseStatus $status;
}

// 使用
$item = new SystemHelpItem([
    'id' => 1,
    'name' => "demo",
    'status' => 1
]);

  var_dump($item->status->getValue()) // 1
  var_dump($item->toArray()); // ['id' => 1,'name' => "demo", 'status' => 1]

3 自定义注解

use Lengbin\Common\Annotation\EnumView;
use Lengbin\Common\Annotation\ArrayType;

/**
 * Class SystemHelpItem.
 */
class SystemHelpItem extends BaseObject
{
    #[EnumView]
    public BaseStatus $status;
}

// 使用
$item = new SystemHelpItem([
    'status' => 1,
]);

  var_dump($item->toArray()) // ["status" => ["message" => "正常", "value" => 1]]
      
 //   #[ArrayType(type: 'int')]  
 //   public array $item;
 //   等价于
 //   /**
 //    * @var int[]
 //    */
      
 //   #[ArrayType(className: SystemHelpItem::class)]  
 //   public array $item;
 //   等价于
 //   /**
 //    * @var SystemHelpItem[]
 //    */
      

简要说明,暂时到这,后面有问题提 issues,散会