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.
Requires
- php: >=7.4
- ext-bcmath: *
- ext-curl: *
- ext-gd: *
- ext-json: *
- ext-libxml: *
- ext-openssl: *
- ext-simplexml: *
- ext-swoole: >=4.4
- alibabacloud/sdk: ^1.8
- aliyuncs/oss-sdk-php: ^2.4
- easyswoole/http-annotation: ^2.0
- easyswoole/http-client: ^1.5
- easyswoole/orm: ^1.5
- easyswoole/redis: ^1.3
- easyswoole/redis-pool: ^2.2
- php-amqplib/php-amqplib: ^3.1
- psr/simple-cache: ^1.0
- qcloud/cos-sdk-v5: ^2.5
- qcloud_sts/qcloud-sts-sdk: ^3.0
- tencentcloud/sms: ^3.0
- tencentcloud/sts: ^3.0
- viest/php-ext-xlswriter-ide-helper: ^1.3
Requires (Dev)
This package is auto-updated.
Last update: 2024-03-30 02:25:05 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());
}
});