likes
comments
collection
share

四 hyperf 的用法总结&apply接口重构

作者站长头像
站长
· 阅读数 65

适时总结下用法,和重构一下,让以后开发时效率更高,减少在细节上过度纠缠

一 migration.

文档 hyperf.wiki/3.0/#/zh-cn…

#新建 
php bin/hyperf.php gen:migration migrationName --create=tableName
#更新
php bin/hyperf.php gen:migration migrationName --table=tableName

#执行迁移.
php bin/hyperf.php migrate

#加字段
$table->string('filed1', 50)->default("xxx");
#改字段
$table->string('name', 50)->change();
#建索引
$table->index(['filed1']);  

二 热重载。

受限cli ,每次改动代码生效要重启容器,这个太麻烦,加个watch处理一下。

//安装
composer require hyperf/watcher --dev

//发布
php bin/hyperf.php vendor:publish hyperf/watcher

//改Dockerfile 的ENTRYPOINT
FROM  swr.cn-south-1.myhuaweicloud.com/docker-study/hyperf:1.0
WORKDIR  /data/project
ENTRYPOINT ["php", "/data/project/api.xuxing.tech/bin/hyperf.php", "server:watch"]
EXPOSE 9501

//记得将原有的docker-compose up 中build 的镜像删掉。

配置文件 .watcher.php

return [
    'driver' => ScanFileDriver::class,
    'bin' => 'php',
    'watch' => [
        'dir' => ['app', 'config'],
        'file' => ['.env'],
        'scan_interval' => 500,
    ],
];

注意

1 删除文件和修改.env需要手动重启才能生效。

2 vendor 中文件变更后 composer dump-autoload -o , 或者直接重启一次。

三 常量,枚举,读配置

文档 hyperf.wiki/3.0/#/zh-cn…

example

//php bin/hyperf.php gen:constant ErrorCode 创建

declare(strict_types=1);

namespace App\Constants;

use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;

#[Constants]
class ErrorCode extends AbstractConstants
{
    /**
     * @Message("Server Error!")
     */
    const SERVER_ERROR = 500;

    /**
     * @Message("系统参数错误")
     */
    const SYSTEM_INVALID = 700;
}

//用法
echo ErrorCode::SYSTEM_INVALID;
echo ErrorCode::getMessage(ErrorCode::SERVER_ERROR);

控制器响应,封装一个code 方法

return $this->code(ErrorCode::SYSTEM_INVALID, $data);

读配置

hyperf.wiki/3.0/#/zh-cn…)

# 1 .env 文件和config 文件中配置 
# 2 使用
$val = env('KEYNAME');  //不存在返回 null
$val = env('KEYNAME',  1);  //不存在返回 1

$val = config('key_name');

//通过 #[Value] 注解获取配置 碰到坑了。代码就几行,照着写,不出效果,懒得排这个框架问题,换个用法即可。

四 request & response

4.1 将 request , response 对象注入。

use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;

class XxController {
    #[Inject]
    protected RequestInterface $request;

    #[Inject]
    protected ResponseInterface $response;

4.2 request 对象用法.

4.2.1 route

# 1 配置。
Router::get('/v1/test/{id}', 'App\Controller\TestController::index');
# 2 获取
# 获取route.

class TestController extends AbstractController
{
    public function index()
    {
        // 存在则返回,不存在则返回默认值 0
        $id = $this->request->route('id', 0);
        return ["id" => $id];
    }
}
# 3 测试
curl 127.0.0.1/v1/test/3
{"id":"3"}

4.2.2 获取query 参数

// 存在则返回,不存在则返回 null
$name = $request->query('name');
// 存在则返回,不存在则返回默认值 Hyperf
$name = $request->query('name', 'Hyperf');
// 不传递参数则以关联数组的形式返回所有 Query 参数
$name = $request->query();

4.2.3 获取post 表单数组。

$name = $request->input('products.0.name');
$names = $request->input('products.*.name');

4.2.4 获取postJson

// 存在则返回,不存在则返回 null
$name = $request->input('user.name');
// 存在则返回,不存在则返回默认值 Hyperf
$name = $request->input('user.name', 'Hyperf');
// 以数组形式返回所有 Json 数据
$name = $request->all();

4.3 response

返回数组,就响应json 了。

五 redis 用法。

#创建 redis 对象。
$redis    = $this->container->get(\Redis::class);
#然后直接用
$redis->get("xxx"); 
$redis->setex("aaa", 1, "value")

六 数据库相关用法。

6.1 引入

use Hyperf\DbConnection\Db;

6.2 事务

    Db::beginTransaction();
    try{
        //code here
        Db::commit();
    } catch(\Throwable $ex){
        return $this->code(ErrorCode::ERROR, ["ex" => $ex->getMessage()]);
        Db::rollBack();
    }

6.3 常用的insert ,update

           $applyData = [
                'mobile' => $mobile,
                'org_name' => $org_name,
                "contact" => $contact,
                "remark" => $remark,
                "status" => Enum::APPLY_STATUS_PENDING,
                "created_at" => time(),
                "updated_at" => time(),
            ];
            $apply_id = Db::table('apply')->insertGetId( $applyData );


 Db::table('apply')->where('id', $apply_id)->update(['status' => Enum::APPLY_STATUS_OK]);

多个条件 。
where([
    ['status', '=', '1'],
    ['gender', '=', '1'],
])

6.4 取数据

//单行。
$apply_row = Db::table('apply')->where('id', $apply_id)->first();
//多行 (注意是对象集)
$users = Db::table('user')->get();

//如果需要为数组,添加文件 App/Listener/FetchModeListener
<?php
declare(strict_types=1);

namespace App\Listener;

use Hyperf\Database\Events\StatementPrepared;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use PDO;

#[Listener]
class FetchModeListener implements ListenerInterface
{
    public function listen(): array
    {
        return [
            StatementPrepared::class,
        ];
    }

    
    public function process(object $event):void
    {
        if ($event instanceof StatementPrepared) {
            $event->statement->setFetchMode(PDO::FETCH_ASSOC);
        }
    }
}

//paste 官网代码时  这行报红。 照抄一下其它例子。
public function process(object $event):  


一般不用delete .

七 重构 v1/apply 接口。

7.1现有代码 分析。

public function apply()
{

    $postData = $this->request->all();

    $this->validCc($postData);

    //获取数据,并校验参数。
    $mobile = $this->request->input('mobile');
    if($mobile == null) {
        return $this->code(ErrorCode::APPLY_LOCK_PARAMS);
    }

    $org_name = $this->request->input('org_name');
    if($org_name == null) {
        return $this->code(ErrorCode::APPLY_LOCK_PARAMS);
    }

    $contact = $this->request->input('contact');
    if($contact == null) {
        return $this->code(ErrorCode::APPLY_LOCK_PARAMS);
    }

    $remark = $this->request->input('remark');

    //判断是否申请过
    $has_apply = Db::table('apply')->where(
       [
            ['status', '=', Enum::APPLY_STATUS_PENDING],
            ['mobile', '=', $mobile],
        ]
    )->exists();

    if($has_apply) {
        return $this->code(ErrorCode::APPLY_REPEAT);
    }

    $has_user =  Db::table('user')->where(
        [
            ['mobile', '=', $mobile],
        ]
    )->exists();

    if($has_user) {
        return $this->code(ErrorCode::APPLY_USER_EXIST);
    }

    Db::beginTransaction();
    try{
        //组装 apply 数据。
        $applyData = [
            'mobile' => $mobile,
            'org_name' => $org_name,
            "contact" => $contact,
            "remark" => $remark,
            "status" => Enum::APPLY_STATUS_PENDING,
            "created_at" => time(),
            "updated_at" => time(),
        ];
        $apply_id = Db::table('apply')->insertGetId( $applyData );

        //开启自动审核后
        if (config("apply_auto_audit")) {
            $org_data = [
               "tname" => $org_name,
               "remark" => $remark,
               "status" => Enum::ORG_STATUS_OK,
               "created_at" => time(),
               "updated_at" => time(),
            ];
            $org_id = Db::table('org')->insertGetId( $org_data );

            $userData =[
                'tname' => $contact,
                "pwd" => md5('123456'),
                "status" => Enum::USER_STATUS_OK,
                "mobile" => $mobile,
                "cur_org_id" => $org_id,
                "cur_staff_id" => 0,
                "last_login_at" => time(),
                "created_at" => time(),
                "updated_at" => time(),
            ];
            Db::table('user')->insertGetId( $userData );

            Db::table('apply')->where('id', $apply_id)->update(['status' => Enum::APPLY_STATUS_OK]);

        }

        Db::commit();
    } catch(\Throwable $ex){
        return $this->code(ErrorCode::ERROR, ["ex" => $ex->getMessage()]);
        Db::rollBack();
    }
    return ['code' => ErrorCode::SUCCESS, "msg" => 'apply success'];
}

分析后有如下问题。

  1. valid 校验,代码有点肿,抽离一下,将意图与实现分离

  2. 开启自动审核使用apply 生效的业务 ,需要被封装一下,以后后台审核时用得上.

7.2 valid 部分重构。

代码调整。


   private function getValidCode()
    {
        $mobile = $this->request->input('mobile');
        $org_name = $this->request->input('org_name');
        $contact = $this->request->input('contact');
        if($mobile == null || $org_name == null || $contact == null) {
            return ErrorCode::APPLY_LOCK_PARAMS;
        }

        //判断是否申请过
        $has_apply = Db::table('apply')->where(
            [
                ['status', '=', Enum::APPLY_STATUS_PENDING],
                ['mobile', '=', $mobile],
            ]
        )->exists();

        if($has_apply) {
           return ErrorCode::APPLY_REPEAT;
        }

        $has_user =  Db::table('user')->where(
            [
                ['mobile', '=', $mobile],
            ]
        )->exists();
        if($has_user) {
            return ErrorCode::APPLY_REPEAT;
        }
    }

		
    public function apply()
    {

        $postData = $this->request->all();

        $this->validCc($postData);

        //获取数据,并校验参数。
        $code = $this->getValidCode();
        if($code != ErrorCode::SUCCESS) {
            return $this->code($code);
        }
      
        //收集数据
        $mobile = $this->request->input('mobile');
        $org_name = $this->request->input('org_name');
        $contact = $this->request->input('contact');
        $remark = $this->request->input('remark');
        

用postman 测一下(漏参,重复注册) 通过。

注意一个原则 ,重构时,步子要小(控制影响) , 并且可测。

7.3 将审核生效业务抽到applyService 中去。

<?php
namespace App\Service;

use App\Constants\Enum;
use App\Constants\ErrorCode;
use Hyperf\DbConnection\Db;

class UserService
{
    public function applyApproved(int $apply_id)
    {
        $apply_row = Db::table('apply')->where(
            [
                ['id', '=',  $apply_id],
                ['status', '=',  Enum::APPLY_STATUS_PENDING],
            ]
        )->first();

        if(empty($apply_row)) {
            return ErrorCode::APPLY_NOT_EXIST;
        }


        $org_name  = $apply_row['org_name'];
        $remark    = $apply_row['remark'];
        $contact   = $apply_row['contact'];
        $mobile    = $apply_row['mobile'];
        $org_data  = [
            "tname"      => $org_name,
            "remark"     => $remark,
            "status"     => Enum::ORG_STATUS_OK,
            "created_at" => time(),
            "updated_at" => time(),
        ];
        $org_id    = Db::table('org')->insertGetId($org_data);

        $userData = [
            'tname'         => $contact,
            "pwd"           => md5('123456'),
            "status"        => Enum::USER_STATUS_OK,
            "mobile"        => $mobile,
            "cur_org_id"    => $org_id,
            "cur_staff_id"  => 0,
            "last_login_at" => time(),
            "created_at"    => time(),
            "updated_at"    => time(),
        ];
        Db::table('user')->insertGetId($userData);

        Db::table('apply')->where('id', $apply_id)->update(['status' => Enum::APPLY_STATUS_OK]);

        return ErrorCode::SUCCESS;
    }
}

考虑到代码不多,之前也单测过, 觉得这里不测也能过,偷一步懒。 回测时发现有问题,再来调这里。

测试这事,没有绝对的对于错,改两行,就走一轮测试 ,和改很多行再测,都不好,这个要实践中,和自己对代码的把握度去不断调整权衡。

将service 注入

use App\Service\UserService;

class ApplyController extends AbstractController
{

    #[Inject]
    protected UserService $userService;

改业务代码 。

...
//开启自动审核后
if (config("apply_auto_audit")) {
   $code =   $this->userService->applyApproved($apply_id);
   if($code != ErrorCode::SUCCESS) {
       Db::rollBack();
       return $this->code($contact);
   }
}
....

再次测试 一下接口。

lucky ,一次过了,写applyService 偷懒没单测成功。

7.4 created_at,updated_at 处理。

这两字段,很多余的感觉,包装一下。

//组装 apply 数据。
$applyData = [
    "created_at" => time(),
    "updated_at" => time(),
    
];

7.4.1 建个service

<?php
namespace App\Service;

class DataHeplerService
{
    public function decorateDateFiled($data)
    {
        if(!isset($data['created_at'])) {
            $data['created_at'] = time();
        }
        if(!isset($data['updated_at'])) {
            $data['updated_at'] = time();
        }
        return $data;
    }
}

7.4.2 使用时,注入再装饰。

            //组装 apply 数据。
            $applyData = [
                'mobile' => $mobile,
                'org_name' => $org_name,
                "contact" => $contact,
                "remark" => $remark,
                "status" => Enum::APPLY_STATUS_PENDING,
            ];
            $apply_id = Db::table('apply')->insertGetId( $dataHelper->decorateDateFiled($applyData) );

用着还是觉得别扭。其实用法为

$apply_id = DbHelper::insertWithDate($tableName, $data);

7.4.3 添加DbHepler

顺带也包一下 insert .(当不需要created_at,updated_at)

<?php
namespace App\Service;

use Hyperf\DbConnection\Db;

class DbHelper
{
    #[Inject]
    protected DataHeplerService $dataHeplerService;

    public function insertWithDate($tableName, $data)
    {
        $data = $this->dataHeplerService->decorateDateFiled($data);
        return Db::table($tableName)->insertGetId($data);
    }


    public function insert($tableName, $data)
    {
        return Db::table($tableName)->insertGetId($data);
    }

}

7.4.4 业务代码调整

//ApplyController
//组装 apply 数据。
$applyData = [
'mobile' => $mobile,
'org_name' => $org_name,
"contact" => $contact,
"remark" => $remark,
"status" => Enum::APPLY_STATUS_PENDING,
];

$apply_id = $this->dbHelper->insertWithDate("apply",$applyData);

//ApplyService

$org_name  = $apply_row['org_name'];
$remark    = $apply_row['remark'];
$contact   = $apply_row['contact'];
$mobile    = $apply_row['mobile'];
$org_data  = [
    "tname"      => $org_name,
    "remark"     => $remark,
    "status"     => Enum::ORG_STATUS_OK,
];
$org_id    =  $this->dbHelper->insertWithDate("org", $org_data);

$userData = [
    'tname'         => $contact,
    "pwd"           => md5('123456'),
    "status"        => Enum::USER_STATUS_OK,
    "mobile"        => $mobile,
    "cur_org_id"    => $org_id,
    "cur_staff_id"  => 0,
    "last_login_at" => time(),
];
$this->dbHelper->insertWithDate("user", $userData);


8 重构后,最终代码。

ApplyController

<?php

declare(strict_types=1);
/**
 *
 * @Author xuxing
 * @description 机构申请接口. (apply_auto_audit 打开后,自动生效)
 */

namespace App\Controller;

use App\Constants\Enum;
use App\Constants\ErrorCode;
use Hyperf\DbConnection\Db;
use App\Service\UserService;
use App\Service\DbHelper;

class ApplyController extends AbstractController
{

    #[Inject]
    protected UserService $userService;

    #[Inject]
    protected DbHelper $dbHelper;
    /**
     * 机构申请.
     * @return array|string[]
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function apply()
    {

        $postData = $this->request->all();

        $this->validCc($postData);

        //获取数据,并校验参数。
        $code = $this->getValidCode();
        if($code != ErrorCode::SUCCESS) {
            return $this->code($code);
        }

        //收集数据
        $mobile = $this->request->input('mobile');
        $org_name = $this->request->input('org_name');
        $contact = $this->request->input('contact');
        $remark = $this->request->input('remark');


        Db::beginTransaction();
        try{
            //组装 apply 数据。
            $applyData = [
                'mobile' => $mobile,
                'org_name' => $org_name,
                "contact" => $contact,
                "remark" => $remark,
                "status" => Enum::APPLY_STATUS_PENDING,
            ];

            $apply_id = $this->dbHelper->insertWithDate("apply",$applyData);

            //开启自动审核后
            if (config("apply_auto_audit")) {
               $code =   $this->userService->applyApproved($apply_id);
               if($code != ErrorCode::SUCCESS) {
                   Db::rollBack();
                   return $this->code($contact);
               }
            }
            Db::commit();
        } catch(\Throwable $ex){
            return $this->code(ErrorCode::ERROR, ["ex" => $ex->getMessage()]);
            Db::rollBack();
        }
        return ['code' => ErrorCode::SUCCESS, "msg" => 'apply success'];
    }

    //请求参数,与业务规则校验。
    private function getValidCode()
    {
        $mobile = $this->request->input('mobile');
        $org_name = $this->request->input('org_name');
        $contact = $this->request->input('contact');
        if($mobile == null || $org_name == null || $contact == null) {
            return ErrorCode::APPLY_LOCK_PARAMS;
        }

        //判断是否申请过
        $has_apply = Db::table('apply')->where(
            [
                ['status', '=', Enum::APPLY_STATUS_PENDING],
                ['mobile', '=', $mobile],
            ]
        )->exists();

        if($has_apply) {
           return ErrorCode::APPLY_REPEAT;
        }

        $has_user =  Db::table('user')->where(
            [
                ['mobile', '=', $mobile],
            ]
        )->exists();
        if($has_user) {
            return ErrorCode::APPLY_REPEAT;
        }
    }
}

applyService

<?php

namespace App\Service;

use App\Constants\Enum;
use App\Constants\ErrorCode;

use Hyperf\DbConnection\Db;
class ApplyService
{
    #[Inject]
    protected DbHelper $dbHelper;

    public function applyApproved(int $apply_id)
    {

        $apply_row = Db::table('apply')->where(
            [
                ['id', '=',  $apply_id],
                ['status', '=',  Enum::APPLY_STATUS_PENDING],
            ]
        )->first();

        if(empty($apply_row)) {
            return ErrorCode::APPLY_NOT_EXIST;
        }


        $org_name  = $apply_row['org_name'];
        $remark    = $apply_row['remark'];
        $contact   = $apply_row['contact'];
        $mobile    = $apply_row['mobile'];
        $org_data  = [
            "tname"      => $org_name,
            "remark"     => $remark,
            "status"     => Enum::ORG_STATUS_OK,
        ];
        $org_id    =  $this->dbHelper->insertWithDate("org", $org_data);

        $userData = [
            'tname'         => $contact,
            "pwd"           => md5('123456'),
            "status"        => Enum::USER_STATUS_OK,
            "mobile"        => $mobile,
            "cur_org_id"    => $org_id,
            "cur_staff_id"  => 0,
            "last_login_at" => time(),
        ];
        $this->dbHelper->insertWithDate("user", $userData);
        Db::table('apply')->where('id', $apply_id)->update(['status' => Enum::APPLY_STATUS_OK]);
        return ErrorCode::SUCCESS;
    }
}

顺眼多了,接着去带娃。

转载自:https://juejin.cn/post/7247926910500339749
评论
请登录