前言
在结合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使用教程相关推荐

  1. thinkphp6+swoole websocket使用教程自研路线不建议使用

    转载请注明: 藏羚骸的博客~thinkphp6+swoole websocket使用教程自研路线不建议使用. 介绍 对于think-swoole网上资料五花八门,根据网上资料,我成功走上了岔路口,但是 ...

  2. Swoole Framework 入门教程(1)

    Swoole Framework入门教程1 简介 Swoole为广大php 程序员带来了福音, 用一句话说 重新定义PHP, 底层用c扩展实现,配合PHP7 性能不弱于 golang ,并且还可以脱离 ...

  3. 卸载nginx php mysql_centos7中配置nginx+php-fpm+swoole+mysql环境教程

    centos7在数据中心服务器中使用较为广泛,为了方便用户配置环境,本文介绍了在centos7系统下部署nginx+php-fpm+swoole+mysql环境的详细步骤. 一.运行nginx 1.新 ...

  4. swoole php 使用教程,Swoole 扩展安装与使用入门

    Swoole 扩展安装与使用入门 由 学院君 创建于2年前, 最后更新于 1年前 版本号 #3 37642 views 13 likes 5 collects Swoole 概述 Swoole 是面向 ...

  5. windows下php swoole扩展,PHP安装Swoole Loader扩展教程,适用于Windows和Linux

    看到百度很多安装扩展还需要下载Cygwin的,所以特别推出这个教程说明一下,PHP安装Swoole Loader扩展是不需要安装Cygwin,看着网络中充斥着很多不负责任的安装教程顿时觉得有些可笑.或 ...

  6. ThinkPhp6框架快速入门教程

    项目介绍 一款 PHP 语言基于 ThinkPhp6.x.Layui.MySQL等框架精心打造的一款模块化.插件化.高性能的前后端分离架构敏捷开发框架,可用于快速搭建前后端分离后台管理系统,本着简化开 ...

  7. easywechat php例子,thinkphp6使用easywechat笔记!

    公众号端基本配置 image.png 公众号端设置 image.png 域名要备案,文件下载上传至tp6的public目录下 image.png composer require overtrue/w ...

  8. Swoole Framework 入门教程(2)-默认路由方式以及GSF扩展路由方式

    Swoole Framework默认路由方式 swoole 框架默认支持的非正则路由方式 有三种 /page/index?a=1 /page/index/a-1 ?c=page&v=index ...

  9. swoole 连接mysql_swoole教程:用swoole4操作mysql连接池之读写分离

    为什么要读写分离? 一般的系统都是读多写少,利用读写分离,可以提升mysql的效率 读写分离后,从库可以水平扩展 下面我们开始代码之旅吧 配置先改造: $config = [ 'host'=> ...

最新文章

  1. 计算机维护常识_系统篇
  2. MySQL检查冗余索引代码
  3. python是什么公司开发的软件-python适合开发桌面软件吗?
  4. 磁盘显示执行页内操作时的错误要如何找到资料
  5. 算法:多数元素,多种解法
  6. JavaScript学习笔记-JSON对象
  7. 2016经典微小说:《轮回》
  8. python怎样实现界面的切换_python tkinter实现界面切换的示例代码
  9. LeetCode 5381. 查询带键的排列
  10. Ubuntu,安装最新版的GCC
  11. php array 插值,PHP中的关联数组的插值(双引号字符串)
  12. Javarscipt中数组或者字符串的随机排序方法
  13. 三星S3 939/9300 android 4.3 如何打开开发者模式
  14. const T 与T const的比较(const T vs.T const的翻译 Dan Saks)
  15. 如何判断自己IP是内网IP还是外网IP
  16. word2vec使用说明
  17. 使用theano进行深度学习实践(一)
  18. 2023年度流行色出炉终于轮到火龙果和草莓熊制霸天下了 优漫动游
  19. 为TextView控件的文字内容添加中划线、下划线方法
  20. 朋友圈的权限研究、最后有个实现朋友圈的实现的推测(全网最全)

热门文章

  1. 如何完美解决catia出现-运行异常,单击“确定终止”-问题
  2. 浅析Python中signal包的使用
  3. 如何写好一份前端简历
  4. 使用ESP8266通过Blinker平台接入天猫精灵控制电视/空调
  5. 基于Spring+SpringMVC+MyBatis博客系统的开发教程(十六)
  6. SQL PLUS命令使用大全(转,特有用)
  7. 对话英特尔副总裁Erez Dagan:自动驾驶引擎盖下的秘密!|《新程序员》
  8. 视频插帧—学习笔记(算法+配置+云服务+Google-Colab)
  9. Python 读取Excel地点名称通过百度地图获取行政区划信息
  10. 示波器基本原理1:模拟示波器