ThinkPHP6+swoole+easywechat使用教程
前言
在结合think-swoole+easywechat扩展使用的时候,需要考虑curl兼容swoole携程问题,request兼容swoole框架,因为easywechat底层还是通过$_POST或者其他来获取请求参数。
还有就是好多的接口基本没有。需要自己写,因为这里安装的是5.0的版本。在6.0版本后easywecaht不在写操作接口的相关逻辑只提供了一些授权后的接口封装、请求封装、日志封装等等。个人还是觉得5.0版本够用了。然后就选择了5.0的版本来开发。5.0版本中例如,直播这块的接口逻辑需要自己写点、企业微信进群配置这些等等。下面我们就看详细的实例教程:
安装
安装think-swoole
composer require topthink/think-swoole
安装easywechat
composer require overtrue/wechat:~5.0 -vvv
使用前配置
请在app/AppService.php的boot方法内增加配置默认请求类
use Yurun\Util\Swoole\Guzzle\SwooleHandler; DefaultHandler::setDefaultHandler(SwooleHandler::class);
例如这里实例化一个企业微信相关的
use EasyWeChat\Work\Application;
use Yurun\Util\Swoole\Guzzle\SwooleHandler;$type = 'user';$config=['corp_id'=>'','token'=>'',
];//实例化企业微信
$application[$type] = Factory::work($config);
//这里是为了兼容swoole的curl携程
$application[$type]['guzzle_handler'] = SwooleHandler::class;
$request = request();
//在swoole模式运行下,需要从think\request下获取请求信息,这一步十分重要
$application[$type]->rebind('request', new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent()));$this->application[$type]->register(new ServiceProvider());
使用前这些配置都需要增加的。这里也可以封装成类来进行调用
为什么要用type来区分实例化类型:
因为在企业微信下会有多种服务实例化对象,例如客户、自建应用、通讯录都会产生不同的实例化对象
构建企业微信服务首先改造下刚才实例化的方式:
use crmeb\services\wechat\groupChat\ServiceProvider;
use Yurun\Util\Swoole\Guzzle\SwooleHandler;use EasyWeChat\Work\Application;
use Symfony\Component\HttpFoundation\Request;class Work extends BaseApplication
{ /** * @var WorkConfig */protected $config;/** * @var Application[] */protected $application = [];/** * @var string */protected $configHandler;/** * @var string[]*/protected static $property = ['groupChat' => 'external_contact', 'groupChatWelcome' => 'external_contact_message_template'];/** * Work constructor.*/public function __construct(){ /** @var WorkConfig config */ $this->config = app()->make(WorkConfig::class); $this->debug = DefaultConfig::value('logger');}/** * 设置获取配置 * @param string $handler * @return $this */public function setConfigHandler(string $handler){ $this->configHandler = $handler; return $this;}/** * @return Work */public static function instance(){ return app()->make(static::class);}/** * 获取实例化句柄 * @param string $type * @return Application */public function application(string $type = WorkConfig::TYPE_USER){ $config = $this->config->all(); $config = array_merge($config, $this->config->setHandler($this->configHandler)->getAppConfig($type)); if (!isset($this->application[$type])) { $this->application[$type] = Factory::work($config); $this->application[$type]['guzzle_handler'] = SwooleHandler::class; $request = request(); $this->application[$type]->rebind('request', new Request($request->get(), $request->post(), [], [], [], $request->server(), $request->getContent())); $this->application[$type]->register(new ServiceProvider()); } return $this->application[$type];}
}
企业微信服务
这里说明下,swoole里面尽量少用静态方法,而这里使用了的原因是,使用了app->make()实例化了当前类。
use think\Response;
/**
* 服务端
* @return Response
* @throws BadRequestException
* @throws InvalidArgumentException
* @throws InvalidConfigException
* @throws \ReflectionException
*/
public static function serve(): Response
{ $make = self::instance(); $make->application()->server->push($make->pushMessageHandler); $response = $make->application()->server->serve(); return response($response->getContent());
}
首先设置pushMessageHandler类,打开app/AppService.php。在register方法中注册服务器相应事件类 ,例如app\listener\wechat\WorkListener 类引入
use crmeb\services\wechat\config\HttpCommonConfig;
use crmeb\services\wechat\config\LogCommonConfig;
use crmeb\services\wechat\config\WorkConfig;
use app\services\work\WorkConfigServices;public function register()
{//实例化企业微信配置$this->app->bind(WorkConfig::class, function () { return (new WorkConfig(new LogCommonConfig(), $this->app->make(HttpCommonConfig::class)))->setHandler(WorkConfigServices::class);});//企业微信$this->app->bind(Work::class, function () { return (new Work)->setPushMessageHandler(WorkListener::class)->setConfigHandler(WorkConfigServices::class);});
}
一定要配置企业微信服务器相应的事件类WorkListener这里列举出WorkListener类里面事件类型
<?phpnamespace app\listener\wechat;
use app\services\user\label\UserLabelServices;
use app\services\work\WorkClientServices;
use app\services\work\WorkDepartmentServices;
use app\services\work\WorkGroupChatServices;
use app\services\work\WorkMemberServices;
use EasyWeChat\Kernel\Contracts\EventHandlerInterface;/** * 企业微信服务消息处理
* Class WorkListener
* @package app\listener\wechat
*/
class WorkListener implements EventHandlerInterface
{ public function handle($payload = null) { $response = null; switch ($payload['MsgType']) { case 'event': switch ($payload['Event']) { case 'change_contact'://通讯录事件 $this->changeContactEvent($payload); break; case 'change_external_chat'://客户群事件 $this->changeExternalChatEvent($payload); break; case 'change_external_contact'://客户事件 $this->externalContactEvent($payload); break; case 'change_external_tag'://客户标签事件 $this->changeExternalTagEvent($payload); break; case 'batch_job_result'://异步任务完成通知 $this->batchJobResultEvent($payload); break; } break; case 'text'://文本消息 break; case 'image'://图片消息 break; case 'voice'://语音消息 break; case 'video'://视频消息 break; case 'news'://图文消息 break; case 'update_button'://模板卡片更新消息 break; case 'update_template_card'://更新点击用户的整张卡片 break; } return $response; } public function batchJobResultEvent(array $payload) { switch ($payload['JobType']) { case 'sync_user'://增量更新成员 break; case 'replace_user'://全量覆盖成员 break; case 'invite_user'://邀请成员关注 break; case 'replace_party'://全量覆盖部门 break; } } /** * 企业微信通讯录事件 * @param array $payload * @return null */ public function changeContactEvent(array $payload) { $response = null; try { switch ($payload['ChangeType']) { case 'create_user'://新增成员事件 break; case 'update_user'://更新成员事件break;case 'delete_user'://删除成员事件 break; case 'create_party'://新增部门事件 break;case 'update_party'://更新部门事件 break; case 'delete_party'://删除部门事件 break; case 'update_tag'://标签成员变更事件 break; } } catch (\Throwable $e) { \think\facade\Log::error([ 'message' => '企业微信通讯录事件发生错误:' . $e->getMessage(), 'payload' => $payload, 'file' => $e->getFile(), 'line' => $e->getLine() ]); } return $response; } /** * 客户事件
* @param array $payload
* @return |null
*/
public function externalContactEvent(array $payload)
{
$response = null;
try {
switch ($payload['ChangeType']) {
case 'add_external_contact'://添加企业客户事件
/** @var WorkClientServices $make */ $make = app()->make(WorkClientServices::class); $make->createClient($payload);
break; case 'edit_external_contact'://编辑企业客户事件
/** @var WorkClientServices $make */
$make = app()->make(WorkClientServices::class); $make->updateClient($payload); break;
case 'del_external_contact': /** @var WorkClientServices $make */
$make = app()->make(WorkClientServices::class); $make->deleteClient($payload);
break; case 'add_half_external_contact'://外部联系人免验证添加成员事件
break;
case 'del_follow_user'://删除跟进成员事件
/** @var WorkClientServices $make */
$make = app()->make(WorkClientServices::class); $make->deleteFollowClient($payload);
break;
case 'transfer_fail'://客户接替失败事件 break;
} } catch (\Throwable $e) { \think\facade\Log::error([
'message' => '客户事件发生错误:' . $e->getMessage(),
'payload' => $payload,
'file' => $e->getFile(),'line' => $e->getLine()]);}return $response;}/*** 客户群事件* @param array $payload*/public function changeExternalChatEvent(array $payload){try {switch ($payload['ChangeType']) {case 'create'://客户群创建事件break;case 'update'://客户群变更事件break;case 'dismiss'://客户群解散事件break;}} catch (\Throwable $e) {\think\facade\Log::error(['message' => $e->getMessage(),'payload' => $payload,'file' => $e->getFile(),'line' => $e->getLine()]);}}/*** 客户标签事件* @param array $payload*/public function changeExternalTagEvent(array $payload){switch ($payload['ChangeType']) {case 'create'://企业客户标签创建事件break;case 'update'://企业客户标签变更事件break;case 'delete'://企业客户标签删除事件break;case 'shuffle'://企业客户标签重排事件break;}}
}
下面提供了完整的类
BaseApplication类
use crmeb\services\wechat\contract\BaseApplicationInterface;/**
* Class BaseApplication
* @package crmeb\services\wechat
*/
abstract class BaseApplication implements BaseApplicationInterface
{ //app端 const APP = 'app'; //h5端、公众端 const WEB = 'web'; //小程序端 const MINI = 'mini'; //开发平台 const OPEN = 'open'; //pc端 const PC = 'pc';/** * 访问端 * @var string */ protected $accessEnd; /** * @var array */ protected static $property = []; /** * @var string */ protected $pushMessageHandler; /** * Debug * @var bool */ protected $debug = true; /** * 设置消息处理类 * @param string $handler * @return $this */ public function setPushMessageHandler(string $handler) { $this->pushMessageHandler = $handler; return $this; } /** * 设置访问端 * @param string $accessEnd * @return $this */ public function setAccessEnd(string $accessEnd) {if (in_array($accessEnd, [self::APP, self::WEB, self::MINI])) { $this->accessEnd = $accessEnd; } return $this; } /** * 自动获取访问端 * @param \think\Request $request * @return string */ public function getAuthAccessEnd(\think\Request $request) {if (!$this->accessEnd) { try { if ($request->isApp()) { $this->accessEnd = self::APP; } else if ($request->isPc()) { $this->accessEnd = self::PC; } else if ($request->isWechat() || $request->isH5()) { $this->accessEnd = self::WEB; } else if ($request->isRoutine()) { $this->accessEnd = self::MINI; } else { $this->accessEnd = self::WEB; } } catch (\Throwable $e) { $this->accessEnd = self::WEB; } } return $this->accessEnd; } /** * 记录错误日志 * @param \Throwable $e */ protected static function error(\Throwable $e) { static::instance()->debug && \think\facade\Log::error([ 'error' => $e->getMessage(), 'line' => $e->getLine(), ' file' => $e->getFile() ]); } /** * 请求日志 * @param string $message * @param $request * @param $response */ protected static function logger(string $message, $request, $response) { $debug = static::instance()->debug; if ($debug) { \think\facade\Log::info([ 'message' => $message, 'request' => json_encode($request), 'response' => json_encode($response) ]); } } /** * @param $name * @param $arguments * @return mixed */ public static function __callStatic($name, $arguments) { if (in_array($name, array_keys(static::$property))) { $name = static::$property[$name]; return static::instance()->application()->{$name}; } throw new WechatException('方法不存在'); }}BaseApplicationInterface接口类
namespace crmeb\services\wechat\contract;/**
* Interface BaseApplicationInterface
* @package crmeb\services\wechat\contract
*/
interface BaseApplicationInterface
{ /** * @return mixed */ public static function instance(); /** * @return mixed */ public function application();}
最后
如果你觉得这篇文章对你有点用的话,麻烦请给我们的开源项目点点star:http://github.crmeb.net/u/defu不胜感激 !
免费获取源码地址:http://www.crmeb.com
PHP学习手册:https://doc.crmeb.com
技术交流论坛:https://q.crmeb.com
ThinkPHP6+swoole+easywechat使用教程相关推荐
- thinkphp6+swoole websocket使用教程自研路线不建议使用
转载请注明: 藏羚骸的博客~thinkphp6+swoole websocket使用教程自研路线不建议使用. 介绍 对于think-swoole网上资料五花八门,根据网上资料,我成功走上了岔路口,但是 ...
- Swoole Framework 入门教程(1)
Swoole Framework入门教程1 简介 Swoole为广大php 程序员带来了福音, 用一句话说 重新定义PHP, 底层用c扩展实现,配合PHP7 性能不弱于 golang ,并且还可以脱离 ...
- 卸载nginx php mysql_centos7中配置nginx+php-fpm+swoole+mysql环境教程
centos7在数据中心服务器中使用较为广泛,为了方便用户配置环境,本文介绍了在centos7系统下部署nginx+php-fpm+swoole+mysql环境的详细步骤. 一.运行nginx 1.新 ...
- swoole php 使用教程,Swoole 扩展安装与使用入门
Swoole 扩展安装与使用入门 由 学院君 创建于2年前, 最后更新于 1年前 版本号 #3 37642 views 13 likes 5 collects Swoole 概述 Swoole 是面向 ...
- windows下php swoole扩展,PHP安装Swoole Loader扩展教程,适用于Windows和Linux
看到百度很多安装扩展还需要下载Cygwin的,所以特别推出这个教程说明一下,PHP安装Swoole Loader扩展是不需要安装Cygwin,看着网络中充斥着很多不负责任的安装教程顿时觉得有些可笑.或 ...
- ThinkPhp6框架快速入门教程
项目介绍 一款 PHP 语言基于 ThinkPhp6.x.Layui.MySQL等框架精心打造的一款模块化.插件化.高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开 ...
- easywechat php例子,thinkphp6使用easywechat笔记!
公众号端基本配置 image.png 公众号端设置 image.png 域名要备案,文件下载上传至tp6的public目录下 image.png composer require overtrue/w ...
- Swoole Framework 入门教程(2)-默认路由方式以及GSF扩展路由方式
Swoole Framework默认路由方式 swoole 框架默认支持的非正则路由方式 有三种 /page/index?a=1 /page/index/a-1 ?c=page&v=index ...
- swoole 连接mysql_swoole教程:用swoole4操作mysql连接池之读写分离
为什么要读写分离? 一般的系统都是读多写少,利用读写分离,可以提升mysql的效率 读写分离后,从库可以水平扩展 下面我们开始代码之旅吧 配置先改造: $config = [ 'host'=> ...
最新文章
- 计算机维护常识_系统篇
- MySQL检查冗余索引代码
- python是什么公司开发的软件-python适合开发桌面软件吗?
- 磁盘显示执行页内操作时的错误要如何找到资料
- 算法:多数元素,多种解法
- JavaScript学习笔记-JSON对象
- 2016经典微小说:《轮回》
- python怎样实现界面的切换_python tkinter实现界面切换的示例代码
- LeetCode 5381. 查询带键的排列
- Ubuntu,安装最新版的GCC
- php array 插值,PHP中的关联数组的插值(双引号字符串)
- Javarscipt中数组或者字符串的随机排序方法
- 三星S3 939/9300 android 4.3 如何打开开发者模式
- const T 与T const的比较(const T vs.T const的翻译 Dan Saks)
- 如何判断自己IP是内网IP还是外网IP
- word2vec使用说明
- 使用theano进行深度学习实践(一)
- 2023年度流行色出炉终于轮到火龙果和草莓熊制霸天下了 优漫动游
- 为TextView控件的文字内容添加中划线、下划线方法
- 朋友圈的权限研究、最后有个实现朋友圈的实现的推测(全网最全)
热门文章
- 如何完美解决catia出现-运行异常,单击“确定终止”-问题
- 浅析Python中signal包的使用
- 如何写好一份前端简历
- 使用ESP8266通过Blinker平台接入天猫精灵控制电视/空调
- 基于Spring+SpringMVC+MyBatis博客系统的开发教程(十六)
- SQL PLUS命令使用大全(转,特有用)
- 对话英特尔副总裁Erez Dagan:自动驾驶引擎盖下的秘密!|《新程序员》
- 视频插帧—学习笔记(算法+配置+云服务+Google-Colab)
- Python 读取Excel地点名称通过百度地图获取行政区划信息
- 示波器基本原理1:模拟示波器