ligan/rx-easyswoole-tools

rx easyswoole tools

This package's canonical repository appears to be gone and the package has been frozen as a result.

v2.0.0 2023-09-16 09:20 UTC

README

easyswoole公共部分封装工具

1.安装

composer require ligan/rx-easyswoole-tools

或者comoser.json文件中添加

"ligan/rx-easyswoole-tools": "^1.0"

2.框架使用

2.1 配置

在App目录下创建 Configs, Enums,Service,Process,Crontab目录。

  • Configs: 用于配置文件,如系统,sms,push,mq等,可以参考包里面的配置
  • Enums: 用于配置系统的枚举,比如返回码
  • Service:服务类
  • Process:进程
  • Crontab:计划任务

测试数据库

CREATE TABLE `test` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT '',
  `create_at` datetime DEFAULT NULL,
  `update_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  `delete_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;

2.2 初始化

EasySwooleEvent.php

<?php

namespace EasySwoole\EasySwoole;

use EasySwoole\EasySwoole\AbstractInterface\Event;
use EasySwoole\EasySwoole\Swoole\EventRegister;
use RX\Event\GlobalEvent;

class EasySwooleEvent implements Event
{
    public static function initialize()
    {
        GlobalEvent::mysql();
        GlobalEvent::redis();
    }

    public static function mainServerCreate(EventRegister $register)
    {
        $process = [];
        GlobalEvent::process($process);

        $tasks = [];
        GlobalEvent::task($tasks);
    }
}

这样就可以启动服务了~

php easyswoole server start

2.3 创建模型

可以在系统创建一个基类 BaseModel.php ,其他的模型继承即可。

<?php

declare(strict_types=1);

namespace App\Model;

use RX\Core\CoreModel;

class BaseModel extends CoreModel
{
}

例子

<?php
declare(strict_types=1);

namespace App\Model;

class TestModel extends BaseModel
{

}
?>

2.4 创建服务

<?php

namespace App\Service;

use App\Model\TestModel;
use RX\Core\CoreService;

class TestService extends CoreService
{
    public static function add(array $params)
    {
        return TestModel::create()->add(["id" => $params["id"]],TestEnum::class);
    }

    public static function edit(array $params)
    {
        return TestModel::create()->whereDB(["id" => $params["id"]])->edit(["type" => $params["type"]],TestEnum::class);
    }

    public static function detail(array $params, string $fields)
    {
        return TestModel::create()->whereDB(["id" => $params["id"]])->field($fields)->find();
    }

    public static function delete(array $params)
    {
        return TestModel::create()->setStatus(["id" => $params["id"]],2,TestEnum::class);
    }

    public static function getList(array $params, string $fields)
    {
        return TestModel::create()->whereDB(["user_id" => $params["user_id"]])->field($fields)->select();
    }

    public static function getListPage(array $params, string $fields)
    {
        return TestModel::create()->whereDB(["user_id" => $params["user_id"]])->field($fields)->paginate(1, 10);
    }

}

2.5 创建控制器

<?php

namespace App\HttpController;

use App\Service\TestService;
use RX\Core\CoreController;

class Index extends CoreController
{

    public function delete()
    {
        $rt = TestService::delete(["id" => 1]);
        $this->success("ok", $rt);
    }

    public function add()
    {
        $rt = TestService::add(["user_id" => 1]);
        $this->success("ok", $rt);
    }

    public function edit()
    {
        $rt = TestService::edit(["id" => 1, "type" => 1111]);
        $this->success("ok", $rt);
    }

    public function detail()
    {
        $rt = TestService::detail(["id" => 1],"id,name");
        $this->success("ok", $rt);
    }

    public function getList()
    {
        $rt = TestService::getList(["user_id" => 1],"id,name");
        $this->success("ok", $rt);
    }

    public function getListPage()
    {
        $rt = TestService::getListPage(["user_id" => 1],"id,name");
        $this->success("ok", $rt);
    }
}

继承了 CoreController 可以调用很多封装好的方法,如: getParams()获取请求接口的参数。

3.短信

3.1 阿里云

$obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::ALIYUN,$config = [])->send("18151768346", "签名", "SMS_142147233", ["code" => rand(1000, 9999)]);

3.2 腾讯云

$obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::TENCENT,$config = [])->send("18151768346", "签名", 175944, [rand(1000, 9999), 5]);

3.3 聚合

$obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::JUHE,$config = [])->send("18151768346", "", 241626, ["code" => rand(1000, 9999)]);

3.4 梦网

$config = [
    "host"     => "",
    "userId"   => "",
    "password" => "",
    "content"  => ""
];
$obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::MW,$config)->send("18151768346", "", "");

3.5 红豆

$config  = [
    "url"       => "/sms/batch/v1",
    "appKey"    => "xxx",
    "appCode"   => "xxx",
    "appSecret" => "xxxx",
];
$content = "测试 hello";
$r       = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::HD, $config)->send("18151768346", "【瑞祥集团】", $content);
var_dump($r);

4.推送

4.1 jpush

$data = array(
    'platform' => "winphone",
    'audience' => "9999999999999999xxxxxx",
    //自定义,透传消息
    'message'  => array(
        "msg_content" => "",
    ),
);
$obj = \RX\Component\Push\PushStaticFactory::factory(PushType::JPush,$config=[])->push($data);

4.2 个推

$data = [
    "scene"    => "场景",
    "request_id"   => time() . uniqid(),
    "settings"     => [
        "ttl" => 3600000
    ],
    "audience"     => [
        "cid" => [
            "xxx"
        ]
    ],
    "push_message" => [
        "notification" => [
            "title"      => "请填写标题",
            "body"       => "请填写内容",
            "click_type" => "url",
            "url"        => "https://www.json.cn/"
        ]
    ]
];
$obj  = \RX\Component\Push\PushStaticFactory::factory(PushType::GETUI,$config=[])->push($data);

5.Redis

RedisCache::set("gan", 123456);
RedisCache::get("gan");
RedisCache::lRange("list",0,10);

更多用法看RedisCache类文件。

6.XlsWriter

# 导入
XlsWriter::import("./1.xlsx");

# 普通导出
$header = [
    "name" => "姓名",
    "age"  => "年龄"
];
$data   = [
    [
        "name" => "test",
        "age"  => 11,
    ],
    [
        "name" => "哈哈",
        "age"  => 30,
    ]
];
XlsWriter::normalExport($header, $data);

# 自定义导出
$header = [
    "name" => "姓名",
    "age"  => "年龄",
    "tel"  => "电话"
];

$data = [
    [
        "name" => "test",
        "age"  => 11,
        "tel"  => "18112345678"
    ],
    [
        "name" => "哈哈",
        "age"  => 30,
        "tel"  => "13112344321"
    ],
    [
        "name" => "哈哈2",
        "age"  => 30,
        "tel"  => "13112344321"
    ]
];

//  将header放在头部
array_unshift($data, $header);

$styleData['column'][] = Xlswriter::setColumnStyle('A:C', 20, 'thin');
$mergeData[]           = Xlswriter::setMergeStyle('A1:C1', "我是居中合并", 'thin');
XlsWriter::DiyExport($header, $data, $mergeData, $styleData);

7.上传

7.1 本地存储

# request为es的request对象
  \RX\Component\Upload\UploadStaticFactory::factory(UploadType::LOCAL,$config = [])->uploadFile([
    "request" => $this->request(),
]);

7.2 OSS

7.2.1 STS模式

去阿里云sts服务获取临时的token,返回给前端,前端根据返回的token和临时accessKeyId等信息进行上传操作。

$config = [
    "accessKeyId"  => "",
    "accessSecret" => "",
    "bucket"       => "",
    "roleArn"      => "acs:ram::.........",
    "domain"       => "",
    "region"       => "",
    "endpoint"     => ""
];
\RX\Component\Upload\UploadStaticFactory::factory(UploadType::OSS, $config)->stsData();

7.2.2 文件上传

去阿里云sts服务获取临时的token,返回给前端,前端根据返回的token和临时accessKeyId等信息进行上传操作。

$config = [
    "accessKeyId"  => "",
    "accessSecret" => "",
    "bucket"       => "",
    "roleArn"      => "acs:ram::.........",
    "domain"       => "",
    "region"       => "",
    "endpoint"     => ""
];
$p = [
    "object"   => "composer-" . time() . ".json",
    "filePath" => "./composer.json",
];
\RX\Component\Upload\UploadStaticFactory::factory(UploadType::OSS, $config)->uploadFile($p);

7.3 COS

7.3.1 STS模式

$config = [
    "secretId"  => "secretId",
    "secretKey" => "secretKey",
    "bucket"    => "bucket",
    "domain"    => "",
    "region"    => "ap-shanghai",
];
$rt     = \RX\Component\Upload\UploadStaticFactory::factory(\RX\Component\Upload\UploadType::COS, $config)->stsData();
var_dump($rt);

7.3.2 文件上传

$rt2 = \RX\Component\Upload\UploadStaticFactory::factory(\RX\Component\Upload\UploadType::COS, $config)->uploadFile([
    "object"   => "test.php",
    "filePath" => "test.php"
]);
var_dump($rt2["Location"]);

8.消息队列

8.1 RabbitMQ

rabbitmq的安装和使用我们这边不过阐述。 生产者

public function rabbitMQ()
{
    $data = [
        "queueName"  => "test",
        "message"   => [
            "time" => DateHelper::getMicroTime(),
            "id"   => time()
        ],
        "messageId" => (string)time()
    ];
    $mq   = (new RabbitMQFactory())->createMQ();
    $mq->send($data);
    $mq->close();
    $timeout = 5;
    $result  = null;
    while ($timeout) {
        $result = RedisCache::get($data["messageId"]);
        if (!empty($result)) {
            break;
        }
        $timeout -= 0.01;
        \co::sleep(0.01);
    }
    $this->success("ok", $result);
}


上面的用法是5秒同步等待mq给返回,利用redis来通讯,也可以使用rpc。

消费端进程

$mq = (new RabbitMQFactory())->createMQ();
$mq->listen(['queueName' => "test"], function (AMQPMessage $msg) {
    $messageId = $msg->get_properties()['message_id'];
    try {
        $payload = $msg->getBody();
        $params  = json_decode($payload, true);
        var_dump($params);
        RedisCache::set($messageId, "listen-{$messageId}-" . time(), 60);
        $msg->getChannel()->basic_ack($msg->getDeliveryTag());
    } catch (\Throwable $th) {
        var_dump($th->getMessage());
    }
});

例子用的是同步等待,这样性能肯定是很低的,tps也上不去的,建议使用异步模式,就是send进去直接返回成功,然后通过前端主动轮训模式来查询状态。消费端最好与前端的规范即可。

延迟队列

生产

try {
    $config = [
        "host"     => "rabbitmq",
        "port"     => 5672,
        "username" => "",
        "password" => "",
        "vhost"    => "/"
    ];
    $mq     = (new \RX\Component\MQ\RabbitMQFactory($config))->createMQ();

    //  定义交换机
    $mq->exchangeDeclare('delay', 'x-delayed-message', true, false, ["x-delayed-type" => ["S", "topic"]]);

    $mq->queueDeclare('delay_queue', true, false);

    $mq->queueBind("delay_queue", "delay", "delay_queue");

    $message = $mq->AMQPMessage('hello world' . time(), [
        'application_headers' => $mq->AMQPTable([
            'x-delay' => 5000
        ])
    ]);

    $mq->publish($message, 'delay', 'delay_queue');

    $mq->close();

} catch (\Exception $exception) {
    echo "异常信息" . $exception->getMessage();
}

消费

$config = [
    "host"     => "rabbitmq",
    "port"     => 5672,
    "username" => "",
    "password" => "",
    "vhost"    => "/"
];
$mq     = (new \RX\Component\MQ\RabbitMQFactory($config))->createMQ();

$mq->setDefaultType("x-delayed-message")
   ->listen(['queueName' => 'delay_queue', 'exchangeName' => "delay"], function (\PhpAmqpLib\Message\AMQPMessage $msg) {
       try {
           $payload = $msg->getBody();
           var_dump($payload . '---' . time());
           $msg->getChannel()->basic_ack($msg->getDeliveryTag());
       } catch (\Throwable $th) {
           var_dump($th->getMessage());
       }
   });

$mq->close();

8.2 Redis Stream

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

消息队列相关命令:

XADD - 添加消息到末尾
XTRIM - 对流进行修剪,限制长度
XDEL - 删除消息
XLEN - 获取流包含的元素数量,即消息长度
XRANGE - 获取消息列表,会自动过滤已经删除的消息
XREVRANGE - 反向获取消息列表,ID 从大到小
XREAD - 以阻塞或非阻塞方式获取消息列表

消费者组相关命令:

XGROUP CREATE - 创建消费者组
XREADGROUP GROUP - 读取消费者组中的消息
XACK - 将消息标记为"已处理"
XGROUP SETID - 为消费者组设置新的最后递送消息ID
XGROUP DELCONSUMER - 删除消费者
XGROUP DESTROY - 删除消费者组
XPENDING - 显示待处理消息的相关信息
XCLAIM - 转移消息的归属权
XINFO - 查看流和消费者组的相关信息;
XINFO GROUPS - 打印消费者组的信息;
XINFO STREAM - 打印流信息

生产者

public function redisMQ()
{
    $data   = [
        "key"     => "redisMQ",
        "message" => [
            "time"      => DateHelper::getMicroTime(),
            "id"        => time(),
            "messageId" => "redisMQ" . time()
        ]
    ];
    $mq     = (new RedisMQFactory())->createMQ();
    $result = $mq->send($data);
    $this->success("ok", $result);
}

消费端进程

$mq       = (new RedisMQFactory())->createMQ();
$stream   = "redisMQ";
$consumer = "c0";
$group    = "test";

$mq->init([
    "stream"  => $stream,
    "group"   => $group,
    'message' => ["type" => "init"]
]);

Timer::getInstance()->loop(1000, function () use ($mq, $group, $consumer, $stream) {
    $mq->listen([
        'group'    => $group,
        "consumer" => $consumer,
        "stream"   => $stream
    ], function ($result) use ($group, $stream) {
        if (!empty($result)) {
            foreach ($result[$stream] as $id => $value) {
                RedisCache::xAck($stream, $group, [$id]);
            }
        }
    });
});

redis stream有个很麻烦的点就是必须要先创建组(针对消费组模式),不然如果程序启动的时候,没有key,没有group的话,会报错。解决方案是先创建一个消息,初始化组,然后执行。

9.其他助手

  • LoggerHelper.php 日志
  • DateHelper.php 时间
  • FileHelper.php 文件
  • FormatHelper.php 格式化
  • PasswordHelper.php 密码
  • RandomHelper.php 随机数
  • RegularHelper.php 正则
  • StringHelper.php 字符串
  • ArrayHelper.php 数据

日志例子:

$path = "/path/1.log";
$log = new LoggerHelper($path);
$log->error("error");
$log->debug("debug");
$log->warning("warning");
$log->notice("notice");
$log->info("info");
$log->alert("alert");

具体可查看类文件实现。

10.PDO包(断线重连)

原:https://gitee.com/ligan0404/easy-db

composer require ligan/easy-db

本次包命名进行了整合,二者不可兼容。

10.1 配置

$config = array(
    'host'       => "127.0.0.1",
    'port'       => 3306,
    'database'   => 'tpshop',
    'username'   => 'root',
    'password'   => '123456',
    'charset'    => 'utf8mb4',
    'unixSocket' => null,
    'options'    => [
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ],
    'size'       => 10
);
$db     = new \RX\Component\DB\EasyPdo\EasyPdo($config,"master");

10.2 查询

// 单条
$db->get("ccb_test", "*");

// 多条
$db->query("select * from ccb_test limit 5")->fetchAll();
$db->select("ccb_test", "*", ["LIMIT" => 10]);

10.3 新增

$db->insert("ccb_test", ["user_id" => 1, "type" => 1]);

10.4 编辑

$db->update("ccb_test", ["address" => 1],["id"=>1]);

10.5 删除

$db->delete("ccb_test", ["id" => 4005]);

具体更多的操作方法可参考官方文档:https://medoo.lvtao.net/

11.Redis包

11.1 配置

$conf  = [
    'host'     => 'localhost',
    'port'     => 6379,
    'auth'     => '',
    'db_index' => 0,
    'time_out' => 3,
    'size'     => 10,
];
$redis = new \RX\Component\DB\EasyRedis\EasyRedis($conf, "master");

11.2 SET

$redis->set("test",123456);

11.3 GET

$redis->get("test");

11.4 TTL

$redis->ttl("test");

11.5 HMSET

$redis->HMSET("MS",["id"=>1,"name"=>'1']);

11.6 HGETALL

$redis->HGETALL("MS");

11.7 LPUSH

$redis->LPUSH("li",time());

11.8 LPOP

$redis->LPOP("li");

更多的命令使用查看官方文档:https://www.redis.com.cn/commands.html

12.云打印

12.1 易联云

$config = [
    "client_id"     => "client_id",
    "client_secret" => "client_secret",
];


$cacheConfig = new \RX\Component\CloudPrint\Cache\CacheConfig();
$cacheConfig->setDriver(\RX\Component\CloudPrint\Driver\RedisDriver::class);
$cache       = new \RX\Component\CloudPrint\Cache\Cache($cacheConfig);

\RX\Component\CloudPrint\CloudPrintStaticFactory::factory(CloudPrintType::YI_LIAN_YUN, $config, $cache)->print([
    "machine_code" => "打印机编号",
    "content"      => "打印内容(需要urlencode)",
    "origin_id"    => "商户系统内部订单号,要求32个字符内,只能是数字、大小写字母 ,且在同一个client_id下唯一。详见商户订单号"
]);

// 如内容格式如下:
$content = '';
$content .= '<FS><center>8号桌</center></FS>';
$content .= str_repeat('-',32);
$content .= '<FS><table>';
$content .= '<tr><td>商品</td><td>数量</td><td>价格</td></tr>';
$content .= '<tr><td>土豆回锅肉</td><td>x1</td><td>¥20</td></tr>';
$content .= '<tr><td>干煸四季豆</td><td>x1</td><td>¥12</td></tr>';
$content .= '<tr><td>苦瓜炒蛋</td><td>x1</td><td>¥15</td></tr>';
$content .= '</table></FS>';
$content .= str_repeat('-',32)."\n";
$content .= '<FS>金额: 47元</FS>';

12.2 飞鹅云

$config = [
    "user" => "user",
    "ukey" => "ukey",
];

\RX\Component\CloudPrint\CloudPrintStaticFactory::factory(CloudPrintType::FEI_E_YUN, $config, null)->print([
    "sn"      => "打印机编号",
    "content" => "打印内容,不能超过5000字节",
    "times"   => "打印次数,默认:1"
]);

13.Etcd

go(function () {
    try {
        $client = (new \RX\Component\Etcd\EtcdFactory(["pretty" => true]))->createClient();
        $rt     = $client->get("/apisix/upstreams/401127401666380483");
        $rt     = $client->getKeysWithPrefix("/apisix/upstreams");
        $rt = $client->compaction(100, true);
        var_dump($rt);
    } catch (Throwable $e) {
        var_dump($e->getMessage());
    }
});