hyperf AppExceptionHandler

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Util\Response;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use function Hyperf\Support\env;

class AppExceptionHandler extends ExceptionHandler
{
    public function __construct(protected StdoutLoggerInterface $logger)
    {

    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        if(env('APP_ENV')!="production"){
            $format =  Response::fail(500,$throwable->getMessage(),$throwable->getTrace());
        }else{
            $format =  Response::fail(intval(500),"系统错误~");
        }

        return $response->withHeader('created-by', 'xiang')->withStatus(200)->withBody(new SwooleStream(json_encode($format)));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}

xiang 发布于  2024-8-24 23:11 

hyperf框架 redis延时队列

DelayedJobs

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Util;

use Hyperf\Context\ApplicationContext;
use Hyperf\Redis\Redis;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use RedisException;

class DelayedJobs
{
    const KEY_RESEND="xiang_delay_queue";
    /**
     * @return false|int|\Redis
     * @throws ContainerExceptionInterface
     * @throws NotFoundExceptionInterface
     * @throws RedisException
     */
    public function add(string $queue_key, int $delay_seconds, array $task)
    {
        $container = ApplicationContext::getContainer();

        $redis = $container->get(Redis::class);

        $timestamp = time() + $delay_seconds;
        return $redis->zAdd($queue_key, $timestamp, json_encode($task));
    }
}

xiang 发布于  2024-8-24 22:55 

hyperf框架 基础功能

BusinessException

<?php

declare(strict_types=1);
/**
 * This file is part of MineAdmin.
 *
 * @link     https://www.mineadmin.com
 * @document https://doc.mineadmin.com
 * @contact  root@imoi.cn
 * @license  https://github.com/mineadmin/MineAdmin/blob/master/LICENSE
 */

namespace App\Exception;

use App\Constants\ErrorCode;
use Hyperf\Server\Exception\ServerException;

class BusinessException extends ServerException
{
    public function __construct(int $code = 0, ?string $message = null, ?\Throwable $previous = null)
    {
        if (is_null($message)) {
            $message = ErrorCode::getMessage($code);
        }

        parent::__construct($message, $code, $previous);
    }
}

BusinessExceptionHandler

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Exception\BusinessException;
use Hyperf\Codec\Json;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class BusinessExceptionHandler extends ExceptionHandler
{
    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        // 判断被捕获到的异常是希望被捕获的异常
        if ($throwable instanceof BusinessException) {
            // 格式化输出
            $format = [
                'code' => $throwable->getCode(),
                'msg' => $throwable->getMessage(),
                'data' => [],
            ];

            $this->stopPropagation();

            return $response->withHeader('Server', 'MineAdmin')
                ->withHeader('Access-Control-Allow-Origin', '*')
                ->withHeader('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS')
                ->withHeader('Access-Control-Allow-Credentials', 'true')
                ->withHeader('Access-Control-Allow-Headers', 'accept-language,authorization,lang,uid,token,Keep-Alive,User-Agent,Cache-Control,Content-Type')
                ->withAddedHeader('content-type', 'application/json; charset=utf-8')
                ->withStatus(200)->withBody(new SwooleStream(Json::encode($format)));
        }

        // 交给下一个异常处理器
        return $response;
        // 或者不做处理直接屏蔽异常
    }

    /**
     * 判断该异常处理器是否要对该异常进行处理.
     */
    public function isValid(Throwable $throwable): bool
    {
        return $throwable instanceof BusinessException;
    }
}

AppExceptionHandler

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Exception\Handler;

use App\Logger;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class AppExceptionHandler extends ExceptionHandler
{
    public function __construct(protected StdoutLoggerInterface $logger)
    {
    }

    public function handle(Throwable $throwable, ResponseInterface $response)
    {
        Logger::info("error",sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
        Logger::info("error",$throwable->getTraceAsString());

        $format = [
            'code' => 500,
            'msg' => "服务器系统错误",
            'data' => [],
        ];

        return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream(json_encode($format)));
    }

    public function isValid(Throwable $throwable): bool
    {
        return true;
    }
}

Response

<?php

declare(strict_types=1);
/**
 * This file is part of Hyperf.
 *
 * @link     https://www.hyperf.io
 * @document https://hyperf.wiki
 * @contact  group@hyperf.io
 * @license  https://github.com/hyperf/hyperf/blob/master/LICENSE
 */

namespace App\Util;

use App\Constants\ErrorCode;

class Response
{
    public static function success(array|object|string $data = []): array
    {
        return [
            'code' => 200,
            'msg' => '成功',
            'data' => $data,
        ];
    }

    public static function fail(int $code = 500, string $msg = "", array|object|string $data = []): array
    {
        if (!$msg) {
            $msg = ErrorCode::getMessage($code);
        }

        return [
            'code' => $code,
            'msg' => $msg,
            'data' => $data,
        ];
    }
}

xiang 发布于  2024-8-24 22:52 

php随机生成字符串

function generateRandomString($length) {
    $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
    $randomString = '';
    for ($i = 0; $i < $length; $i++) {
        $randomString .= $characters[rand(0, strlen($characters) - 1)];
    }
    return $randomString;
}
  function generateRandomChineseString($length) {
        $string = '';
        $characters = '阿啊哎哀唉埃挨癌矮艾爱碍安氨俺岸按案暗昂凹熬傲奥澳八巴叭吧拔把坝爸罢霸白百柏摆败拜班般颁斑搬板版办半伴扮瓣邦帮膀傍棒包胞宝饱保堡报抱豹暴爆卑杯悲碑北贝备背倍被辈奔本崩逼鼻比彼笔币必毕闭辟碧蔽壁避臂边编蝙鞭扁便变遍辨辩标表别宾滨冰兵丙柄饼并病拨波玻剥播脖伯驳泊勃博搏膊薄卜补捕不布步部擦猜才材财裁采彩踩菜蔡参餐残蚕惨灿仓苍舱藏操曹槽草册侧测策层叉插查茶察差拆柴缠产阐颤昌长肠尝偿常厂场畅倡唱抄超巢朝潮吵炒车扯彻撤尘臣沉陈闯衬称趁撑成呈承诚城乘惩程橙吃池驰迟持匙尺齿斥赤翅充冲虫崇抽仇绸愁筹酬丑瞅臭出初除厨础储楚处触川穿传船喘串窗床晨创吹垂锤春纯唇醇词瓷慈辞磁雌此次刺从匆葱聪丛凑粗促催脆翠村存寸措错搭达答打大呆代带待袋逮戴丹单担胆旦但诞弹淡蛋氮当挡党荡刀导岛倒蹈到盗道稻得德的灯登等邓凳瞪低堤滴迪敌笛底抵地弟帝递第颠典点电店垫淀殿雕吊钓调掉爹跌叠蝶丁叮盯钉顶订定丢东冬懂动冻洞都斗抖陡豆督毒读独堵赌杜肚度渡端短段断锻堆队对吨敦蹲盾顿多夺朵躲俄鹅额恶饿鳄恩儿而尔耳二发乏伐罚阀法帆番翻凡烦繁反返犯泛饭范贩方坊芳防妨房肪仿访纺放飞非啡菲肥废沸肺费分纷芬坟粉份奋愤粪丰风枫封疯峰锋蜂冯逢缝凤奉佛否夫肤孵弗伏扶服浮符幅福辐蝠抚府辅腐父付妇负附复赴副傅';
        $charLength = mb_strlen($characters, 'UTF-8');
        for ($i = 0; $i < $length; $i++) {
            $string .= mb_substr($characters, rand(0, $charLength - 1), 1, 'UTF-8');
        }
        return $string;
    }

xiang 发布于  2024-8-24 18:06 

hyperf日志log配置

'hipc_todolist_update' => [
        'handler' => [
            'class' => Monolog\Handler\StreamHandler::class,
            'constructor' => [
                'stream' => BASE_PATH . '/runtime/logs/rabbitmq/hipc_todolist_update.log',
                'level' => Monolog\Logger::INFO,
            ],
        ],
        'formatter' => [
            'class' => Monolog\Formatter\LineFormatter::class,
            'constructor' => [
                'format' => null,
                'dateFormat' => 'Y-m-d H:i:s',
                'allowInlineLineBreaks' => true,
            ],
        ],
    ],

xiang 发布于  2024-8-22 23:51 

hyperf pest单元测试 使用容器

test('addClientGroup', function () {
    \App\System\Model\SystemUser::truncate();
    $container = \Hyperf\Context\ApplicationContext::getContainer();
    $res = $container->get(ClientService::class)->addClientGroup(0,1,1);

    expect($res->client_user_id)->toEqual(1);
});

测试保护方法

 $container = \Hyperf\Context\ApplicationContext::getContainer();
    // 使用反射获取受保护的方法
    $method = new ReflectionMethod(ClientService::class, 'addClientGroup');

    // 调用受保护的方法
    $res = $method->invoke($container->get(ClientService::class), 1, 1, 2);

    expect($res->client_user_id)->toEqual(2);
    expect($res->group_id)->toEqual(1);
    expect($res->is_boss)->toEqual(0);

测试私有静态方法

test('addClientGroup2', function () {
    \App\System\Model\SystemUser::truncate();

    $container = \Hyperf\Context\ApplicationContext::getContainer();
    // 使用反射获取受保护的方法
    $method = new ReflectionMethod(ClientService::class, 'addClientGroup');
    $res = $method->invokeArgs($container->get(ClientService::class), [1, 1, 2]);
    expect($res->client_user_id)->toEqual(2);
    expect($res->group_id)->toEqual(1);
    expect($res->is_boss)->toEqual(0);
});

xiang 发布于  2024-8-22 17:24 

CloudProjectModel

<?php

declare(strict_types=1);

namespace App\Model;

use Hyperf\Database\Model\SoftDeletes;
use Hyperf\DbConnection\Model\Model;
use Hyperf\ModelCache\Cacheable;

class CloudProjectModel extends Model
{
    use Cacheable;

    use SoftDeletes;

    /**
     * The table associated with the model.
     */
    protected ?string $table = 'cloud_project';

    /**
     * The attributes that are mass assignable.
     */
    protected array $fillable = [];

    /**
     * The attributes that should be cast to native types.
     */
    protected array $casts = [];

}

xiang 发布于  2024-8-14 19:36 

hyperf mysql数据库连接数公式

MySQL_connections = (worker_nums + task_worker_nums + custom process nums) * pool.max_connections

http服务worker_nums数量

自定义进程数量

task_worker_nums数量加起来的和乘以 连接池最大连接数pool.max_connections

'pool' => [
            'min_connections' => 1,
            'max_connections' => 10,
            'connect_timeout' => 10.0,
            'wait_timeout' => 3.0,
            'heartbeat' => -1,
            'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
        ],

xiang 发布于  2024-8-10 16:38 

hyperf路由写不规范,导致验证器的场景无效

Router::get('/index/index', '\App\Controller\IndexController@index');

  protected array $scenes = [
        'index' => ['username'],
        'bar' => ['username', 'password'],
    ];

导致scenes不成功

解决办法

Router::get('/index/index', 'App\Controller\IndexController@index');

App前不能加"\"


xiang 发布于  2024-8-5 16:03