diff --git a/src/Client.php b/src/Client.php index 091286e..a8a14a5 100644 --- a/src/Client.php +++ b/src/Client.php @@ -2,6 +2,10 @@ declare(strict_types=1); +/** + * SDK 根入口与通道客户端工厂。 + */ + namespace We; use GuzzleHttp\ClientInterface; @@ -26,10 +30,10 @@ use We\Platform\Wechat\WxappClient as WechatWxappClient; use We\Support\FileCacheStore; /** - * 根入口:通过 `__call` 以通道工厂方法名创建各平台客户端(内部 `ReflectionClass::newInstanceArgs`),便于集中维护构造参数。 + * SDK 根入口:按平台与业务域创建微信、支付宝客户端,工厂方法命名与配置对象语义保持一致。 * - * 缓存键固定为 `{cacheKeyPrefix}:{platformChannel}:{logicalKey}`,见 {@see \We\Support\CacheKey::compose};未传 `cacheKeyPrefix` 时使用 {@see self::DEFAULT_CACHE_KEY_PREFIX},不得传空白字符串。 - * 未传入 `cache` 时默认使用 {@see FileCacheStore},目录为 {@see self::defaultCacheStoreDirectory()}(位于 PHP `sys_get_temp_dir()` 下)。 + * access_token 等运行态数据的缓存键固定为 `{cacheKeyPrefix}:{platformChannel}:{logicalKey}`,见 {@see \We\Support\CacheKey::compose}。 + * 未注入缓存实现时使用 {@see FileCacheStore},默认目录为 {@see self::defaultCacheStoreDirectory()}。 * * @method WechatPlatformClient wechatPlatform(WechatPlatformConfig $config) * @method WechatWxappClient wechatWxapp(WechatWxappConfig $config) @@ -54,6 +58,9 @@ final class Client private readonly string $cacheKeyPrefix; + /** + * 初始化 SDK 根入口,注入运行态缓存、授权方 Token 仓库和 HTTP 客户端。 + */ public function __construct( ?StoreCacheInterface $cache = null, ?StoreTokenInterface $authorizers = null, @@ -78,27 +85,27 @@ final class Client } /** - * 按通道标识取实例:`new Client()->get('wechat.platform', new WechatPlatformConfig(...))` + * 按字符串通道创建客户端;通道名称与配置对象一一对应。 */ public function get(string $channel, ConfigInterface $config): object { - $factory = match ($channel) { - 'wechat.platform' => 'wechatPlatform', - 'wechat.wxapp' => 'wechatWxapp', - 'wechat.service' => 'wechatService', - 'wechat.payment' => 'wechatPayment', - 'alipay.platform' => 'alipayPlatform', - 'alipay.payment' => 'alipayPayment', + [$factory, $expected] = match ($channel) { + 'wechat.platform' => ['wechatPlatform', WechatPlatformConfig::class], + 'wechat.wxapp' => ['wechatWxapp', WechatWxappConfig::class], + 'wechat.service' => ['wechatService', WechatServiceConfig::class], + 'wechat.payment' => ['wechatPayment', WechatPaymentConfig::class], + 'alipay.platform' => ['alipayPlatform', AlipayPlatformConfig::class], + 'alipay.payment' => ['alipayPayment', AlipayPaymentConfig::class], default => throw new WechatException('不支持的通道标识: ' . $channel), }; - return $this->__call($factory, [$config]); + return $this->__call($factory, [$this->ensureConfig($config, $expected, $factory)]); } /** - * 魔术工厂:`$client->wechatPlatform($config)` 等价于反射 `new WechatPlatformClient(...)`。 + * 魔术工厂:只暴露平台前缀明确的客户端创建方法。 * - * @param array $arguments + * @param array $arguments */ public function __call(string $name, array $arguments): object { @@ -144,6 +151,8 @@ final class Client } /** + * 使用反射创建具体平台客户端实例。 + * * @param class-string $class * @param array $args */ @@ -157,6 +166,8 @@ final class Client } /** + * 校验工厂方法收到的配置对象类型。 + * * @template T of object * @param class-string $expected * @return T @@ -170,7 +181,11 @@ final class Client return $config; } - /** @param class-string $fqcn */ + /** + * 获取类短名,用于生成清晰的配置类型错误信息。 + * + * @param class-string $fqcn + */ private function shortClass(string $fqcn): string { $pos = strrpos($fqcn, '\\'); diff --git a/src/Config/AlipayPaymentConfig.php b/src/Config/AlipayPaymentConfig.php index 2e35016..c70d01a 100644 --- a/src/Config/AlipayPaymentConfig.php +++ b/src/Config/AlipayPaymentConfig.php @@ -2,8 +2,15 @@ declare(strict_types=1); +/** + * 支付宝支付配置对象。 + */ + namespace We\Config; +/** + * 支付宝支付配置,继承支付宝开放平台网关签名与验签参数。 + */ final class AlipayPaymentConfig extends AlipayPlatformConfig { } diff --git a/src/Config/AlipayPlatformConfig.php b/src/Config/AlipayPlatformConfig.php index 8e87367..3eb5141 100644 --- a/src/Config/AlipayPlatformConfig.php +++ b/src/Config/AlipayPlatformConfig.php @@ -2,16 +2,27 @@ declare(strict_types=1); +/** + * 支付宝开放平台配置对象。 + */ + namespace We\Config; use We\Contract\ConfigInterface; use We\Exception\WechatException; /** + * 支付宝开放平台基础配置。 + * + * 应用私钥用于支付宝开放平台网关请求签名;支付宝公钥用于同步响应和异步通知验签。 + * * @phpstan-consistent-constructor */ class AlipayPlatformConfig implements ConfigInterface { + /** + * 创建支付宝开放平台配置并执行必填项校验。 + */ public function __construct( public string $appid, public string $privateKey, @@ -25,6 +36,9 @@ class AlipayPlatformConfig implements ConfigInterface $this->validate(); } + /** + * 校验支付宝 app_id 与应用私钥。 + */ public function validate(): void { if (trim($this->appid) === '' || trim($this->privateKey) === '') { @@ -33,6 +47,8 @@ class AlipayPlatformConfig implements ConfigInterface } /** + * 从数组创建支付宝开放平台配置。 + * * @param array $data */ public static function fromArray(array $data): static diff --git a/src/Config/WechatPaymentConfig.php b/src/Config/WechatPaymentConfig.php index b6d5d5e..e4411dc 100644 --- a/src/Config/WechatPaymentConfig.php +++ b/src/Config/WechatPaymentConfig.php @@ -2,26 +2,44 @@ declare(strict_types=1); +/** + * 微信支付 APIv3 商户配置对象。 + */ + namespace We\Config; use We\Contract\ConfigInterface; use We\Exception\WechatException; +/** + * 微信支付 APIv3 商户配置。 + * + * 商户号、商户 API 证书序列号和商户私钥用于生成 APIv3 请求签名;APIv3 密钥用于回调资源解密;微信支付平台证书或平台公钥用于通知验签。 + */ final class WechatPaymentConfig implements ConfigInterface { + /** + * 创建微信支付 APIv3 配置并执行必填项校验。 + */ public function __construct( public string $appid, public string $mchId, public string $apiV3Key, public string $merchantSerial, public string $merchantPrivateKey, + /** 微信支付平台证书 PEM;未配置 platformPublicKey 时用于回调验签。 */ public string $platformCertificate = '', + /** 微信支付平台公钥 PEM,优先用于回调验签。 */ public string $platformPublicKey = '', + /** 微信支付平台证书/公钥序列号;非空时会校验回调头 Wechatpay-Serial。 */ public string $platformSerial = '', ) { $this->validate(); } + /** + * 校验微信支付 appid、商户号、APIv3 密钥、商户证书序列号和商户私钥。 + */ public function validate(): void { foreach ([ @@ -38,6 +56,8 @@ final class WechatPaymentConfig implements ConfigInterface } /** + * 从数组创建微信支付 APIv3 商户配置。 + * * @param array $data */ public static function fromArray(array $data): static diff --git a/src/Config/WechatPlatformConfig.php b/src/Config/WechatPlatformConfig.php index 85f9c29..2a5363c 100644 --- a/src/Config/WechatPlatformConfig.php +++ b/src/Config/WechatPlatformConfig.php @@ -2,20 +2,32 @@ declare(strict_types=1); +/** + * 微信公众平台配置对象。 + */ + namespace We\Config; use We\Contract\ConfigInterface; use We\Exception\WechatException; +/** + * 微信公众平台基础配置。 + * + * appId/appSecret 用于获取微信公众平台接口调用凭据 access_token;Token 与 EncodingAESKey 用于服务器配置、消息签名校验和安全模式消息加解密。 + */ final class WechatPlatformConfig implements ConfigInterface { + /** + * 创建微信公众平台配置并执行必填项校验。 + */ public function __construct( public string $appid, public string $appSecret, public string $token = '', public string $encodingAesKey = '', /** - * 业务维度的缓存分桶:Token 键形如 `wechat:app:{appid}:official:access_token:scope:{storageScope}`; + * 业务维度的缓存分桶:Token 键形如 `wechat:app:{appid}:platform:access_token:scope:{storageScope}`; * 空字符串则仅按 appid 分组。多租户下同一 appid 若需隔离(极少见)可传租户/账号标识。 */ public string $storageScope = '', @@ -24,6 +36,8 @@ final class WechatPlatformConfig implements ConfigInterface } /** + * 从数组创建微信公众平台配置,兼容常见下划线字段名。 + * * @param array $data */ public static function fromArray(array $data): static @@ -37,6 +51,9 @@ final class WechatPlatformConfig implements ConfigInterface ); } + /** + * 校验微信公众平台 appid 与 appSecret。 + */ public function validate(): void { foreach ([ diff --git a/src/Config/WechatServiceConfig.php b/src/Config/WechatServiceConfig.php index 601a840..8e50732 100644 --- a/src/Config/WechatServiceConfig.php +++ b/src/Config/WechatServiceConfig.php @@ -2,13 +2,25 @@ declare(strict_types=1); +/** + * 微信服务平台(第三方平台)配置对象。 + */ + namespace We\Config; use We\Contract\ConfigInterface; use We\Exception\WechatException; +/** + * 微信服务平台(第三方平台)配置。 + * + * componentAppid/componentAppSecret 用于获取第三方平台 component_access_token;componentToken/componentEncodingAesKey 用于授权事件接收 URL 的签名校验与安全模式消息解密。 + */ final class WechatServiceConfig implements ConfigInterface { + /** + * 创建微信服务平台(第三方平台)配置并执行必填项校验。 + */ public function __construct( public string $componentAppid, public string $componentAppSecret, @@ -20,6 +32,9 @@ final class WechatServiceConfig implements ConfigInterface $this->validate(); } + /** + * 校验第三方平台 component_appid、secret、Token 与 EncodingAESKey。 + */ public function validate(): void { foreach ([ @@ -35,6 +50,8 @@ final class WechatServiceConfig implements ConfigInterface } /** + * 从数组创建微信服务平台(第三方平台)配置。 + * * @param array $data */ public static function fromArray(array $data): static diff --git a/src/Config/WechatWxappConfig.php b/src/Config/WechatWxappConfig.php index ed8fe7c..72d29a5 100644 --- a/src/Config/WechatWxappConfig.php +++ b/src/Config/WechatWxappConfig.php @@ -2,13 +2,25 @@ declare(strict_types=1); +/** + * 微信小程序配置对象。 + */ + namespace We\Config; use We\Contract\ConfigInterface; use We\Exception\WechatException; +/** + * 微信小程序基础配置。 + * + * appid/appSecret 用于获取小程序接口调用凭据 access_token;storageScope 用于隔离不同业务上下文下的凭据缓存。 + */ final class WechatWxappConfig implements ConfigInterface { + /** + * 创建微信小程序配置并执行必填项校验。 + */ public function __construct( public string $appid, public string $appSecret, @@ -19,6 +31,8 @@ final class WechatWxappConfig implements ConfigInterface } /** + * 从数组创建微信小程序配置,兼容常见下划线字段名。 + * * @param array $data */ public static function fromArray(array $data): static @@ -30,6 +44,9 @@ final class WechatWxappConfig implements ConfigInterface ); } + /** + * 校验小程序 appid 与 appSecret。 + */ public function validate(): void { if (trim($this->appid) === '' || trim($this->appSecret) === '') { diff --git a/src/Contract/ConfigInterface.php b/src/Contract/ConfigInterface.php index ad3098f..1364658 100644 --- a/src/Contract/ConfigInterface.php +++ b/src/Contract/ConfigInterface.php @@ -2,20 +2,26 @@ declare(strict_types=1); +/** + * 平台配置契约。 + */ + namespace We\Contract; /** - * 平台配置统一契约:所有通道配置必须能从数组构造,并在构造阶段完成自身业务校验。 + * 平台配置统一契约:所有配置对象必须支持数组构造,并在构造阶段完成平台必填项校验。 */ interface ConfigInterface { /** + * 通过数组创建配置对象。 + * * @param array $data */ public static function fromArray(array $data): static; /** - * 校验配置字段完整性、密钥格式等通道级约束;失败时抛出 SDK 异常。 + * 校验平台配置的必填字段、密钥格式等约束;校验失败时抛出 SDK 异常。 */ public function validate(): void; } diff --git a/src/Contract/StoreCacheInterface.php b/src/Contract/StoreCacheInterface.php index bb8cb3b..316d227 100644 --- a/src/Contract/StoreCacheInterface.php +++ b/src/Contract/StoreCacheInterface.php @@ -2,20 +2,24 @@ declare(strict_types=1); +/** + * SDK 运行态缓存契约。 + */ + namespace We\Contract; /** - * 通用缓存契约:用于 access_token 等 SDK 运行态数据,必须显式支持 TTL 与刷新锁。 + * 运行态缓存契约:用于保存 access_token、component_access_token 等平台接口调用凭据,必须支持 TTL 与刷新锁。 */ interface StoreCacheInterface { /** - * 读取缓存值,缓存不存在、已过期或无法解析时返回默认值。 + * 读取缓存值;缓存不存在、已过期或无法解析时返回默认值。 */ public function get(string $key, mixed $default = null): mixed; /** - * 写入缓存值;$ttl 为剩余秒数,必须至少按 1 秒处理。 + * 写入缓存值;TTL 单位为秒,实现侧至少按 1 秒处理。 */ public function set(string $key, mixed $value, int $ttl): void; @@ -25,7 +29,7 @@ interface StoreCacheInterface public function del(string $key): void; /** - * 在锁内执行回调,避免集群或多进程下重复刷新 access_token。 + * 在互斥锁内执行回调,避免多进程或集群环境重复刷新平台接口调用凭据。 * * @template T * @param callable():T $callback diff --git a/src/Contract/StoreTokenInterface.php b/src/Contract/StoreTokenInterface.php index 6c618bd..ff82309 100644 --- a/src/Contract/StoreTokenInterface.php +++ b/src/Contract/StoreTokenInterface.php @@ -2,20 +2,24 @@ declare(strict_types=1); +/** + * 微信服务平台授权方 Token 存储契约。 + */ + namespace We\Contract; /** - * 开放平台授权方 Token 存储契约;SDK 只读取 refresh token 并回写刷新结果。 + * 微信服务平台授权方 Token 存储契约;SDK 读取 authorizer_refresh_token,并在刷新后回写授权方 Token 数据。 */ interface StoreTokenInterface { /** - * 获取授权账号 refresh token。 + * 获取授权方账号的 authorizer_refresh_token。 */ public function refreshToken(string $authorizerAppid): string; /** - * 授权账号 token 刷新后回写业务存储,避免 SDK 持有请求态数据。 + * 授权方 authorizer_access_token 刷新后回写业务存储。 * * @param array $payload */ diff --git a/src/Exception/ApiException.php b/src/Exception/ApiException.php index 558f4e1..c8ce67b 100644 --- a/src/Exception/ApiException.php +++ b/src/Exception/ApiException.php @@ -2,6 +2,13 @@ declare(strict_types=1); +/** + * 平台接口请求异常。 + */ + namespace We\Exception; +/** + * HTTP 请求失败或平台接口返回错误时抛出的异常。 + */ final class ApiException extends WechatException {} diff --git a/src/Exception/SignatureException.php b/src/Exception/SignatureException.php index 5cae514..31209e2 100644 --- a/src/Exception/SignatureException.php +++ b/src/Exception/SignatureException.php @@ -2,6 +2,13 @@ declare(strict_types=1); +/** + * 签名与验签异常。 + */ + namespace We\Exception; +/** + * 微信回调、微信支付通知或支付宝通知签名验证失败时抛出的异常。 + */ final class SignatureException extends WechatException {} diff --git a/src/Exception/WechatException.php b/src/Exception/WechatException.php index 5bd2ae2..6bc4cd5 100644 --- a/src/Exception/WechatException.php +++ b/src/Exception/WechatException.php @@ -2,14 +2,25 @@ declare(strict_types=1); +/** + * SDK 基础异常。 + */ + namespace We\Exception; use RuntimeException; use Throwable; +/** + * SDK 基础异常。 + * + * 通过 context() 暴露平台响应、验签明细等上下文,便于业务侧记录日志和排查问题。 + */ class WechatException extends RuntimeException { /** + * 创建 SDK 异常并保存可选上下文。 + * * @param array $context */ public function __construct( @@ -22,6 +33,8 @@ class WechatException extends RuntimeException } /** + * 获取异常附带的平台响应或验签上下文。 + * * @return array */ public function context(): array diff --git a/src/Support/CacheKey.php b/src/Support/CacheKey.php index ec60731..02a1c9a 100644 --- a/src/Support/CacheKey.php +++ b/src/Support/CacheKey.php @@ -2,16 +2,22 @@ declare(strict_types=1); +/** + * 缓存键生成工具。 + */ + namespace We\Support; use We\Exception\WechatException; /** - * SDK 缓存完整键生成器,固定为 `{cacheKeyPrefix}:{platformChannel}:{logicalKey}` 三段。 + * SDK 缓存完整键生成器,固定为 `{cacheKeyPrefix}:{platformChannel}:{logicalKey}` 三段,便于按项目、通道和逻辑键隔离。 */ final class CacheKey { /** + * 组合缓存完整键。 + * * @param string $prefix 根 Client 通用命名段,不得为空,用于区分部署、租户或应用。 * @param string $channel 通道段,如 `wechat.platform`,必须与 Client 通道标识一致。 * @param string $logicalKey 业务逻辑键,如 TokenCacheKey 生成的 access_token 键。 @@ -34,6 +40,9 @@ final class CacheKey return $prefix . ':' . $channel . ':' . $logical; } + /** + * 规范化缓存键命名段并去除两侧多余冒号。 + */ private static function normalizeSegment(string $segment): string { $segment = trim($segment); diff --git a/src/Support/FileCacheStore.php b/src/Support/FileCacheStore.php index 8accf3b..d4ca71e 100644 --- a/src/Support/FileCacheStore.php +++ b/src/Support/FileCacheStore.php @@ -2,16 +2,23 @@ declare(strict_types=1); +/** + * 本地文件缓存实现。 + */ + namespace We\Support; use We\Contract\StoreCacheInterface; use We\Exception\WechatException; /** - * 单机文件缓存:缓存值以 JSON 保存,使用 flock 提供单机多进程刷新锁。 + * 本地文件缓存实现:缓存值以 JSON 保存,并使用 flock 提供单机多进程刷新锁。 */ final class FileCacheStore implements StoreCacheInterface { + /** + * 创建文件缓存目录并校验可写权限。 + */ public function __construct(private readonly string $directory) { if ($this->directory === '') { @@ -25,6 +32,9 @@ final class FileCacheStore implements StoreCacheInterface } } + /** + * 读取文件缓存值;文件不存在、过期或 JSON 无效时返回默认值。 + */ public function get(string $key, mixed $default = null): mixed { $path = $this->pathFor($key); @@ -55,7 +65,7 @@ final class FileCacheStore implements StoreCacheInterface if (!is_array($payload) || !array_key_exists('expires_at', $payload) || !array_key_exists('value', $payload)) { return $default; } - if ((int)$payload['expires_at'] < time()) { + if ((int)$payload['expires_at'] <= time()) { $this->del($key); return $default; @@ -64,6 +74,9 @@ final class FileCacheStore implements StoreCacheInterface return $payload['value']; } + /** + * 以原子写入方式保存缓存值与过期时间。 + */ public function set(string $key, mixed $value, int $ttl): void { $path = $this->pathFor($key); @@ -90,6 +103,9 @@ final class FileCacheStore implements StoreCacheInterface } } + /** + * 删除指定缓存键对应的文件。 + */ public function del(string $key): void { $path = $this->pathFor($key); @@ -98,6 +114,9 @@ final class FileCacheStore implements StoreCacheInterface } } + /** + * 基于 flock 在互斥锁内执行回调。 + */ public function lock(string $key, int $ttl, callable $callback): mixed { $path = $this->pathFor('lock:' . $key) . '.lock'; @@ -123,6 +142,9 @@ final class FileCacheStore implements StoreCacheInterface } } + /** + * 根据缓存键生成哈希分片后的文件路径。 + */ private function pathFor(string $key): string { $hash = hash('sha256', $key); diff --git a/src/Support/NullCacheStore.php b/src/Support/NullCacheStore.php index 7fd5b86..e3a8e27 100644 --- a/src/Support/NullCacheStore.php +++ b/src/Support/NullCacheStore.php @@ -2,24 +2,40 @@ declare(strict_types=1); +/** + * 空缓存实现。 + */ + namespace We\Support; use We\Contract\StoreCacheInterface; /** - * 空缓存实现:用于测试或显式禁用缓存,锁回调直接执行。 + * 空缓存实现:用于测试或显式禁用缓存;读取永远返回默认值,锁回调直接执行。 */ final class NullCacheStore implements StoreCacheInterface { + /** + * 返回默认值,不保存任何缓存数据。 + */ public function get(string $key, mixed $default = null): mixed { return $default; } + /** + * 忽略写入请求。 + */ public function set(string $key, mixed $value, int $ttl): void {} + /** + * 忽略删除请求。 + */ public function del(string $key): void {} + /** + * 不加锁,直接执行回调。 + */ public function lock(string $key, int $ttl, callable $callback): mixed { return $callback(); diff --git a/src/Support/PsrSimpleCacheStore.php b/src/Support/PsrSimpleCacheStore.php index 2308626..ece44dd 100644 --- a/src/Support/PsrSimpleCacheStore.php +++ b/src/Support/PsrSimpleCacheStore.php @@ -2,6 +2,10 @@ declare(strict_types=1); +/** + * PSR-16 缓存适配器。 + */ + namespace We\Support; use Psr\SimpleCache\CacheInterface; @@ -9,11 +13,13 @@ use We\Contract\StoreCacheInterface; use We\Exception\WechatException; /** - * PSR-16 缓存适配器;集群锁需由业务注入原子锁回调。 + * PSR-16 缓存适配器;缓存能力委托给 PSR Simple Cache,实现侧需注入原子锁回调以支持刷新锁。 */ final class PsrSimpleCacheStore implements StoreCacheInterface { /** + * 创建 PSR-16 缓存适配器,并可选注入锁回调。 + * * @param null|callable(string,int,callable):mixed $locker */ public function __construct( @@ -21,21 +27,33 @@ final class PsrSimpleCacheStore implements StoreCacheInterface private readonly mixed $locker = null, ) {} + /** + * 从 PSR-16 缓存读取值。 + */ public function get(string $key, mixed $default = null): mixed { return $this->cache->get($key, $default); } + /** + * 写入 PSR-16 缓存并设置 TTL。 + */ public function set(string $key, mixed $value, int $ttl): void { $this->cache->set($key, $value, max(1, $ttl)); } + /** + * 从 PSR-16 缓存删除值。 + */ public function del(string $key): void { $this->cache->delete($key); } + /** + * 通过业务注入的锁回调执行互斥逻辑。 + */ public function lock(string $key, int $ttl, callable $callback): mixed { if (!is_callable($this->locker)) { diff --git a/src/Support/TokenCacheKey.php b/src/Support/TokenCacheKey.php index e37f4ef..1802e3c 100644 --- a/src/Support/TokenCacheKey.php +++ b/src/Support/TokenCacheKey.php @@ -2,10 +2,14 @@ declare(strict_types=1); +/** + * 平台接口调用凭据缓存逻辑键生成工具。 + */ + namespace We\Support; /** - * Token 缓存键统一按「微信侧 appid 优先」分段,便于 Redis 等按前缀扫描、按应用清理。 + * 微信接口调用凭据缓存逻辑键统一按「微信侧 appid 优先」分段,便于 Redis 等存储按应用前缀扫描和清理。 * * 约定前缀:`wechat:app:{appid}:...`;若 Config 带 `storageScope`(业务隔离),追加 `:scope:{值}`。 * 经根 {@see \We\Client} 与各通道写入存储时,作为第三段与通用前缀、平台段经 {@see CacheKey::compose} 拼成固定三段键。 @@ -13,41 +17,44 @@ namespace We\Support; final class TokenCacheKey { /** - * 公众号 client_credential access_token - * 例:`wechat:app:wxabcd:official:access_token` 或带 scope 后缀。 + * 微信公众平台 client_credential access_token。 + * 例:`wechat:app:wxabcd:platform:access_token` 或带 scope 后缀。 */ - public static function wechatOfficialAccessToken(string $appid, string $storageScope = ''): string + public static function wechatPlatformAccessToken(string $appid, string $storageScope = ''): string { - return self::appendScope('wechat:app:' . $appid . ':official:access_token', $storageScope); + return self::appendScope('wechat:app:' . $appid . ':platform:access_token', $storageScope); } /** - * 小程序 client_credential access_token + * 小程序 client_credential access_token。 */ - public static function wechatMiniAccessToken(string $appid, string $storageScope = ''): string + public static function wechatWxappAccessToken(string $appid, string $storageScope = ''): string { - return self::appendScope('wechat:app:' . $appid . ':mini:access_token', $storageScope); + return self::appendScope('wechat:app:' . $appid . ':wxapp:access_token', $storageScope); } /** - * 开放平台第三方 component_access_token(按 component_appid 分组) + * 微信服务平台(第三方平台) component_access_token(按 component_appid 分组)。 */ - public static function wechatOpenComponentAccessToken(string $componentAppid, string $storageScope = ''): string + public static function wechatServiceComponentAccessToken(string $componentAppid, string $storageScope = ''): string { - return self::appendScope('wechat:app:' . $componentAppid . ':open:component_access_token', $storageScope); + return self::appendScope('wechat:app:' . $componentAppid . ':service:component_access_token', $storageScope); } /** - * 开放平台代授权方 authorizer_access_token(挂在 component_appid 下,避免键平面冲突) + * 微信服务平台代授权方 authorizer_access_token(挂在 component_appid 下,避免键平面冲突)。 */ - public static function wechatOpenAuthorizerAccessToken(string $componentAppid, string $authorizerAppid, string $storageScope = ''): string + public static function wechatServiceAuthorizerAccessToken(string $componentAppid, string $authorizerAppid, string $storageScope = ''): string { return self::appendScope( - 'wechat:app:' . $componentAppid . ':open:authorizer:' . $authorizerAppid . ':access_token', + 'wechat:app:' . $componentAppid . ':service:authorizer:' . $authorizerAppid . ':access_token', $storageScope, ); } + /** + * 按需追加 storageScope,隔离同一 appid 在不同业务上下文中的凭据缓存。 + */ private static function appendScope(string $base, string $storageScope): string { $s = trim($storageScope);