注意:以下操作经过本人在生产环境不完全验证,因为我本身仅仅是一个业务人员,所以涉及到专业的知识性错误欢迎大家补充指正!!!
环境:
1、如果使用的是 hyperf2.x 则 PHP 必须是 8.0.x,因为 hyperf2.x 不支持 8.1 以上,easywechat6.x 不支持 8.0 以下
2、swoole 截止到我测试通过,最新的发布版本 4.8.x 是不支持的,原因是 curl 函数在 swoole 携程化下有 bug,具体的报错可以自行编译测试,总之就是与 easywechat6.x 使用的 symfony/http-client 包中的某些 curl 不兼容,实际上 hyperf 提供了携程的 Guzzle HTTP 客户端但是 easywechat6.x 在调研之初就否定了,参考#2328,然后 6.x 实际上也只封装了核心部分功能,具体业务接口还是需要自己手动写请求,所以如果你 hyperf 非常牛,guzzle 用得也非常 6 完全可以把 6.x 的功能抄过来直接用就好了,这个不在本文的讨论范围。
但是 swoole 的 master 分支编译后可以无缝支持,原因是这些 bug 已经修复了,可以看一下最新的提交记录
已经测试通过的功能:
公众号、开放平台、支付,小程序、企业微信因为业务暂时没有用到暂未测试
原理:跟 5.x 在 hyperf 下使用类似,因为实际上这样的 API 相互调用的 sdk 就是发请求处理响应,而优秀的 easywechat6.x 提供了完全自定义的能力,包括核心的 http 请求客户端,所以你完全可以根据自己的实际需求来替换,当前全都换了她就不是那个她了,哈哈 ~
客户端:es6.x 要求是实现了 Symfony\Contracts\HttpClient\HttpClientInterface 接口的,所以如果你无法升级 swoole 的版本,可以通过替换客户端的方式实现,写一个实现这个接口的类,奈何我不会,幸好 swoole5.x 已经兼容了所以本步骤跳过
请求:hyperf 的请求类跟 es6.x 要求的请求类是实现了同一套接口的,可以直接替换使用且必须替换,否则 es6.x 拿不到请求参数
缓存:hyperf 的缓存同样跟 es6.x 要求的缓存类是实现同一套接口的,可直接使用,建议替换,默认的文件缓存根据 5.x 的经验隔一段时间或者并发较大的情况下或造成缓存错误的问题。
开放平台:
<?php
// $platformModel 是开放平台模型类,简单来说是从数据库中取出来的,如果用配置文件也可以
public function initApplication(PlatformModel $platformModel)
{
// 实例化应用
$application = make(Application::class, [[
'app_id' => $platformModel->app_id,
'secret' => $platformModel->app_secret,
'token' => $platformModel->app_token,
'aes_key' => $platformModel->app_key
]]);
// region 替换请求[必须替换] +++++
$request = ApplicationContext::getContainer()->get(RequestInterface::class);
$application->setRequest($request);
// endregion
// region 替换缓存[可选,建议替换] +++++
$cache = ApplicationContext::getContainer()->get(CacheInterface::class);
$application->setCache($cache);
// endregion
return $application;
}
开放平台代公众号实现业务,这步操作必须要有,原因是开放平台也需要去兑换公众号的应用实例,所以兑换出来的实例也需要替换响应的请求,以下可供参考,需要根据自己的业务修改。
<?php
public function getOfficialApplication(AuthorizeModel $authorizeModel): \EasyWeChat\OfficialAccount\Application
{
$platformModel = $authorizeModel->platform;
$platformApplication = $this->initApplication($platformModel);
$cache = ApplicationContext::getContainer()->get(CacheInterface::class);
$cacheName = md5($platformModel->id.'_'.$authorizeModel->app_id.'_authorizer_access_token');
$authorizerAccessToken = $cache->get($cacheName, '');
if (!$authorizerAccessToken) {
$refreshAuthorizerToken = $platformApplication->refreshAuthorizerToken($authorizeModel->app_id, $authorizeModel->refresh_token);
$authorizerAccessToken = $refreshAuthorizerToken['authorizer_access_token'];
// 写入缓存
$cache->set($cacheName, $authorizerAccessToken, $refreshAuthorizerToken['expires_in']);
}
$officialAccessToken = make(AuthorizerAccessToken::class, [$authorizeModel->app_id, $authorizerAccessToken]);
// 公众号应用
$officialApplication = $platformApplication->getOfficialAccount($officialAccessToken);
// region 替换请求 +++++
$request = ApplicationContext::getContainer()->get(RequestInterface::class);
$officialApplication->setRequest($request);
// endregion
// region 替换缓存 +++++
$officialApplication->setCache($cache);
// endregion
// 设置客户端
$officialApplication->setClient($platformApplication->getClient());
// var_dump($officialApplication->getAccessToken());
// $client = $officialApplication->createClient();
// $officialApplication->setClient($client);
return $officialApplication;
}
公众号:这是直接使用公众号后台配置接口的情况,为了兼容,写了开放平台的东西,如果你完全没用开放平台可以直接替换请求合缓存就能用。
<?php
public function initApplication(OfficialModel $officialModel, PlatformModel $platformModel = null)
{
$authorizeModel = null;
// 如指定开放平台或公众号自身缺少必要属性则尝试开放平台实例
if ($platformModel || !$officialModel->app_secret || !$officialModel->app_token) {
if ($platformModel) {
$authorizeModel = $this->authorizeService->model->where([
['platform_id', '=', $platformModel->id],
['app_id', '=', $officialModel->app_id]
])->firstOrFail();
} else {
$authorizeModel = $this->authorizeService->model->where([
['app_id', '=', $officialModel->app_id]
])->firstOrFail();
}
}
if ($authorizeModel instanceof AuthorizeModel) {
return $this->platformService->getOfficialApplication($authorizeModel);
}
// 实例化应用
$application = make(Application::class, [[
'app_id' => $officialModel->app_id,
'secret' => $officialModel->app_secret,
'token' => $officialModel->app_token,
'aes_key' => $officialModel->app_key,
]]);
// region 替换请求[必须替换] +++++
$request = ApplicationContext::getContainer()->get(RequestInterface::class);
$application->setRequest($request);
// endregion
// region 替换缓存[可选,建议替换] +++++
$cache = ApplicationContext::getContainer()->get(CacheInterface::class);
$application->setCache($cache);
// endregion
return $application;
}
支付:支付仅测试通过 v2,暂未测试 v3,如有问题我会补充
<?php
public function initApplication(MerchantModel $merchantModel)
{
$application = make(Application::class, [[
// 商户号
'mch_id' => $merchantModel->mch_id,
// 商户证书
'certificate' => BASE_PATH.'/cert/'.$merchantModel->mch_id.'/apiclient_cert.pem',
'private_key' => BASE_PATH.'/cert/'.$merchantModel->mch_id.'/apiclient_key.pem',
// v2 API 密钥
'v2_secret_key' => $merchantModel->pay_key,
// v3 API 密钥
'secret_key' => $merchantModel->v3_pay_key,
]]);
// region 替换请求 +++++
$request = ApplicationContext::getContainer()->get(RequestInterface::class);
$server = make(Server::class, [
$application->getMerchant(),
$request
]);
$application->setServer($server);
// endregion
return $application;
}