写点什么

ThinkPHP6+swoole+easywechat 使用教程

作者:CRMEB
  • 2022 年 4 月 25 日
  • 本文字数:8733 字

    阅读完需:约 29 分钟

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 类里面事件类型

<?php
namespace 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

用户头像

CRMEB

关注

还未添加个人签名 2021.11.02 加入

CRMEB就是客户关系管理+营销电商系统实现公众号端、微信小程序端、H5端、APP、PC端用户账号同步,能够快速积累客户、会员数据分析、智能转化客户、有效提高销售、会员维护、网络营销的一款企业应用

评论

发布
暂无评论
ThinkPHP6+swoole+easywechat使用教程_CRMEB_InfoQ写作社区