Completed
Push — master ( cc1d01...0c66f9 )
by Carlos
36:33 queued 12:36
created

API::wrapApi()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 2
nc 2
nop 1
dl 0
loc 4
ccs 0
cts 0
cp 0
crap 6
rs 10
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 bool
45
     */
46
    protected $sandboxEnabled = false;
47
48
    const API_HOST = 'https://api.mch.weixin.qq.com';
49
50
    // api
51
    const API_PAY_ORDER = '/pay/micropay';
52
    const API_PREPARE_ORDER = '/pay/unifiedorder';
53
    const API_QUERY = '/pay/orderquery';
54
    const API_CLOSE = '/pay/closeorder';
55
    const API_REVERSE = '/secapi/pay/reverse';
56
    const API_REFUND = '/secapi/pay/refund';
57
    const API_QUERY_REFUND = '/pay/refundquery';
58
    const API_DOWNLOAD_BILL = '/pay/downloadbill';
59
    const API_REPORT = '/payitil/report';
60
    const API_URL_SHORTEN = '/tools/shorturl';
61
    const API_AUTH_CODE_TO_OPENID = '/tools/authcodetoopenid';
62
63
    // order id types.
64
    const TRANSACTION_ID = 'transaction_id';
65
    const OUT_TRADE_NO = 'out_trade_no';
66
    const OUT_REFUND_NO = 'out_refund_no';
67
    const REFUND_ID = 'refund_id';
68
69
    // bill types.
70
    const BILL_TYPE_ALL = 'ALL';
71 12
    const BILL_TYPE_SUCCESS = 'SUCCESS';
72
    const BILL_TYPE_REFUND = 'REFUND';
73 12
    const BILL_TYPE_REVOKED = 'REVOKED';
74 12
75
    /**
76
     * API constructor.
77
     *
78
     * @param \EasyWeChat\Payment\Merchant $merchant
79
     */
80
    public function __construct(Merchant $merchant)
81
    {
82
        $this->merchant = $merchant;
83 1
    }
84
85 1
    /**
86
     * Pay the order.
87
     *
88
     * @param Order $order
89
     *
90
     * @return \EasyWeChat\Support\Collection
91
     */
92
    public function pay(Order $order)
93
    {
94
        return $this->request($this->wrapApi(self::API_PAY_ORDER), $order->all());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...ORDER), $order->all()); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 94 which is incompatible with the return type documented by EasyWeChat\Payment\API::pay of type EasyWeChat\Support\Collection.
Loading history...
95 1
    }
96
97 1
    /**
98 1
     * Prepare order to pay.
99 1
     *
100 1
     * @param Order $order
101
     *
102 1
     * @return \EasyWeChat\Support\Collection
103
     */
104
    public function prepare(Order $order)
105
    {
106
        $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...
107
        if (is_null($order->spbill_create_ip)) {
108
            $order->spbill_create_ip = ($order->trade_type === Order::NATIVE) ? get_server_ip() : get_client_ip();
109
        }
110
111
        return $this->request($this->wrapApi(self::API_PREPARE_ORDER), $order->all());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...ORDER), $order->all()); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 111 which is incompatible with the return type documented by EasyWeChat\Payment\API::prepare of type EasyWeChat\Support\Collection.
Loading history...
112
    }
113 1
114
    /**
115
     * Query order.
116 1
     *
117 1
     * @param string $orderNo
118
     * @param string $type
119 1
     *
120
     * @return \EasyWeChat\Support\Collection
121
     */
122 View Code Duplication
    public function query($orderNo, $type = self::OUT_TRADE_NO)
123
    {
124
        $params = [
125
            $type => $orderNo,
126
        ];
127
128
        return $this->request($this->wrapApi(self::API_QUERY), $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...::API_QUERY), $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 128 which is incompatible with the return type documented by EasyWeChat\Payment\API::query of type EasyWeChat\Support\Collection.
Loading history...
129 1
    }
130
131 1
    /**
132
     * Query order by transaction_id.
133
     *
134
     * @param string $transactionId
135
     *
136
     * @return \EasyWeChat\Support\Collection
137
     */
138
    public function queryByTransactionId($transactionId)
139
    {
140
        return $this->query($transactionId, self::TRANSACTION_ID);
141 1
    }
142
143
    /**
144 1
     * Close order by out_trade_no.
145 1
     *
146
     * @param $tradeNo
147 1
     *
148
     * @return \EasyWeChat\Support\Collection
149
     */
150
    public function close($tradeNo)
151
    {
152
        $params = [
153
            'out_trade_no' => $tradeNo,
154
        ];
155
156
        return $this->request($this->wrapApi(self::API_CLOSE), $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...::API_CLOSE), $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 156 which is incompatible with the return type documented by EasyWeChat\Payment\API::close of type EasyWeChat\Support\Collection.
Loading history...
157
    }
158 1
159
    /**
160
     * Reverse order.
161 1
     *
162 1
     * @param string $orderNo
163
     * @param string $type
164 1
     *
165
     * @return \EasyWeChat\Support\Collection
166
     */
167
    public function reverse($orderNo, $type = self::OUT_TRADE_NO)
168
    {
169
        $params = [
170
            $type => $orderNo,
171
        ];
172
173
        return $this->safeRequest($this->wrapApi(self::API_REVERSE), $params);
174
    }
175
176
    /**
177
     * Reverse order by transaction_id.
178
     *
179
     * @param int $transactionId
180
     *
181
     * @return \EasyWeChat\Support\Collection
182
     */
183
    public function reverseByTransactionId($transactionId)
184
    {
185
        return $this->reverse($transactionId, self::TRANSACTION_ID);
186
    }
187
188
    /**
189
     * Make a refund request.
190
     *
191 1
     * @param string $orderNo
192
     * @param float  $totalFee
193
     * @param float  $refundFee
194
     * @param string $opUserId
195
     * @param string $type
196
     * @param string $refundAccount
197
     *
198
     * @return \EasyWeChat\Support\Collection
199
     */
200
    public function refund(
201 1
        $orderNo,
202 1
        $refundNo,
203 1
        $totalFee,
204 1
        $refundFee = null,
205 1
        $opUserId = null,
206 1
        $type = self::OUT_TRADE_NO,
207 1
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
208 1
        ) {
209
        $params = [
210 1
            $type => $orderNo,
211
            'out_refund_no' => $refundNo,
212
            'total_fee' => $totalFee,
213
            'refund_fee' => $refundFee ?: $totalFee,
214
            'refund_fee_type' => $this->merchant->fee_type,
215
            'refund_account' => $refundAccount,
216
            'op_user_id' => $opUserId ?: $this->merchant->merchant_id,
217
        ];
218
219
        return $this->safeRequest($this->wrapApi(self::API_REFUND), $params);
220
    }
221
222
    /**
223
     * Refund by transaction id.
224
     *
225
     * @param string $orderNo
226
     * @param float  $totalFee
227
     * @param float  $refundFee
228
     * @param string $opUserId
229
     * @param string $refundAccount
230
     *
231
     * @return \EasyWeChat\Support\Collection
232
     */
233
    public function refundByTransactionId(
234
        $orderNo,
235
        $refundNo,
236
        $totalFee,
237
        $refundFee = null,
238
        $opUserId = null,
239
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
240
        ) {
241
        return $this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, self::TRANSACTION_ID, $refundAccount);
242
    }
243 1
244
    /**
245
     * Query refund status.
246 1
     *
247 1
     * @param string $orderNo
248
     * @param string $type
249 1
     *
250
     * @return \EasyWeChat\Support\Collection
251
     */
252 View Code Duplication
    public function queryRefund($orderNo, $type = self::OUT_TRADE_NO)
253
    {
254
        $params = [
255
            $type => $orderNo,
256
        ];
257
258
        return $this->request($this->wrapApi(self::API_QUERY_REFUND), $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...UERY_REFUND), $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 258 which is incompatible with the return type documented by EasyWeChat\Payment\API::queryRefund of type EasyWeChat\Support\Collection.
Loading history...
259
    }
260
261
    /**
262
     * Query refund status by out_refund_no.
263
     *
264
     * @param string $refundNo
265
     *
266
     * @return \EasyWeChat\Support\Collection
267
     */
268
    public function queryRefundByRefundNo($refundNo)
269
    {
270
        return $this->queryRefund($refundNo, self::OUT_REFUND_NO);
271
    }
272
273
    /**
274
     * Query refund status by transaction_id.
275
     *
276
     * @param string $transactionId
277
     *
278
     * @return \EasyWeChat\Support\Collection
279
     */
280
    public function queryRefundByTransactionId($transactionId)
281
    {
282
        return $this->queryRefund($transactionId, self::TRANSACTION_ID);
283
    }
284
285
    /**
286
     * Query refund status by refund_id.
287
     *
288
     * @param string $refundId
289
     *
290
     * @return \EasyWeChat\Support\Collection
291
     */
292
    public function queryRefundByRefundId($refundId)
293
    {
294
        return $this->queryRefund($refundId, self::REFUND_ID);
295
    }
296 1
297
    /**
298
     * Download bill history as a table file.
299 1
     *
300 1
     * @param string $date
301 1
     * @param string $type
302
     *
303 1
     * @return \Psr\Http\Message\ResponseInterface
304
     */
305
    public function downloadBill($date, $type = self::BILL_TYPE_ALL)
306
    {
307
        $params = [
308
            'bill_date' => $date,
309
            'bill_type' => $type,
310
        ];
311
312
        return $this->request($this->wrapApi(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...
313 1
    }
314
315 1
    /**
316
     * Convert long url to short url.
317
     *
318
     * @param string $url
319
     *
320
     * @return \EasyWeChat\Support\Collection
321
     */
322
    public function urlShorten($url)
323
    {
324
        return $this->request($this->wrapApi(self::API_URL_SHORTEN), ['long_url' => $url]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...y('long_url' => $url)); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 324 which is incompatible with the return type documented by EasyWeChat\Payment\API::urlShorten of type EasyWeChat\Support\Collection.
Loading history...
325
    }
326
327
    /**
328
     * Report API status to WeChat.
329
     *
330
     * @param string $api
331
     * @param int    $timeConsuming
332
     * @param string $resultCode
333
     * @param string $returnCode
334
     * @param array  $other         ex: err_code,err_code_des,out_trade_no,user_ip...
335
     *
336
     * @return \EasyWeChat\Support\Collection
337
     */
338
    public function report($api, $timeConsuming, $resultCode, $returnCode, array $other = [])
339
    {
340
        $params = array_merge([
341
            'interface_url' => $api,
342
            'execute_time_' => $timeConsuming,
343
            'return_code' => $returnCode,
344
            'return_msg' => null,
345
            'result_code' => $resultCode,
346
            'user_ip' => get_client_ip(),
347
            'time' => time(),
348
        ], $other);
349
350
        return $this->request($this->wrapApi(self::API_REPORT), $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...:API_REPORT), $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 350 which is incompatible with the return type documented by EasyWeChat\Payment\API::report of type EasyWeChat\Support\Collection.
Loading history...
351 1
    }
352
353 1
    /**
354
     * Get openid by auth code.
355
     *
356
     * @param string $authCode
357
     *
358
     * @return \EasyWeChat\Support\Collection
359
     */
360
    public function authCodeToOpenId($authCode)
361
    {
362
        return $this->request($this->wrapApi(self::API_AUTH_CODE_TO_OPENID), ['auth_code' => $authCode]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($this->wr...h_code' => $authCode)); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 362 which is incompatible with the return type documented by EasyWeChat\Payment\API::authCodeToOpenId of type EasyWeChat\Support\Collection.
Loading history...
363 1
    }
364
365 1
    /**
366 1
     * Merchant setter.
367
     *
368
     * @param Merchant $merchant
369
     *
370
     * @return $this
371
     */
372
    public function setMerchant(Merchant $merchant)
373 1
    {
374
        $this->merchant = $merchant;
375 1
    }
376
377
    /**
378
     * Merchant getter.
379
     *
380
     * @return Merchant
381
     */
382
    public function getMerchant()
383
    {
384
        return $this->merchant;
385
    }
386
387
    /**
388
     * Make a API request.
389 10
     *
390
     * @param string $api
391 10
     * @param array  $params
392
     * @param string $method
393 10
     * @param array  $options
394 10
     * @param bool   $returnResponse
395 10
     *
396 10
     * @return \EasyWeChat\Support\Collection|\Psr\Http\Message\ResponseInterface
397 10
     */
398 10
    protected function request($api, array $params, $method = 'post', array $options = [], $returnResponse = false)
399
    {
400 10
        $params = array_merge($params, $this->merchant->only(['sub_appid', 'sub_mch_id']));
401 10
402 10
        $params['appid'] = $this->merchant->app_id;
403
        $params['mch_id'] = $this->merchant->merchant_id;
404 10
        $params['device_info'] = $this->merchant->device_info;
405
        $params['nonce_str'] = uniqid();
406 10
        $params = array_filter($params);
407
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
408
409
        $options = array_merge([
410
            'body' => XML::build($params),
411
        ], $options);
412
413
        $response = $this->getHttp()->request($api, $method, $options);
414
415
        return $returnResponse ? $response : $this->parseResponse($response);
416
    }
417
418 2
    /**
419
     * Request with SSL.
420
     *
421 2
     * @param string $api
422 2
     * @param array  $params
423 2
     * @param string $method
424
     *
425 2
     * @return \EasyWeChat\Support\Collection
426
     */
427
    protected function safeRequest($api, array $params, $method = 'post')
428
    {
429
        $options = [
430
            'cert' => $this->merchant->get('cert_path'),
431
            'ssl_key' => $this->merchant->get('key_path'),
432
        ];
433
434
        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 434 which is incompatible with the return type documented by EasyWeChat\Payment\API::safeRequest of type EasyWeChat\Support\Collection.
Loading history...
435 9
    }
436
437 9
    /**
438
     * Parse Response XML to array.
439
     *
440
     * @param ResponseInterface $response
441 9
     *
442
     * @return \EasyWeChat\Support\Collection
443
     */
444
    protected function parseResponse($response)
445
    {
446
        if ($response instanceof ResponseInterface) {
447
            $response = $response->getBody();
448
        }
449
450
        return new Collection((array) XML::parse($response));
451
    }
452
453
    /**
454
     * Set sandbox mode.
455
     *
456
     * @param bool $enabled
457
     */
458
    public function sandboxMode($enabled = false)
459
    {
460
        $this->sandboxEnabled = $enabled;
461
    }
462
463
    /**
464
     * Wrap sandbox API.
465
     *
466
     * @param string $resource
467
     */
468
    protected function wrapApi($resource)
469
    {
470
        return self::API_HOST.($this->sandboxEnabled ? '/sandbox' : '').$resource;
471
    }
472
}
473