Skip to content

Commit bd2148e

Browse files
saber-xljxTheNorthMemory
authored
v1.4.12 released (#146)
* Fix transformRequest for GET requests * Refactored to use if statement for parsing queryParams * optimize request parameter parsing and handling * sample tests on `v2/papay/h5entrustweb` request --------- Co-authored-by: ljx <luojiaxin.xx@gmali.com> Co-authored-by: James ZHNAG <thenorthmemory@qq.com>
1 parent 6f2994f commit bd2148e

File tree

6 files changed

+148
-6
lines changed

6 files changed

+148
-6
lines changed

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
# 变更历史
22

3-
## [1.4.11](../../compare/v1.4.9...v1.4.10) - 2024-12-23
3+
## [1.4.12](../../compare/v1.4.11...v1.4.12) - 2025-01-27
4+
5+
- 修正`APIv2`特殊`GET`请求抛异常问题,相关记录见[这里](https://github.com/wechatpay-apiv3/wechatpay-php/issues/146)
6+
7+
## [1.4.11](../../compare/v1.4.10...v1.4.11) - 2024-12-27
48

59
-`APIv2`服务端返回值做精细判断,对于`return_code`(返回状态码)及/或`result_code`(业务结果)有key且值不为`SUCCESS`的情形,抛出客户端`RejectionException`异常,并加入[AuthcodetoopenidTest.php](./tests/OpenAPI/V2/Tools/AuthcodetoopenidTest.php)异常处理示例。
610

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
## 项目状态
2727

28-
当前版本为 `1.4.11` 版。
28+
当前版本为 `1.4.12` 版。
2929
项目版本遵循 [语义化版本号](https://semver.org/lang/zh-CN/)
3030
如果你使用的版本 `<=v1.3.2`,升级前请参考 [升级指南](UPGRADING.md)
3131

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "wechatpay/wechatpay",
3-
"version": "1.4.11",
3+
"version": "1.4.12",
44
"description": "[A]Sync Chainable WeChatPay v2&v3's OpenAPI SDK for PHP",
55
"type": "library",
66
"keywords": [

src/ClientDecoratorInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ interface ClientDecoratorInterface
1414
/**
1515
* @var string - This library version
1616
*/
17-
public const VERSION = '1.4.11';
17+
public const VERSION = '1.4.12';
1818

1919
/**
2020
* @var string - The HTTP transfer `xml` based protocol

src/ClientXmlTrait.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
use GuzzleHttp\Client;
1111
use GuzzleHttp\HandlerStack;
12+
use GuzzleHttp\Psr7\Query;
1213
use GuzzleHttp\Psr7\Utils;
1314
use GuzzleHttp\Promise\Create;
1415
use GuzzleHttp\Promise\PromiseInterface;
@@ -82,7 +83,13 @@ public static function transformRequest(
8283
{
8384
return static function (callable $handler) use ($mchid, $secret, $merchant): callable {
8485
return static function (RequestInterface $request, array $options = []) use ($handler, $mchid, $secret, $merchant): PromiseInterface {
85-
$data = $options['xml'] ?? [];
86+
$methodIsGet = $request->getMethod() === 'GET';
87+
88+
if ($methodIsGet) {
89+
$queryParams = Query::parse($request->getUri()->getQuery());
90+
}
91+
92+
$data = $options['xml'] ?? ($queryParams ?? []);
8693

8794
if ($mchid && $mchid !== ($inputMchId = $data['mch_id'] ?? $data['mchid'] ?? $data['combine_mch_id'] ?? null)) {
8895
throw new Exception\InvalidArgumentException(sprintf(Exception\EV2_REQ_XML_NOTMATCHED_MCHID, $inputMchId ?? '', $mchid));
@@ -94,7 +101,7 @@ public static function transformRequest(
94101

95102
$data['sign'] = Crypto\Hash::sign($type, Formatter::queryStringLike(Formatter::ksort($data)), $secret);
96103

97-
$modify = ['body' => Transformer::toXml($data)];
104+
$modify = $methodIsGet ? ['query' => Query::build($data)] : ['body' => Transformer::toXml($data)];
98105

99106
// for security request, it was required the merchant's private_key and certificate
100107
if (isset($options['security']) && true === $options['security']) {
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace WeChatPay\Tests\OpenAPI\V2\Papay;
4+
5+
use GuzzleHttp\Handler\MockHandler;
6+
use GuzzleHttp\HandlerStack;
7+
use GuzzleHttp\Psr7\Response;
8+
use Psr\Http\Message\ResponseInterface;
9+
use WeChatPay\Builder;
10+
use WeChatPay\Crypto\Hash;
11+
use WeChatPay\Formatter;
12+
use WeChatPay\Transformer;
13+
use PHPUnit\Framework\TestCase;
14+
15+
class H5entrustwebTest extends TestCase
16+
{
17+
/** @var MockHandler $mock */
18+
private $mock;
19+
20+
private function guzzleMockStack(): HandlerStack
21+
{
22+
$this->mock = new MockHandler();
23+
24+
return HandlerStack::create($this->mock);
25+
}
26+
27+
/**
28+
* @param string $mchid
29+
* @return array{\WeChatPay\BuilderChainable}
30+
*/
31+
private function prepareEnvironment(string $mchid, string $secret): array
32+
{
33+
$instance = Builder::factory([
34+
'mchid' => $mchid,
35+
'serial' => 'nop',
36+
'privateKey' => 'any',
37+
'certs' => ['any' => null],
38+
'secret' => $secret,
39+
'handler' => $this->guzzleMockStack(),
40+
]);
41+
42+
$endpoint = $instance->chain('v2/papay/h5entrustweb');
43+
44+
return [$endpoint];
45+
}
46+
47+
/**
48+
* @return array<string,array{string,string,array<string,int|string>,ResponseInterface}>
49+
*/
50+
public function mockRequestsDataProvider(): array
51+
{
52+
$mchid = '1230000109';
53+
$secret = Formatter::nonce(32);
54+
$queryData = [
55+
'appid' => 'wxcbda96de0b165486',
56+
'mch_id' => $mchid,
57+
'plan_id' => '12535',
58+
'contract_code' => '100000',
59+
'request_serial' => 1000,
60+
'contract_display_account' => '微信代扣',
61+
'notify_url' => 'https://weixin.qq.com',
62+
'version' => '1.0',
63+
'sign_type' => 'HMAC-SHA256',
64+
'timestamp' => Formatter::timestamp(),
65+
'return_appid' => 'wxcbda96de0b165486',
66+
];
67+
$responseData = [
68+
'return_code' => 'SUCCESS',
69+
'return_msg' => '',
70+
'result_code' => 'SUCCESS',
71+
'result_msg' => '',
72+
'redirect_url' => 'https://payapp.weixin.qq.com',
73+
];
74+
75+
return [
76+
'return_code=SUCCESS' => [$mchid, $secret, $queryData, new Response(200, [], Transformer::toXml($responseData))],
77+
];
78+
}
79+
80+
/**
81+
* @dataProvider mockRequestsDataProvider
82+
* @param string $mchid
83+
* @param string $secret
84+
* @param array<string,int|string> $query
85+
* @param ResponseInterface $respondor
86+
*/
87+
public function testGet(string $mchid, string $secret, array $query, ResponseInterface $respondor): void
88+
{
89+
[$endpoint] = $this->prepareEnvironment($mchid, $secret);
90+
91+
$this->mock->reset();
92+
$this->mock->append($respondor);
93+
94+
$res = $endpoint->get(['nonceless' => true, 'query' => $query]);
95+
self::responseAssertion($res);
96+
}
97+
98+
/**
99+
* @param ResponseInterface $response
100+
*/
101+
private static function responseAssertion(ResponseInterface $response): void
102+
{
103+
$txt = (string) $response->getBody();
104+
$array = Transformer::toArray($txt);
105+
static::assertArrayHasKey('redirect_url', $array);
106+
static::assertArrayHasKey('return_code', $array);
107+
static::assertArrayHasKey('result_code', $array);
108+
}
109+
110+
/**
111+
* @dataProvider mockRequestsDataProvider
112+
* @param string $mchid
113+
* @param string $secret
114+
* @param array<string,string> $query
115+
* @param ResponseInterface $respondor
116+
*/
117+
public function testGetAsync(string $mchid, string $secret, array $query, ResponseInterface $respondor): void
118+
{
119+
[$endpoint] = $this->prepareEnvironment($mchid, $secret);
120+
121+
$this->mock->reset();
122+
$this->mock->append($respondor);
123+
124+
$endpoint->getAsync([
125+
'nonceless' => true,
126+
'query' => $query,
127+
])->then(static function(ResponseInterface $res) {
128+
self::responseAssertion($res);
129+
})->wait();
130+
}
131+
}

0 commit comments

Comments
 (0)