Pusher::createTagTokenPairs()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 9
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 3
nop 2
crap 12
1
<?php
2
3
namespace ElfSundae\XgPush;
4
5
use Illuminate\Support\Arr;
6
use Illuminate\Support\Str;
7
8
class Pusher
9
{
10
    /**
11
     * The XingeApp instance.
12
     *
13
     * @var \ElfSundae\XgPush\XingeApp
14
     */
15
    protected $xinge;
16
17
    /**
18
     * The pusher environment.
19
     *
20
     * 向iOS设备推送时必填,1表示推送生产环境;2表示推送开发环境。推送Android平台不填或填0.
21
     *
22
     * @var int
23
     */
24
    protected $environment = XingeApp::IOSENV_DEV;
25
26
    /**
27
     * The key of custom payload.
28
     *
29
     * @var string
30
     */
31
    protected $customKey = 'custom';
32
33
    /**
34
     * Xinge account prefix.
35
     *
36
     * @warning 信鸽不允许使用简单的账号,例如纯数字的id。
37
     *
38
     * @var string
39
     */
40
    protected $accountPrefix;
41
42
    /**
43
     * Create a new instance.
44
     *
45
     * @param  string  $appKey
46
     * @param  string  $appSecret
47
     */
48 1
    public function __construct($appKey, $appSecret)
49
    {
50 1
        $this->xinge = new XingeApp($appKey, $appSecret);
51 1
    }
52
53
    /**
54
     * Get the XingeApp instance.
55
     *
56
     * @return \ElfSundae\XgPush\XingeApp
57
     */
58
    public function xinge()
59
    {
60
        return $this->xinge;
61
    }
62
63
    /**
64
     * Get the app key.
65
     *
66
     * @return string
67
     */
68
    public function getAppKey()
69
    {
70
        return $this->xinge->accessId;
71
    }
72
73
    /**
74
     * Get the app secret.
75
     *
76
     * @return string
77
     */
78
    public function getAppSecret()
79
    {
80
        return $this->xinge->secretKey;
81
    }
82
83
    /**
84
     * Get the pusher environment.
85
     *
86
     * @return int
87
     */
88
    public function getEnvironment()
89
    {
90
        return $this->environment;
91
    }
92
93
    /**
94
     * Set the pusher environment.
95
     *
96
     * @param  mixed  $env
97
     * @return $this
98
     */
99
    public function setEnvironment($env)
100
    {
101
        if (is_string($env)) {
102
            $env = $env == 'production' ? XingeApp::IOSENV_PROD : XingeApp::IOSENV_DEV;
103
        }
104
105
        if (is_int($env)) {
106
            $this->environment = $env;
107
        }
108
109
        return $this;
110
    }
111
112
    /**
113
     * Get the key of custom payload.
114
     *
115
     * @return string|null
116
     */
117
    public function getCustomKey()
118
    {
119
        return $this->customKey;
120
    }
121
122
    /**
123
     * Set the key of custom payload.
124
     *
125
     * @param  string|null  $key
126
     * @return $this
127
     */
128
    public function setCustomKey($key)
129
    {
130
        $this->customKey = $key;
131
132
        return $this;
133
    }
134
135
    /**
136
     * Get the account prefix.
137
     *
138
     * @return string
139
     */
140
    public function getAccountPrefix()
141
    {
142
        return $this->accountPrefix;
143
    }
144
145
    /**
146
     * Set the account prefix.
147
     *
148
     * @param  string  $prefix
149
     * @return $this
150
     */
151
    public function setAccountPrefix($prefix)
152
    {
153
        $this->accountPrefix = $prefix;
154
155
        return $this;
156
    }
157
158
    /**
159
     * Determine if the Xinge response is success.
160
     *
161
     * @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
162
     *
163
     * @param  mixed  $response
164
     * @return bool
165
     */
166
    public function succeed($response)
167
    {
168
        return $this->code($response) === 0;
169
    }
170
171
    /**
172
     * Get the code of Xinge response.
173
     *
174
     * @param  mixed  $response
175
     * @return int|null
176
     */
177
    public function code($response)
178
    {
179
        if (is_array($response)) {
180
            return Arr::get($response, 'ret_code');
181
        }
182
    }
183
184
    /**
185
     * Get the error message of Xinge response.
186
     *
187
     * @param  mixed  $response
188
     * @return string|null
189
     */
190
    public function message($response)
191
    {
192
        if (is_array($response)) {
193
            return Arr::get($response, 'err_msg');
194
        }
195
    }
196
197
    /**
198
     * Get the result data of Xinge response.
199
     *
200
     * @param  mixed  $response
201
     * @param  string  $key
202
     * @param  mixed  $default
203
     * @return mixed
204
     */
205
    public function result($response, $key = null, $default = null)
206
    {
207
        if (is_array($response)) {
208
            return Arr::get($response, $key ? "result.{$key}" : 'result', $default);
209
        }
210
    }
211
212
    /**
213
     * Encode the custom data.
214
     *
215
     * @param  mixed  $data
216
     * @return array
217
     */
218
    public function encodeCustomData($data)
219
    {
220
        if ($this->customKey && $data) {
221
            return [$this->customKey => $data];
222
        }
223
224
        return $data ?: [];
225
    }
226
227
    /**
228
     * Get Xinge account for the given user.
229
     *
230
     * @param  mixed  $user
231
     * @return string
232
     */
233
    public function accountForUser($user)
234
    {
235
        if ($this->accountPrefix && Str::startsWith($user, $this->accountPrefix)) {
236
            return $user;
237
        }
238
239
        if (method_exists($user, 'getKeyName')) {
240
            $user = $user->getKeyName();
241
        } elseif (is_array($user) && ! empty($user['id'])) {
242
            $user = $user['id'];
243
        }
244
245
        return $this->accountPrefix.$user;
246
    }
247
248
    /**
249
     * Get Xinge accounts for users.
250
     *
251
     * @param  array $users
252
     * @return array
253
     */
254
    public function accountsForUsers(array $users)
255
    {
256
        return array_map([$this, 'accountForUser'], $users);
257
    }
258
259
    /**
260
     * Creates a new MessageIOS instance.
261
     *
262
     * @param  string  $alert
263
     * @param  mixed  $custom
264
     * @param  int  $badge
265
     * @param  string  $sound
266
     * @return \ElfSundae\XgPush\MessageIOS
267
     */
268
    public function createIOSMessage($alert = '', $custom = null, $badge = 1, $sound = 'default')
269
    {
270
        $message = new MessageIOS();
271
        $message->setAlert($alert);
272
        $message->setCustom($this->encodeCustomData($custom));
273
        if (is_int($badge) && $badge >= 0) {
274
            $message->setBadge($badge);
275
        }
276
        if ($sound) {
277
            $message->setSound($sound);
278
        }
279
280
        return $message;
281
    }
282
283
    /**
284
     * Create a new Message instance.
285
     *
286
     * @param  string  $title
287
     * @param  string  $content
288
     * @param  mixed  $custom
289
     * @param  int  $type
290
     * @return \ElfSundae\XgPush\Message
291
     */
292
    public function createAndroidMessage($title = '', $content = '', $custom = null, $type = Message::TYPE_MESSAGE)
293
    {
294
        $message = new Message();
295
        $message->setTitle($title);
296
        $message->setContent($content);
297
        $message->setCustom($this->encodeCustomData($custom));
298
        $message->setType($type);
299
300
        return $message;
301
    }
302
303
    /**
304
     * Create a new Message instance for notification.
305
     * The default action is opening app.
306
     *
307
     * @param  string  $title
308
     * @param  string  $content
309
     * @param  mixed  $custom
310
     * @return \ElfSundae\XgPush\Message
311
     */
312
    public function createAndroidNotification($title = '', $content = '', $custom = null)
313
    {
314
        $message = $this->createAndroidMessage($title, $content, $custom, Message::TYPE_NOTIFICATION);
315
316
        $message->setStyle(new Style(0, 1, 1, 1, 0));
317
        $action = new ClickAction();
318
        $action->setActionType(ClickAction::TYPE_ACTIVITY);
319
        $message->setAction($action);
320
321
        return $message;
322
    }
323
324
    /**
325
     * Push message to a device.
326
     *
327
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
328
     * @param  string  $deviceToken
329
     * @return array
330
     */
331
    public function toDevice($message, $deviceToken)
332
    {
333
        return $this->xinge->PushSingleDevice($deviceToken, $message, $this->environment);
334
    }
335
336
    /**
337
     * Push message to all devices.
338
     *
339
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
340
     * @return array
341
     */
342
    public function toAllDevices($message)
343
    {
344
        return $this->xinge->PushAllDevices(0, $message, $this->environment);
345
    }
346
347
    /**
348
     * Push message to users.
349
     *
350
     * @warning 用户数限制 100 个。
351
     *
352
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
353
     * @param  mixed|array  $users
354
     * @return array
355
     */
356
    public function toUser($message, $users)
357
    {
358
        $accounts = $this->accountsForUsers((array) $users);
359
360
        if (count($accounts) == 1) {
361
            return $this->xinge->PushSingleAccount(0, $accounts[0], $message, $this->environment);
362
        }
363
364
        return $this->xinge->PushAccountList(0, $accounts, $message, $this->environment);
365
    }
366
367
    /**
368
     * Push message to tagged devices.
369
     *
370
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
371
     * @param  string|string[]  $tags
372
     * @param  string  $tagsOperation  'OR', 'AND'
373
     * @return array
374
     */
375
    public function toTags($message, $tags, $tagsOperation = 'OR')
376
    {
377
        return $this->xinge->PushTags(0, (array) $tags, strtoupper($tagsOperation), $message, $this->environment);
378
    }
379
380
    /**
381
     * Create a batch push.
382
     *
383
     * @param  \ElfSundae\XgPush\Message|\ElfSundae\XgPush\MessageIOS  $message
384
     * @return string|null
385
     */
386
    public function createBatch($message)
387
    {
388
        return $this->result($this->xinge->CreateMultipush($message, $this->environment), 'push_id');
389
    }
390
391
    /**
392
     * Batch pushing to a list of users.
393
     *
394
     * @warning 用户数限制 1000 个。
395
     *
396
     * @param  int|string  $pushId
397
     * @param  mixed|array  $users
398
     * @return array
399
     */
400
    public function batchToUsers($pushId, $users)
401
    {
402
        return $this->xinge->PushAccountListMultiple($pushId, $this->accountsForUsers((array) $users));
403
    }
404
405
    /**
406
     * Batch pushing to a list of devices.
407
     *
408
     * @warning 设备数限制 1000 个。
409
     *
410
     * @param  int|string  $pushId
411
     * @param  string|string[]  $deviceTokens
412
     * @return array
413
     */
414
    public function batchToDevices($pushId, $deviceTokens)
415
    {
416
        return $this->xinge->PushDeviceListMultiple($pushId, (array) $deviceTokens);
417
    }
418
419
    /**
420
     * Query group pushing status.
421
     *
422
     * @param  string|string[]  $pushIds
423
     * @return array
424
     */
425
    public function queryPushStatus($pushIds)
426
    {
427
        $list = $this->result($this->xinge->QueryPushStatus((array) $pushIds), 'list', []);
428
429
        return array_combine(array_pluck($list, 'push_id'), $list);
430
    }
431
432
    /**
433
     * Cancel a timed pushing task that has not been pushed.
434
     *
435
     * @param  string  $pushId
436
     * @return array
437
     */
438
    public function cancelTimedPush($pushId)
439
    {
440
        return $this->xinge->CancelTimingPush($pushId);
441
    }
442
443
    /**
444
     * Query all device tokens for the given user.
445
     *
446
     * @param  mixed  $user
447
     * @return string[]
448
     */
449
    public function queryDeviceTokensForUser($user)
450
    {
451
        return $this->result($this->xinge->QueryTokensOfAccount($this->accountForUser($user)), 'tokens', []);
452
    }
453
454
    /**
455
     * Delete device tokens for the given user.
456
     *
457
     * @param  mixed  $user
458
     * @param  string|string[]  $deviceTokens
459
     * @return bool
460
     */
461
    public function deleteDeviceTokensForUser($user, $deviceTokens = null)
462
    {
463
        $account = $this->accountForUser($user);
464
465
        if (is_null($deviceTokens)) {
466
            return $this->succeed($this->xinge->DeleteAllTokensOfAccount($account));
467
        }
468
469
        $deviceTokens = array_unique((array) $deviceTokens);
470
471
        $result = true;
472
473
        foreach ($deviceTokens as $token) {
474
            $result = $result && $this->succeed($this->xinge->DeleteTokenOfAccount($account, $token));
475
        }
476
477
        return $result;
478
    }
479
480
    /**
481
     * Query count of registered devices.
482
     *
483
     * @return int
484
     */
485
    public function queryCountOfDevices()
486
    {
487
        return $this->result($this->xinge->QueryDeviceCount(), 'device_num', 0);
488
    }
489
490
    /**
491
     * Query info for the given device token.
492
     *
493
     * @param  string  $deviceToken
494
     * @return array
495
     */
496
    public function queryDeviceTokenInfo($deviceToken)
497
    {
498
        return $this->xinge->QueryInfoOfToken($deviceToken);
499
    }
500
501
    /**
502
     * Query count of registered tokens for the given tag.
503
     *
504
     * @param  string  $tag
505
     * @return int
506
     */
507
    public function queryCountOfDeviceTokensForTag($tag)
508
    {
509
        return $this->result($this->xinge->QueryTagTokenNum($tag), 'device_num', 0);
510
    }
511
512
    /**
513
     * Query tags.
514
     *
515
     * @return array
516
     */
517
    public function queryTags($start = 0, $limit = 100)
518
    {
519
        return $this->xinge->QueryTags($start, $limit);
520
    }
521
522
    /**
523
     * Query all tags for the given device token.
524
     *
525
     * @param  string  $deviceToken
526
     * @return string[]
527
     */
528
    public function queryTagsForDeviceToken($deviceToken)
529
    {
530
        return $this->result($this->xinge->QueryTokenTags($deviceToken), 'tags', []);
531
    }
532
533
    /**
534
     * Query all tags for the given user.
535
     *
536
     * @param  mixed  $user
537
     * @param  array  &$deviceTokens
538
     * @return array
539
     */
540
    public function queryTagsForUser($user, &$deviceTokens = null)
541
    {
542
        $deviceTokens = $this->queryDeviceTokensForUser($user);
543
544
        $result = [];
545
        foreach ($deviceTokens as $token) {
546
            $result[$token] = $this->queryTagsForDeviceToken($token);
547
        }
548
549
        return $result;
550
    }
551
552
    /**
553
     * Add tags for device tokens.
554
     *
555
     * @warning 每次最多设置 20 对。
556
     *
557
     * @param  \ElfSundae\XgPush\TagTokenPair[]  $tagTokenPairs
558
     * @return bool
559
     */
560
    public function addTags($tagTokenPairs)
561
    {
562
        return $this->succeed($this->xinge->BatchSetTag($tagTokenPairs));
563
    }
564
565
    /**
566
     * Add tags for the given device token.
567
     *
568
     * @param  string  $deviceToken
569
     * @param  string|string[]  $tags
570
     * @return bool
571
     */
572
    public function addTagsForDeviceToken($deviceToken, $tags)
573
    {
574
        return $this->addTags($this->createTagTokenPairs((array) $tags, $deviceToken));
575
    }
576
577
    /**
578
     * Add tags for the given user.
579
     *
580
     * @param  mixed  $user
581
     * @param  string|array  $tags
582
     * @return bool
583
     */
584
    public function addTagsForUser($user, $tags)
585
    {
586
        return $this->addTags(
587
            $this->createTagTokenPairs((array) $tags, $this->queryDeviceTokensForUser($user))
588
        );
589
    }
590
591
    /**
592
     * Remove tags for device tokens.
593
     *
594
     * @warning 每次最多删除 20 对。
595
     *
596
     * @param  \ElfSundae\XgPush\TagTokenPair[]  $tagTokenPairs
597
     * @return bool
598
     */
599
    public function removeTags($tagTokenPairs)
600
    {
601
        return $this->succeed($this->xinge->BatchDelTag($tagTokenPairs));
602
    }
603
604
    /**
605
     * Remove tags for the given device token.
606
     *
607
     * @param  string  $deviceToken
608
     * @param  string|string[]  $tags
609
     * @return bool
610
     */
611
    public function removeTagsForDeviceToken($deviceToken, $tags)
612
    {
613
        return $this->removeTags(
614
            $this->createTagTokenPairs((array) $tags, $deviceToken)
615
        );
616
    }
617
618
    /**
619
     * Remove tags for the given user.
620
     *
621
     * @param  mixed  $user
622
     * @param  string|string[]  $tags
623
     * @return bool
624
     */
625
    public function removeTagsForUser($user, $tags)
626
    {
627
        return $this->removeTags(
628
            $this->createTagTokenPairs((array) $tags, $this->queryDeviceTokensForUser($user))
629
        );
630
    }
631
632
    /**
633
     * Set tags for the given device token.
634
     *
635
     * @param  string  $deviceToken
636
     * @param  string|string[]  $tags
637
     * @return bool
638
     */
639
    public function setTagsForDeviceToken($deviceToken, $tags)
640
    {
641
        $tags = (array) $tags;
642
        $oldTags = $this->queryTagsForDeviceToken($deviceToken);
643
644
        $result = true;
645
646
        if ($addTags = array_diff($tags, $oldTags)) {
647
            $result = $result && $this->addTagsForDeviceToken($deviceToken, $addTags);
648
        }
649
650
        if ($removeTags = array_diff($oldTags, $tags)) {
651
            $result = $result && $this->removeTagsForDeviceToken($deviceToken, $removeTags);
652
        }
653
654
        return $result;
655
    }
656
657
    /**
658
     * Set tags for the given user.
659
     *
660
     * @param  mixed  $user
661
     * @param  string|string[]  $tags
662
     * @return bool
663
     */
664
    public function setTagsForUser($user, $tags)
665
    {
666
        $tags = (array) $tags;
667
        $oldTags = $this->queryTagsForUser($user, $tokens);
668
669
        $addTagTokenPairs = [];
670
        $removeTagTokenPairs = [];
671
672
        foreach ($oldTags as $token => $tokenTags) {
673
            $addTagTokenPairs = array_merge($addTagTokenPairs,
674
                $this->createTagTokenPairs(array_diff($tags, $tokenTags), $token)
675
            );
676
677
            $removeTagTokenPairs = array_merge($removeTagTokenPairs,
678
                $this->createTagTokenPairs(array_diff($tokenTags, $tags), $token)
679
            );
680
        }
681
682
        $result = true;
683
684
        if (count($addTagTokenPairs) > 0) {
685
            $result = $result && $this->addTags($addTagTokenPairs);
686
        }
687
688
        if (count($removeTagTokenPairs) > 0) {
689
            $result = $result && $this->removeTags($removeTagTokenPairs);
690
        }
691
692
        return $result;
693
    }
694
695
    /**
696
     * Create array of TagTokenPair.
697
     *
698
     * @warning $tags 和 $tokens 一个是数组,另一个是字符串
699
     *
700
     * @param  string|string[]  $tags
701
     * @param  string|string[]  $tokens
702
     * @return \ElfSundae\XgPush\TagTokenPair[]
703
     */
704
    protected function createTagTokenPairs($tags, $tokens)
705
    {
706
        $tagTokenPairs = [];
707
708
        $tokens = (array) $tokens;
709
        foreach ((array) $tags as $tag) {
710
            foreach ($tokens as $token) {
711
                $tagTokenPairs[] = new TagTokenPair($tag, $token);
712
            }
713
        }
714
715
        return $tagTokenPairs;
716
    }
717
718
    /**
719
     * Dynamically handle calls to the XingeApp instance.
720
     *
721
     * @param  string  $method
722
     * @param  array   $parameters
723
     * @return mixed
724
     */
725
    public function __call($method, $parameters)
726
    {
727
        return call_user_func_array([$this->xinge, $method], $parameters);
728
    }
729
}
730