# rx-easyswoole-tools **Repository Path**: yvtang/rx-easyswoole-tools ## Basic Information - **Project Name**: rx-easyswoole-tools - **Description**: 用于easyswoole框架的常用组件封装 - **Primary Language**: PHP - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: http://www.zjwoo.com - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2023-02-21 - **Last Updated**: 2023-02-21 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # rx-easyswoole-tools easyswoole公共部分封装工具 ## 1.安装 ```shell composer require ligan/rx-easyswoole-tools ``` 或者`comoser.json`文件中添加 ```shell "ligan/rx-easyswoole-tools": "^1.0" ``` ## 2.框架使用 ### 2.1 配置 在App目录下创建 `Configs`, `Enums`,`Service`,`Process`,`Crontab`目录。 - Configs: 用于配置文件,如系统,sms,push,mq等,可以参考包里面的配置 - Enums: 用于配置系统的枚举,比如返回码 - Service:服务类 - Process:进程 - Crontab:计划任务 **测试数据库** ```mysql 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 ``` ### 2.4 创建服务 ```php 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 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 阿里云 ```php $obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::ALIYUN,$config = [])->send("18151768346", "签名", "SMS_142147233", ["code" => rand(1000, 9999)]); ``` ### 3.2 腾讯云 ```php $obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::TENCENT,$config = [])->send("18151768346", "签名", 175944, [rand(1000, 9999), 5]); ``` ### 3.3 聚合 ```php $obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::JUHE,$config = [])->send("18151768346", "", 241626, ["code" => rand(1000, 9999)]); ``` ### 3.4 梦网 ```php $config = [ "host" => "", "userId" => "", "password" => "", "content" => "" ]; $obj = \RX\Component\Sms\SmsStaticFactory::factory(\RX\Component\Sms\SmsType::MW,$config)->send("18151768346", "", ""); ``` ## 4.推送 ### 4.1 jpush ```php $data = array( 'platform' => "winphone", 'audience' => "9999999999999999xxxxxx", //自定义,透传消息 'message' => array( "msg_content" => "", ), ); $obj = \RX\Component\Push\PushStaticFactory::factory(PushType::JPush,$config=[])->push($data); ``` ### 4.2 个推 ```php $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 ```php RedisCache::set("gan", 123456); RedisCache::get("gan"); RedisCache::lRange("list",0,10); ``` 更多用法看RedisCache类文件。 ## 6.XlsWriter ```php # 导入 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 本地存储 ```php # 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等信息进行上传操作。 ```php $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等信息进行上传操作。 ```php $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模式 ```php $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 文件上传 ```php $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的安装和使用我们这边不过阐述。 生产者 ```php 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。 消费端进程 ```php $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进去直接返回成功,然后通过前端主动轮训模式来查询状态。消费端最好与前端的规范即可。 **延迟队列** 生产 ```php 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(); } ``` 消费 ```php $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 - 打印流信息 生产者 ```php 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); } ``` 消费端进程 ```php $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 数据 日志例子: ```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 ```php composer require ligan/easy-db ``` > 本次包命名进行了整合,二者不可兼容。 ### 10.1 配置 ```php $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 查询 ```php // 单条 $db->get("ccb_test", "*"); // 多条 $db->query("select * from ccb_test limit 5")->fetchAll(); $db->select("ccb_test", "*", ["LIMIT" => 10]); ``` ### 10.3 新增 ```php $db->insert("ccb_test", ["user_id" => 1, "type" => 1]); ``` ### 10.4 编辑 ```php $db->update("ccb_test", ["address" => 1],["id"=>1]); ``` ### 10.5 删除 ```php $db->delete("ccb_test", ["id" => 4005]); ``` > 具体更多的操作方法可参考官方文档:https://medoo.lvtao.net/ ## 11.Redis包 ### 11.1 配置 ```php $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 ```php $redis->set("test",123456); ``` ### 11.3 GET ```php $redis->get("test"); ``` ### 11.4 TTL ```php $redis->ttl("test"); ``` ### 11.5 HMSET ```php $redis->HMSET("MS",["id"=>1,"name"=>'1']); ``` ### 11.6 HGETALL ```php $redis->HGETALL("MS"); ``` ### 11.7 LPUSH ```php $redis->LPUSH("li",time()); ``` ### 11.8 LPOP ```php $redis->LPOP("li"); ``` 更多的命令使用查看官方文档:https://www.redis.com.cn/commands.html ## 12.云打印 ### 12.1 易联云 ```php $config = [ "client_id" => "client_id", "client_secret" => "client_secret", ]; $cacheConfig = new \RX\Component\CloudPrint\Cache\CacheConfig(\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下唯一。详见商户订单号" ]); ``` ### 12.2 飞鹅云 ```php $config = [ "user" => "user", "ukey" => "ukey", ]; \RX\Component\CloudPrint\CloudPrintStaticFactory::factory(CloudPrintType::FEI_E_YUN, $config, null)->print([ "sn" => "打印机编号", "content" => "打印内容,不能超过5000字节", "times" => "打印次数,默认:1" ]); ``` ## 13.Etcd ```php 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()); } }); ```