Payment::handleNotify()   B
last analyzed

Complexity

Conditions 4
Paths 3

Size

Total Lines 27
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 16
nc 3
nop 1
dl 0
loc 27
rs 8.5806
c 0
b 0
f 0
1
<?php
2
3
namespace EntWeChat\Payment;
4
5
use EntWeChat\Core\Exceptions\FaultException;
6
use EntWeChat\Support\Url as UrlHelper;
7
use EntWeChat\Support\XML;
8
use Overtrue\Socialite\AccessTokenInterface;
9
use Symfony\Component\HttpFoundation\Response;
10
11
/**
12
 * Class Payment.
13
 *
14
 * @mixin API
15
 */
16
class Payment
17
{
18
    /**
19
     * Scheme base path.
20
     */
21
    const SCHEME_PATH = 'weixin://wxpay/bizpayurl';
22
23
    /**
24
     * @var API
25
     */
26
    protected $api;
27
28
    /**
29
     * Merchant instance.
30
     *
31
     * @var \EntWeChat\Payment\Merchant
32
     */
33
    protected $merchant;
34
35
    /**
36
     * Constructor.
37
     *
38
     * @param Merchant $merchant
39
     */
40
    public function __construct(Merchant $merchant)
41
    {
42
        $this->merchant = $merchant;
43
    }
44
45
    /**
46
     * Build payment scheme for product.
47
     *
48
     * @param string $productId
49
     *
50
     * @return string
51
     */
52
    public function scheme($productId)
53
    {
54
        $params = [
55
            'appid'      => $this->merchant->app_id,
56
            'mch_id'     => $this->merchant->merchant_id,
57
            'time_stamp' => time(),
58
            'nonce_str'  => uniqid(),
59
            'product_id' => $productId,
60
        ];
61
62
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
63
64
        return self::SCHEME_PATH.'?'.http_build_query($params);
65
    }
66
67
    /**
68
     * Handle payment notify.
69
     *
70
     * @param callable $callback
71
     *
72
     * @return Response
73
     */
74
    public function handleNotify(callable $callback)
75
    {
76
        $notify = $this->getNotify();
77
78
        if (!$notify->isValid()) {
79
            throw new FaultException('Invalid request payloads.', 400);
80
        }
81
82
        $notify = $notify->getNotify();
83
        $successful = $notify->get('result_code') === 'SUCCESS';
84
85
        $handleResult = call_user_func_array($callback, [$notify, $successful]);
86
87
        if (is_bool($handleResult) && $handleResult) {
88
            $response = [
89
                'return_code' => 'SUCCESS',
90
                'return_msg'  => 'OK',
91
            ];
92
        } else {
93
            $response = [
94
                'return_code' => 'FAIL',
95
                'return_msg'  => $handleResult,
96
            ];
97
        }
98
99
        return new Response(XML::build($response));
100
    }
101
102
    /**
103
     * Handle native scan notify.
104
     * https://pay.weixin.qq.com/wiki/doc/api/native.php?chapter=6_4
105
     * The callback shall return string of prepay_id or throw an exception.
106
     *
107
     * @param callable $callback
108
     *
109
     * @return Response
110
     */
111
    public function handleScanNotify(callable $callback)
112
    {
113
        $notify = $this->getNotify();
114
115
        if (!$notify->isValid()) {
116
            throw new FaultException('Invalid request payloads.', 400);
117
        }
118
119
        $notify = $notify->getNotify();
120
121
        try {
122
            $prepayId = call_user_func_array($callback, [$notify->get('product_id'), $notify->get('openid'), $notify]);
123
            $response = [
124
                'return_code' => 'SUCCESS',
125
                'appid'       => $this->merchant->app_id,
126
                'mch_id'      => $this->merchant->merchant_id,
127
                'nonce_str'   => uniqid(),
128
                'prepay_id'   => strval($prepayId),
129
                'result_code' => 'SUCCESS',
130
            ];
131
            $response['sign'] = generate_sign($response, $this->merchant->key);
132
        } catch (\Exception $e) {
133
            $response = [
134
                'return_code'  => 'SUCCESS',
135
                'return_msg'   => $e->getCode(),
136
                'result_code'  => 'FAIL',
137
                'err_code_des' => $e->getMessage(),
138
            ];
139
        }
140
141
        return new Response(XML::build($response));
142
    }
143
144
    /**
145
     * [WeixinJSBridge] Generate js config for payment.
146
     *
147
     * <pre>
148
     * WeixinJSBridge.invoke(
149
     *  'getBrandWCPayRequest',
150
     *  ...
151
     * );
152
     * </pre>
153
     *
154
     * @param string $prepayId
155
     * @param bool   $json
156
     *
157
     * @return string|array
158
     */
159
    public function configForPayment($prepayId, $json = true)
160
    {
161
        $params = [
162
            'appId'     => $this->merchant->app_id,
163
            'timeStamp' => strval(time()),
164
            'nonceStr'  => uniqid(),
165
            'package'   => "prepay_id=$prepayId",
166
            'signType'  => 'MD5',
167
        ];
168
169
        $params['paySign'] = generate_sign($params, $this->merchant->key, 'md5');
170
171
        return $json ? json_encode($params) : $params;
172
    }
173
174
    /**
175
     * [JSSDK] Generate js config for payment.
176
     *
177
     * <pre>
178
     * wx.chooseWXPay({...});
179
     * </pre>
180
     *
181
     * @param string $prepayId
182
     *
183
     * @return array|string
184
     */
185
    public function configForJSSDKPayment($prepayId)
186
    {
187
        $config = $this->configForPayment($prepayId, false);
188
189
        $config['timestamp'] = $config['timeStamp'];
190
        unset($config['timeStamp']);
191
192
        return $config;
193
    }
194
195
    /**
196
     * Generate app payment parameters.
197
     *
198
     * @param string $prepayId
199
     *
200
     * @return array
201
     */
202
    public function configForAppPayment($prepayId)
203
    {
204
        $params = [
205
            'appid'     => $this->merchant->app_id,
206
            'partnerid' => $this->merchant->merchant_id,
207
            'prepayid'  => $prepayId,
208
            'noncestr'  => uniqid(),
209
            'timestamp' => time(),
210
            'package'   => 'Sign=WXPay',
211
        ];
212
213
        $params['sign'] = generate_sign($params, $this->merchant->key);
214
215
        return $params;
216
    }
217
218
    /**
219
     * Generate js config for share user address.
220
     *
221
     * @param string|\Overtrue\Socialite\AccessTokenInterface $accessToken
222
     * @param bool                                            $json
223
     *
224
     * @return string|array
225
     */
226
    public function configForShareAddress($accessToken, $json = true)
227
    {
228
        if ($accessToken instanceof AccessTokenInterface) {
0 ignored issues
show
Bug introduced by
The class Overtrue\Socialite\AccessTokenInterface does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
229
            $accessToken = $accessToken->getToken();
230
        }
231
232
        $params = [
233
            'appId'     => $this->merchant->app_id,
234
            'scope'     => 'jsapi_address',
235
            'timeStamp' => strval(time()),
236
            'nonceStr'  => uniqid(),
237
            'signType'  => 'SHA1',
238
        ];
239
240
        $signParams = [
241
            'appid'       => $params['appId'],
242
            'url'         => UrlHelper::current(),
243
            'timestamp'   => $params['timeStamp'],
244
            'noncestr'    => $params['nonceStr'],
245
            'accesstoken' => strval($accessToken),
246
        ];
247
248
        ksort($signParams);
249
250
        $params['addrSign'] = sha1(urldecode(http_build_query($signParams)));
251
252
        return $json ? json_encode($params) : $params;
253
    }
254
255
    /**
256
     * Merchant setter.
257
     *
258
     * @param Merchant $merchant
259
     */
260
    public function setMerchant(Merchant $merchant)
261
    {
262
        $this->merchant = $merchant;
263
    }
264
265
    /**
266
     * Merchant getter.
267
     *
268
     * @return Merchant
269
     */
270
    public function getMerchant()
271
    {
272
        return $this->merchant;
273
    }
274
275
    /**
276
     * Return Notify instance.
277
     *
278
     * @return \EntWeChat\Payment\Notify
279
     */
280
    public function getNotify()
281
    {
282
        return new Notify($this->merchant);
283
    }
284
285
    /**
286
     * API setter.
287
     *
288
     * @param API $api
289
     */
290
    public function setAPI(API $api)
291
    {
292
        $this->api = $api;
293
    }
294
295
    /**
296
     * Return API instance.
297
     *
298
     * @return API
299
     */
300
    public function getAPI()
301
    {
302
        return $this->api ?: $this->api = new API($this->getMerchant());
303
    }
304
305
    /**
306
     * Magic call.
307
     *
308
     * @param string $method
309
     * @param array  $args
310
     *
311
     * @return mixed
312
     *
313
     * @codeCoverageIgnore
314
     */
315
    public function __call($method, $args)
316
    {
317
        if (is_callable([$this->getAPI(), $method])) {
318
            return call_user_func_array([$this->api, $method], $args);
319
        }
320
    }
321
}
322