Completed
Push — master ( 279d4e...5d09e0 )
by Elf
02:49
created

XgPusher::accountForUser()   B

Complexity

Conditions 6
Paths 4

Size

Total Lines 14
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
cc 6
eloc 8
nc 4
nop 1
dl 0
loc 14
ccs 0
cts 12
cp 0
crap 42
rs 8.8571
c 0
b 0
f 0
1
<?php
2
3
namespace ElfSundae\Laravel\Support\Tencent;
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
        if (is_object($user)) {
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