Completed
Push — master ( f0d1a4...bf72bf )
by Elf
09:50
created

XgPusher::encodeCustomData()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
eloc 4
nc 3
nop 1
dl 0
loc 8
ccs 0
cts 7
cp 0
crap 20
rs 9.2
c 0
b 0
f 0
1
<?php
2
3
namespace ElfSundae\Laravel\Support\Services\XgPush;
4
5
use ElfSundae\XgPush\Style;
6
use ElfSundae\XgPush\Message;
7
use ElfSundae\XgPush\XingeApp;
8
use ElfSundae\XgPush\MessageIOS;
9
use ElfSundae\XgPush\ClickAction;
10
use ElfSundae\XgPush\TagTokenPair;
11
12
class XgPusher
13
{
14
    /**
15
     * The XingeApp instance.
16
     *
17
     * @var \ElfSundae\XgPush\XingeApp
18
     */
19
    protected $xinge;
20
21
    /**
22
     * The pusher environment.
23
     *
24
     * 向iOS设备推送时必填,1表示推送生产环境;2表示推送开发环境。推送Android平台不填或填0.
25
     *
26
     * @var int
27
     */
28
    protected $environment = XingeApp::IOSENV_DEV;
29
30
    /**
31
     * The key of custom payload.
32
     *
33
     * @var string
34
     */
35
    protected $customKey;
36
37
    /**
38
     * Xinge account prefix.
39
     *
40
     * @warning 信鸽不允许使用简单的账号,例如纯数字的id。
41
     *
42
     * @var string
43
     */
44
    protected $accountPrefix;
45
46
    /**
47
     * Create a new instance.
48
     *
49
     * @param  string  $appKey
50
     * @param  string  $appSecret
51
     */
52
    public function __construct($appKey, $appSecret)
53
    {
54
        $this->xinge = new XingeApp($appKey, $appSecret);
55
    }
56
57
    /**
58
     * Get the XingeApp instance.
59
     *
60
     * @return \ElfSundae\XgPush\XingeApp
61
     */
62
    public function xinge()
63
    {
64
        return $this->xinge;
65
    }
66
67
    /**
68
     * Get the app key.
69
     *
70
     * @return string
71
     */
72
    public function getAppKey()
73
    {
74
        return $this->xinge->accessId;
75
    }
76
77
    /**
78
     * Get the app secret.
79
     *
80
     * @return string
81
     */
82
    public function getAppSecret()
83
    {
84
        return $this->xinge->secretKey;
85
    }
86
87
    /**
88
     * Get the pusher environment.
89
     *
90
     * @return int
91
     */
92
    public function getEnvironment()
93
    {
94
        return $this->environment;
95
    }
96
97
    /**
98
     * Set the pusher environment.
99
     *
100
     * @param  mixed  $env
101
     * @return $this
102
     */
103
    public function setEnvironment($env)
104
    {
105
        if (is_string($env)) {
106
            $env = $env == 'production' ? XingeApp::IOSENV_PROD : XingeApp::IOSENV_DEV;
107
        }
108
109
        if (is_int($env)) {
110
            $this->environment = $env;
111
        }
112
113
        return $this;
114
    }
115
116
    /**
117
     * Get the key of custom payload.
118
     *
119
     * @return string|null
120
     */
121
    public function getCustomKey()
122
    {
123
        return $this->customKey;
124
    }
125
126
    /**
127
     * Set the key of custom payload.
128
     *
129
     * @param  string|null  $key
130
     * @return $this
131
     */
132
    public function setCustomKey($key)
133
    {
134
        $this->customKey = $key;
135
136
        return $this;
137
    }
138
139
    /**
140
     * Get the account prefix.
141
     *
142
     * @return string
143
     */
144
    public function getAccountPrefix()
145
    {
146
        return $this->accountPrefix;
147
    }
148
149
    /**
150
     * Set the account prefix.
151
     *
152
     * @param  string  $prefix
153
     * @return $this
154
     */
155
    public function setAccountPrefix($prefix)
156
    {
157
        $this->accountPrefix = $prefix;
158
159
        return $this;
160
    }
161
162
    /**
163
     * Determine if the Xinge response is success.
164
     *
165
     * @see http://developer.qq.com/wiki/xg/%E6%9C%8D%E5%8A%A1%E7%AB%AFAPI%E6%8E%A5%E5%85%A5/Rest%20API%20%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97/Rest%20API%20%E4%BD%BF%E7%94%A8%E6%8C%87%E5%8D%97.html
166
     *
167
     * @param  mixed  $response
168
     * @return bool
169
     */
170
    public function succeed($response)
171
    {
172
        return $this->code($response) === 0;
173
    }
174
175
    /**
176
     * Get the code of Xinge response.
177
     *
178
     * @param  mixed  $response
179
     * @return int|null
180
     */
181
    public function code($response)
182
    {
183
        if (is_array($response)) {
184
            return array_get($response, 'ret_code');
185
        }
186
    }
187
188
    /**
189
     * Get the error message of Xinge response.
190
     *
191
     * @param  mixed  $response
192
     * @return string|null
193
     */
194
    public function message($response)
195
    {
196
        if (is_array($response)) {
197
            return array_get($response, 'err_msg');
198
        }
199
    }
200
201
    /**
202
     * Get the result data of Xinge response.
203
     *
204
     * @param  mixed  $response
205
     * @param  string  $key
206
     * @param  mixed  $default
207
     * @return mixed
208
     */
209
    public function result($response, $key = null, $default = null)
210
    {
211
        if (is_array($response)) {
212
            return array_get($response, $key ? "result.{$key}" : 'result', $default);
213
        }
214
    }
215
216
    /**
217
     * Encode the custom data.
218
     *
219
     * @param  mixed  $data
220
     * @return array
221
     */
222
    public function encodeCustomData($data)
223
    {
224
        if ($this->customKey && $data) {
225
            return [$this->customKey => $data];
226
        }
227
228
        return $data ?: [];
229
    }
230
231
    /**
232
     * Get Xinge account for the given user.
233
     *
234
     * @param  mixed  $user
235
     * @return string
236
     */
237
    public function accountForUser($user)
238
    {
239
        if ($this->accountPrefix && is_string($user) && starts_with($user, $this->accountPrefix)) {
240
            return $user;
241
        }
242
243 View Code Duplication
        if (is_object($user)) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
244
            $user = $user->id;
245
        } elseif (is_array($user)) {
246
            $user = $user['id'];
247
        }
248
249
        return $this->accountPrefix.$user;
250
    }
251
252
    /**
253
     * Get Xinge accounts for users.
254
     *
255
     * @param  array $users
256
     * @return array
257
     */
258
    public function accountsForUsers(array $users)
259
    {
260
        return array_map([$this, 'accountForUser'], $users);
261
    }
262
263
    /**
264
     * Creates a new MessageIOS instance.
265
     *
266
     * @param  string  $alert
267
     * @param  mixed  $custom
268
     * @param  int  $badge
269
     * @param  string  $sound
270
     * @return \ElfSundae\XgPush\MessageIOS
271
     */
272
    public function createIOSMessage($alert = '', $custom = null, $badge = 1, $sound = 'default')
273
    {
274
        $message = new MessageIOS();
275
        $message->setAlert($alert);
276
        $message->setCustom($this->encodeCustomData($custom));
277
        if (is_int($badge) && $badge >= 0) {
278
            $message->setBadge($badge);
279
        }
280
        if ($sound) {
281
            $message->setSound($sound);
282
        }
283
284
        return $message;
285
    }
286
287
    /**
288
     * Create a new Message instance.
289
     *
290
     * @param  string  $title
291
     * @param  string  $content
292
     * @param  mixed  $custom
293
     * @param  int  $type
294
     * @return \ElfSundae\XgPush\Message
295
     */
296
    public function createAndroidMessage($title = '', $content = '', $custom = null, $type = Message::TYPE_MESSAGE)
297
    {
298
        $message = new Message();
299
        $message->setTitle($title);
300
        $message->setContent($content);
301
        $message->setCustom($this->encodeCustomData($custom));
302
        $message->setType($type);
303
304
        return $message;
305
    }
306
307
    /**
308
     * Create a new Message instance for notification.
309
     * The default action is opening app.
310
     *
311
     * @param  string  $title
312
     * @param  string  $content
313
     * @param  mixed  $custom
314
     * @return \ElfSundae\XgPush\Message
315
     */
316
    public function createAndroidNotification($title = '', $content = '', $custom = null)
317
    {
318
        $message = $this->createAndroidMessage($title, $content, $custom, Message::TYPE_NOTIFICATION);
319
320
        $message->setStyle(new Style(0, 1, 1, 1, 0));
321
        $action = new ClickAction();
322
        $action->setActionType(ClickAction::TYPE_ACTIVITY);
323
        $message->setAction($action);
324
325
        return $message;
326
    }
327
328
    /**
329
     * Push message to a device.
330
     *
331
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
332
     * @param  string  $deviceToken
333
     * @return array
334
     */
335
    public function toDevice($message, $deviceToken)
336
    {
337
        return $this->xinge->PushSingleDevice($deviceToken, $message, $this->environment);
338
    }
339
340
    /**
341
     * Push message to all devices.
342
     *
343
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
344
     * @return array
345
     */
346
    public function toAllDevices($message)
347
    {
348
        return $this->xinge->PushAllDevices(0, $message, $this->environment);
349
    }
350
351
    /**
352
     * Push message to users.
353
     *
354
     * @warning 用户数限制 100 个。
355
     *
356
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
357
     * @param  mixed  $users
358
     * @return array
359
     */
360
    public function toUser($message, $users)
1 ignored issue
show
Unused Code introduced by
The parameter $users is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
361
    {
362
        $users = $this->getParameterAsArray(func_get_args(), 1);
363
        $accounts = $this->accountsForUsers($users);
364
365
        if (count($accounts) == 1) {
366
            return $this->xinge->PushSingleAccount(0, $accounts[0], $message, $this->environment);
367
        }
368
369
        return $this->xinge->PushAccountList(0, $accounts, $message, $this->environment);
370
    }
371
372
    /**
373
     * Push message to tagged devices.
374
     *
375
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
376
     * @param  string|string[]  $tags
377
     * @param  string  $tagsOperation  'OR', 'AND'
378
     * @return array
379
     */
380
    public function toTags($message, $tags, $tagsOperation = 'OR')
381
    {
382
        return $this->xinge->PushTags(0, (array) $tags, strtoupper($tagsOperation), $message, $this->environment);
383
    }
384
385
    /**
386
     * Create a batch push.
387
     *
388
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
389
     * @return string|null
390
     */
391
    public function createBatch($message)
392
    {
393
        return $this->result($this->xinge->CreateMultipush($message, $this->environment), 'push_id');
394
    }
395
396
    /**
397
     * Batch pushing to a list of users.
398
     *
399
     * @warning 用户数限制 1000 个。
400
     *
401
     * @param  int|string  $pushId
402
     * @param  mixed $users
403
     * @return array
404
     */
405
    public function batchToUsers($pushId, $users)
1 ignored issue
show
Unused Code introduced by
The parameter $users is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
406
    {
407
        return $this->xinge->PushAccountListMultiple(
408
            $pushId,
409
            $this->accountsForUsers($this->getParameterAsArray(func_get_args(), 1))
410
        );
411
    }
412
413
    /**
414
     * Batch pushing to a list of devices.
415
     *
416
     * @warning 设备数限制 1000 个。
417
     *
418
     * @param  int|string  $pushId
419
     * @param  mixed  $deviceTokens
420
     * @return array
421
     */
422
    public function batchToDevices($pushId, $deviceTokens)
1 ignored issue
show
Unused Code introduced by
The parameter $deviceTokens is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
423
    {
424
        return $this->xinge->PushDeviceListMultiple(
425
            $pushId,
426
            $this->getParameterAsArray(func_get_args(), 1)
427
        );
428
    }
429
430
    /**
431
     * Query group pushing status.
432
     *
433
     * @param  mixed  $pushIds
434
     * @return array
435
     */
436
    public function queryPushStatus($pushIds)
1 ignored issue
show
Unused Code introduced by
The parameter $pushIds is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
437
    {
438
        $pushIds = $this->getParameterAsArray(func_get_args());
439
440
        $list = $this->result($this->xinge->QueryPushStatus($pushIds), 'list', []);
441
442
        return array_combine(array_pluck($list, 'push_id'), $list);
443
    }
444
445
    /**
446
     * Cancel a timed pushing task that has not been pushed.
447
     *
448
     * @param  string  $pushId
449
     * @return array
450
     */
451
    public function cancelTimedPush($pushId)
452
    {
453
        return $this->xinge->CancelTimingPush($pushId);
454
    }
455
456
    /**
457
     * Query all device tokens for the given user.
458
     *
459
     * @param  mixed  $user
460
     * @return string[]
461
     */
462
    public function queryDeviceTokensForUser($user)
463
    {
464
        return $this->result($this->xinge->QueryTokensOfAccount($this->accountForUser($user)), 'tokens', []);
465
    }
466
467
    /**
468
     * Delete device tokens for the given user.
469
     *
470
     * @param  mixed  $user
471
     * @param  string|string[]  $deviceTokens
472
     * @return bool
473
     */
474
    public function deleteDeviceTokensForUser($user, $deviceTokens = null)
475
    {
476
        $account = $this->accountForUser($user);
477
478
        if (is_null($deviceTokens)) {
479
            return $this->succeed($this->xinge->DeleteAllTokensOfAccount($account));
480
        }
481
482
        $deviceTokens = array_unique((array) $deviceTokens);
483
484
        $result = true;
485
486
        foreach ($deviceTokens as $token) {
487
            $result = $result && $this->succeed($this->xinge->DeleteTokenOfAccount($account, $token));
488
        }
489
490
        return $result;
491
    }
492
493
    /**
494
     * Query count of registered devices.
495
     *
496
     * @return int
497
     */
498
    public function queryCountOfDevices()
499
    {
500
        return $this->result($this->xinge->QueryDeviceCount(), 'device_num', 0);
501
    }
502
503
    /**
504
     * Query info for the given device token.
505
     *
506
     * @param  string  $deviceToken
507
     * @return array
508
     */
509
    public function queryDeviceTokenInfo($deviceToken)
510
    {
511
        return $this->xinge->QueryInfoOfToken($deviceToken);
512
    }
513
514
    /**
515
     * Query count of registered tokens for the given tag.
516
     *
517
     * @param  string  $tag
518
     * @return int
519
     */
520
    public function queryCountOfDeviceTokensForTag($tag)
521
    {
522
        return $this->result($this->xinge->QueryTagTokenNum($tag), 'device_num', 0);
523
    }
524
525
    /**
526
     * Query tags.
527
     *
528
     * @return array
529
     */
530
    public function queryTags($start = 0, $limit = 100)
531
    {
532
        return $this->xinge->QueryTags($start, $limit);
533
    }
534
535
    /**
536
     * Query all tags for the given device token.
537
     *
538
     * @param  string  $deviceToken
539
     * @return string[]
540
     */
541
    public function queryTagsForDeviceToken($deviceToken)
542
    {
543
        return $this->result($this->xinge->QueryTokenTags($deviceToken), 'tags', []);
544
    }
545
546
    /**
547
     * Query all tags for the given user.
548
     *
549
     * @param  mixed  $user
550
     * @param  array  &$deviceTokens
551
     * @return array
552
     */
553
    public function queryTagsForUser($user, &$deviceTokens = null)
554
    {
555
        $deviceTokens = $this->queryDeviceTokensForUser($user);
556
557
        $result = [];
558
        foreach ($deviceTokens as $token) {
559
            $result[$token] = $this->queryTagsForDeviceToken($token);
560
        }
561
562
        return $result;
563
    }
564
565
    /**
566
     * Add tags for device tokens.
567
     *
568
     * @warning 每次最多设置 20 对。
569
     *
570
     * @param  \ElfSundae\XgPush\TagTokenPair[]  $tagTokenPairs
571
     * @return bool
572
     */
573
    public function addTags($tagTokenPairs)
574
    {
575
        return $this->succeed($this->xinge->BatchSetTag($tagTokenPairs));
576
    }
577
578
    /**
579
     * Add tags for the given device token.
580
     *
581
     * @param  string  $deviceToken
582
     * @param  mixed  $tags
583
     * @return bool
584
     */
585
    public function addTagsForDeviceToken($deviceToken, $tags)
1 ignored issue
show
Unused Code introduced by
The parameter $tags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
586
    {
587
        return $this->addTags(
588
            $this->createTagTokenPairs($this->getParameterAsArray(func_get_args(), 1), $deviceToken)
589
        );
590
    }
591
592
    /**
593
     * Add tags for the given user.
594
     *
595
     * @param  mixed  $user
596
     * @param  mixed  $tags
597
     * @return bool
598
     */
599
    public function addTagsForUser($user, $tags)
1 ignored issue
show
Unused Code introduced by
The parameter $tags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
600
    {
601
        return $this->addTags(
602
            $this->createTagTokenPairs(
603
                $this->getParameterAsArray(func_get_args(), 1),
604
                $this->queryDeviceTokensForUser($user)
605
            )
606
        );
607
    }
608
609
    /**
610
     * Remove tags for device tokens.
611
     *
612
     * @warning 每次最多删除 20 对。
613
     *
614
     * @param  \ElfSundae\XgPush\TagTokenPair[]  $tagTokenPairs
615
     * @return bool
616
     */
617
    public function removeTags($tagTokenPairs)
618
    {
619
        return $this->succeed($this->xinge->BatchDelTag($tagTokenPairs));
620
    }
621
622
    /**
623
     * Remove tags for the given device token.
624
     *
625
     * @param  string  $deviceToken
626
     * @param  mixed  $tags
627
     * @return bool
628
     */
629
    public function removeTagsForDeviceToken($deviceToken, $tags)
1 ignored issue
show
Unused Code introduced by
The parameter $tags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
630
    {
631
        return $this->removeTags(
632
            $this->createTagTokenPairs($this->getParameterAsArray(func_get_args(), 1), $deviceToken)
633
        );
634
    }
635
636
    /**
637
     * Remove tags for the given user.
638
     *
639
     * @param  mixed  $user
640
     * @param  mixed  $tags
641
     * @return bool
642
     */
643
    public function removeTagsForUser($user, $tags)
1 ignored issue
show
Unused Code introduced by
The parameter $tags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
644
    {
645
        return $this->removeTags(
646
            $this->createTagTokenPairs(
647
                $this->getParameterAsArray(func_get_args(), 1),
648
                $this->queryDeviceTokensForUser($user)
649
            )
650
        );
651
    }
652
653
    /**
654
     * Set tags for the given device token.
655
     *
656
     * @param  string  $deviceToken
657
     * @param  mixed  $tags
658
     * @return bool
659
     */
660
    public function setTagsForDeviceToken($deviceToken, $tags)
1 ignored issue
show
Unused Code introduced by
The parameter $tags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
661
    {
662
        $tags = $this->getParameterAsArray(func_get_args(), 1);
663
        $oldTags = $this->queryTagsForDeviceToken($deviceToken);
664
665
        $result = true;
666
667
        if ($addTags = array_diff($tags, $oldTags)) {
668
            $result = $result && $this->addTagsForDeviceToken($deviceToken, $addTags);
669
        }
670
671
        if ($removeTags = array_diff($oldTags, $tags)) {
672
            $result = $result && $this->removeTagsForDeviceToken($deviceToken, $removeTags);
673
        }
674
675
        return $result;
676
    }
677
678
    /**
679
     * Set tags for the given user.
680
     *
681
     * @param  mixed  $user
682
     * @param  mixed  $tags
683
     * @return bool
684
     */
685
    public function setTagsForUser($user, $tags)
1 ignored issue
show
Unused Code introduced by
The parameter $tags is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
686
    {
687
        $tags = $this->getParameterAsArray(func_get_args(), 1);
688
        $oldTags = $this->queryTagsForUser($user, $tokens);
689
690
        $addTagTokenPairs = [];
691
        $removeTagTokenPairs = [];
692
693
        foreach ($oldTags as $token => $tokenTags) {
694
            $addTagTokenPairs = array_merge($addTagTokenPairs,
695
                $this->createTagTokenPairs(array_diff($tags, $tokenTags), $token)
696
            );
697
698
            $removeTagTokenPairs = array_merge($removeTagTokenPairs,
699
                $this->createTagTokenPairs(array_diff($tokenTags, $tags), $token)
700
            );
701
        }
702
703
        $result = true;
704
705
        if (count($addTagTokenPairs) > 0) {
706
            $result = $result && $this->addTags($addTagTokenPairs);
707
        }
708
709
        if (count($removeTagTokenPairs) > 0) {
710
            $result = $result && $this->removeTags($removeTagTokenPairs);
711
        }
712
713
        return $result;
714
    }
715
716
    /**
717
     * Get parameter as array.
718
     *
719
     * @param  array  $args
720
     * @param  int $offset
721
     * @return array
722
     */
723
    protected function getParameterAsArray(array $args, $offset = 0)
724
    {
725
        return is_array($args[$offset]) ? $args[$offset] : array_slice($args, $offset);
726
    }
727
728
    /**
729
     * Create array of TagTokenPair.
730
     *
731
     * @warning $tags 和 $tokens 一个是数组,另一个是字符串
732
     *
733
     * @param  string|string[]  $tags
734
     * @param  string|string[]  $tokens
735
     * @return \ElfSundae\XgPush\TagTokenPair[]
736
     */
737
    protected function createTagTokenPairs($tags, $tokens)
738
    {
739
        $tagTokenPairs = [];
740
741
        $tokens = (array) $tokens;
742
        foreach ((array) $tags as $tag) {
743
            foreach ($tokens as $token) {
744
                $tagTokenPairs[] = new TagTokenPair($tag, $token);
745
            }
746
        }
747
748
        return $tagTokenPairs;
749
    }
750
751
    /**
752
     * Dynamically handle calls to the XingeApp instance.
753
     *
754
     * @param  string  $method
755
     * @param  array   $parameters
756
     * @return mixed
757
     */
758
    public function __call($method, $parameters)
759
    {
760
        return call_user_func_array([$this->xinge, $method], $parameters);
761
    }
762
}
763