Test Failed
Pull Request — master (#657)
by
unknown
03:05
created

API::enableSandbox()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 8
ccs 0
cts 0
cp 0
crap 6
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the overtrue/wechat.
5
 *
6
 * (c) overtrue <[email protected]>
7
 *
8
 * This source file is subject to the MIT license that is bundled
9
 * with this source code in the file LICENSE.
10
 */
11
12
/**
13
 * API.php.
14
 *
15
 * @author    overtrue <[email protected]>
16
 * @copyright 2015 overtrue <[email protected]>
17
 *
18
 * @see      https://github.com/overtrue
19
 * @see      http://overtrue.me
20
 */
21
22
namespace EasyWeChat\Payment;
23
24
use EasyWeChat\Core\AbstractAPI;
25
use EasyWeChat\Support\Collection;
26
use EasyWeChat\Support\XML;
27
use Psr\Http\Message\ResponseInterface;
28
29
/**
30
 * Class API.
31
 */
32
class API extends AbstractAPI
33
{
34
    /**
35
     * Merchant instance.
36
     *
37
     * @var Merchant
38
     */
39
    protected $merchant;
40
41
    /**
42
     * Sandbox box mode
43
     *
44
     * @var string
45
     */
46
     protected $sandboxMode = '';
47
48
49
    const API_ENDPOINT = 'https://api.mch.weixin.qq.com';
50
51
    // api
52
    const API_PAY_ORDER = '/pay/micropay';
53
    const API_PREPARE_ORDER = '/pay/unifiedorder';
54
    const API_QUERY = '/pay/orderquery';
55
    const API_CLOSE = '/pay/closeorder';
56
    const API_REVERSE = '/secapi/pay/reverse';
57
    const API_REFUND = '/secapi/pay/refund';
58
    const API_QUERY_REFUND = '/pay/refundquery';
59
    const API_DOWNLOAD_BILL = '/pay/downloadbill';
60
    const API_REPORT = '/payitil/report';
61
    const API_URL_SHORTEN = '/tools/shorturl';
62
    const API_AUTH_CODE_TO_OPENID = '/tools/authcodetoopenid';
63
64
    // order id types.
65
    const TRANSACTION_ID = 'transaction_id';
66
    const OUT_TRADE_NO = 'out_trade_no';
67
    const OUT_REFUND_NO = 'out_refund_no';
68
    const REFUND_ID = 'refund_id';
69
70
    // bill types.
71 12
    const BILL_TYPE_ALL = 'ALL';
72
    const BILL_TYPE_SUCCESS = 'SUCCESS';
73 12
    const BILL_TYPE_REFUND = 'REFUND';
74 12
    const BILL_TYPE_REVOKED = 'REVOKED';
75
76
    /**
77
     * API constructor.
78
     *
79
     * @param \EasyWeChat\Payment\Merchant $merchant
80
     */
81
    public function __construct(Merchant $merchant, $isSandboxMode = FALSE)
82
    {
83 1
        $this->merchant = $merchant;
84
        if ($isSandboxMode == TRUE) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
85 1
            $this->sandboxMode = '/sandbox';
86
        }
87
    }
88
89
    /**
90
     * Pay the order.
91
     *
92
     * @param Order $order
93
     *
94
     * @return \EasyWeChat\Support\Collection
95 1
     */
96
    public function pay(Order $order)
97 1
    {
98 1
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_PAY_ORDER, $order->all());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API..._ORDER, $order->all()); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 98 which is incompatible with the return type documented by EasyWeChat\Payment\API::pay of type EasyWeChat\Support\Collection.
Loading history...
99 1
    }
100 1
101
    /**
102 1
     * Prepare order to pay.
103
     *
104
     * @param Order $order
105
     *
106
     * @return \EasyWeChat\Support\Collection
107
     */
108
    public function prepare(Order $order)
109
    {
110
        $order->notify_url = $order->get('notify_url', $this->merchant->notify_url);
0 ignored issues
show
Documentation introduced by
The property notify_url does not exist on object<EasyWeChat\Payment\Merchant>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
111
        if (is_null($order->spbill_create_ip)) {
112
            $order->spbill_create_ip = ($order->trade_type === Order::NATIVE) ? get_server_ip() : get_client_ip();
113 1
        }
114
115
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_PREPARE_ORDER, $order->all());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API..._ORDER, $order->all()); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 115 which is incompatible with the return type documented by EasyWeChat\Payment\API::prepare of type EasyWeChat\Support\Collection.
Loading history...
116 1
    }
117 1
118
    /**
119 1
     * Query order.
120
     *
121
     * @param string $orderNo
122
     * @param string $type
123
     *
124
     * @return \EasyWeChat\Support\Collection
125
     */
126 View Code Duplication
    public function query($orderNo, $type = self::OUT_TRADE_NO)
127
    {
128
        $params = [
129 1
            $type => $orderNo,
130
        ];
131 1
132
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_QUERY, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...f::API_QUERY, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 132 which is incompatible with the return type documented by EasyWeChat\Payment\API::query of type EasyWeChat\Support\Collection.
Loading history...
133
    }
134
135
    /**
136
     * Query order by transaction_id.
137
     *
138
     * @param string $transactionId
139
     *
140
     * @return \EasyWeChat\Support\Collection
141 1
     */
142
    public function queryByTransactionId($transactionId)
143
    {
144 1
        return $this->query($transactionId, self::TRANSACTION_ID);
145 1
    }
146
147 1
    /**
148
     * Close order by out_trade_no.
149
     *
150
     * @param $tradeNo
151
     *
152
     * @return \EasyWeChat\Support\Collection
153
     */
154
    public function close($tradeNo)
155
    {
156
        $params = [
157
            'out_trade_no' => $tradeNo,
158 1
        ];
159
160
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_CLOSE, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...f::API_CLOSE, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 160 which is incompatible with the return type documented by EasyWeChat\Payment\API::close of type EasyWeChat\Support\Collection.
Loading history...
161 1
    }
162 1
163
    /**
164 1
     * Reverse order.
165
     *
166
     * @param string $orderNo
167
     * @param string $type
168
     *
169
     * @return \EasyWeChat\Support\Collection
170
     */
171
    public function reverse($orderNo, $type = self::OUT_TRADE_NO)
172
    {
173
        $params = [
174
            $type => $orderNo,
175
        ];
176
177
        return $this->safeRequest(self::API_ENDPOINT . $this->sandboxMode . self::API_REVERSE, $params);
178
    }
179
180
    /**
181
     * Reverse order by transaction_id.
182
     *
183
     * @param int $transactionId
184
     *
185
     * @return \EasyWeChat\Support\Collection
186
     */
187
    public function reverseByTransactionId($transactionId)
188
    {
189
        return $this->reverse($transactionId, self::TRANSACTION_ID);
190
    }
191 1
192
    /**
193
     * Make a refund request.
194
     *
195
     * @param string $orderNo
196
     * @param float  $totalFee
197
     * @param float  $refundFee
198
     * @param string $opUserId
199
     * @param string $type
200
     * @param string $refundAccount
201 1
     *
202 1
     * @return \EasyWeChat\Support\Collection
203 1
     */
204 1
    public function refund(
205 1
        $orderNo,
206 1
        $refundNo,
207 1
        $totalFee,
208 1
        $refundFee = null,
209
        $opUserId = null,
210 1
        $type = self::OUT_TRADE_NO,
211
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
212
        ) {
213
        $params = [
214
            $type => $orderNo,
215
            'out_refund_no' => $refundNo,
216
            'total_fee' => $totalFee,
217
            'refund_fee' => $refundFee ?: $totalFee,
218
            'refund_fee_type' => $this->merchant->fee_type,
219
            'refund_account' => $refundAccount,
220
            'op_user_id' => $opUserId ?: $this->merchant->merchant_id,
221
        ];
222
223
        return $this->safeRequest(self::API_ENDPOINT . $this->sandboxMode . self::API_REFUND, $params);
224
    }
225
226
    /**
227
     * Refund by transaction id.
228
     *
229
     * @param string $orderNo
230
     * @param float  $totalFee
231
     * @param float  $refundFee
232
     * @param string $opUserId
233
     * @param string $refundAccount
234
     *
235
     * @return \EasyWeChat\Support\Collection
236
     */
237
    public function refundByTransactionId(
238
        $orderNo,
239
        $refundNo,
240
        $totalFee,
241
        $refundFee = null,
242
        $opUserId = null,
243 1
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
244
        ) {
245
        return $this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, self::TRANSACTION_ID, $refundAccount);
246 1
    }
247 1
248
    /**
249 1
     * Query refund status.
250
     *
251
     * @param string $orderNo
252
     * @param string $type
253
     *
254
     * @return \EasyWeChat\Support\Collection
255
     */
256 View Code Duplication
    public function queryRefund($orderNo, $type = self::OUT_TRADE_NO)
257
    {
258
        $params = [
259
            $type => $orderNo,
260
        ];
261
262
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_QUERY_REFUND, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...QUERY_REFUND, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 262 which is incompatible with the return type documented by EasyWeChat\Payment\API::queryRefund of type EasyWeChat\Support\Collection.
Loading history...
263
    }
264
265
    /**
266
     * Query refund status by out_refund_no.
267
     *
268
     * @param string $refundNo
269
     *
270
     * @return \EasyWeChat\Support\Collection
271
     */
272
    public function queryRefundByRefundNo($refundNo)
273
    {
274
        return $this->queryRefund($refundNo, self::OUT_REFUND_NO);
275
    }
276
277
    /**
278
     * Query refund status by transaction_id.
279
     *
280
     * @param string $transactionId
281
     *
282
     * @return \EasyWeChat\Support\Collection
283
     */
284
    public function queryRefundByTransactionId($transactionId)
285
    {
286
        return $this->queryRefund($transactionId, self::TRANSACTION_ID);
287
    }
288
289
    /**
290
     * Query refund status by refund_id.
291
     *
292
     * @param string $refundId
293
     *
294
     * @return \EasyWeChat\Support\Collection
295
     */
296 1
    public function queryRefundByRefundId($refundId)
297
    {
298
        return $this->queryRefund($refundId, self::REFUND_ID);
299 1
    }
300 1
301 1
    /**
302
     * Download bill history as a table file.
303 1
     *
304
     * @param string $date
305
     * @param string $type
306
     *
307
     * @return \Psr\Http\Message\ResponseInterface
308
     */
309
    public function downloadBill($date, $type = self::BILL_TYPE_ALL)
310
    {
311
        $params = [
312
            'bill_date' => $date,
313 1
            'bill_type' => $type,
314
        ];
315 1
316
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_DOWNLOAD_BILL, $params, 'post', [\GuzzleHttp\RequestOptions::STREAM => true], true)->getBody();
0 ignored issues
show
Bug introduced by
The method getBody does only exist in Psr\Http\Message\ResponseInterface, but not in EasyWeChat\Support\Collection.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
317
    }
318
319
    /**
320
     * Convert long url to short url.
321
     *
322
     * @param string $url
323
     *
324
     * @return \EasyWeChat\Support\Collection
325
     */
326
    public function urlShorten($url)
327
    {
328
        return $this->request(self::API_URL_SHORTEN, ['long_url' => $url]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...y('long_url' => $url)); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 328 which is incompatible with the return type documented by EasyWeChat\Payment\API::urlShorten of type EasyWeChat\Support\Collection.
Loading history...
329
    }
330
331
    /**
332
     * Report API status to WeChat.
333
     *
334
     * @param string $api
335
     * @param int    $timeConsuming
336
     * @param string $resultCode
337
     * @param string $returnCode
338
     * @param array  $other         ex: err_code,err_code_des,out_trade_no,user_ip...
339
     *
340
     * @return \EasyWeChat\Support\Collection
341
     */
342
    public function report($api, $timeConsuming, $resultCode, $returnCode, array $other = [])
343
    {
344
        $params = array_merge([
345
            'interface_url' => $api,
346
            'execute_time_' => $timeConsuming,
347
            'return_code' => $returnCode,
348
            'return_msg' => null,
349
            'result_code' => $resultCode,
350
            'user_ip' => get_client_ip(),
351 1
            'time' => time(),
352
        ], $other);
353 1
354
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_REPORT, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...::API_REPORT, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 354 which is incompatible with the return type documented by EasyWeChat\Payment\API::report of type EasyWeChat\Support\Collection.
Loading history...
355
    }
356
357
    /**
358
     * Get openid by auth code.
359
     *
360
     * @param string $authCode
361
     *
362
     * @return \EasyWeChat\Support\Collection
363 1
     */
364
    public function authCodeToOpenId($authCode)
365 1
    {
366 1
        return $this->request(self::API_ENDPOINT . $this->sandboxMode . self::API_AUTH_CODE_TO_OPENID, ['auth_code' => $authCode]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...h_code' => $authCode)); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 366 which is incompatible with the return type documented by EasyWeChat\Payment\API::authCodeToOpenId of type EasyWeChat\Support\Collection.
Loading history...
367
    }
368
369
    /**
370
     * Merchant setter.
371
     *
372
     * @param Merchant $merchant
373 1
     *
374
     * @return $this
375 1
     */
376
    public function setMerchant(Merchant $merchant)
377
    {
378
        $this->merchant = $merchant;
379
    }
380
381
    /**
382
     * Merchant getter.
383
     *
384
     * @return Merchant
385
     */
386
    public function getMerchant()
387
    {
388
        return $this->merchant;
389 10
    }
390
391 10
    /**
392
     * Make a API request.
393 10
     *
394 10
     * @param string $api
395 10
     * @param array  $params
396 10
     * @param string $method
397 10
     * @param array  $options
398 10
     * @param bool   $returnResponse
399
     *
400 10
     * @return \EasyWeChat\Support\Collection|\Psr\Http\Message\ResponseInterface
401 10
     */
402 10
    protected function request($api, array $params, $method = 'post', array $options = [], $returnResponse = false)
403
    {
404 10
        $params = array_merge($params, $this->merchant->only(['sub_appid', 'sub_mch_id']));
405
406 10
        $params['appid'] = $this->merchant->app_id;
407
        $params['mch_id'] = $this->merchant->merchant_id;
408
        $params['device_info'] = $this->merchant->device_info;
409
        $params['nonce_str'] = uniqid();
410
        $params = array_filter($params);
411
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
412
413
        $options = array_merge([
414
            'body' => XML::build($params),
415
        ], $options);
416
417
        $response = $this->getHttp()->request($api, $method, $options);
418 2
419
        return $returnResponse ? $response : $this->parseResponse($response);
420
    }
421 2
422 2
    /**
423 2
     * Request with SSL.
424
     *
425 2
     * @param string $api
426
     * @param array  $params
427
     * @param string $method
428
     *
429
     * @return \EasyWeChat\Support\Collection
430
     */
431
    protected function safeRequest($api, array $params, $method = 'post')
432
    {
433
        $options = [
434
            'cert' => $this->merchant->get('cert_path'),
435 9
            'ssl_key' => $this->merchant->get('key_path'),
436
        ];
437 9
438
        return $this->request($api, $params, $method, $options);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($api, $params, $method, $options); of type Psr\Http\Message\Respons...Chat\Support\Collection adds the type Psr\Http\Message\ResponseInterface to the return on line 438 which is incompatible with the return type documented by EasyWeChat\Payment\API::safeRequest of type EasyWeChat\Support\Collection.
Loading history...
439
    }
440
441 9
    /**
442
     * Parse Response XML to array.
443
     *
444
     * @param ResponseInterface $response
445
     *
446
     * @return \EasyWeChat\Support\Collection
447
     */
448
    protected function parseResponse($response)
449
    {
450
        if ($response instanceof ResponseInterface) {
451
            $response = $response->getBody();
452
        }
453
454
        return new Collection((array) XML::parse($response));
455
    }
456
457
    /**
458
     * Set sandbox mode
459
     *
460
     * @param bool $mode
461
     */
462
    public function enableSandbox($mode)
463
    {
464
        if ($mode == TRUE) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
465
            $this->sandboxMode = '/sandbox';
466
        } else {
467
            $this->sandboxMode = '';
468
        }
469
    }
470
}
471