Completed
Branch master (ecc79d)
by Arthur
01:43 queued 29s
created

Payload::checkPayloadSize()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 1
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
1
<?php
2
3
/*
4
 * This file is part of the Pushok package.
5
 *
6
 * (c) Arthur Edamov <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Pushok;
13
14
use Countable;
15
use Pushok\Payload\Alert;
16
use Pushok\Payload\Sound;
17
18
// Polyfill for PHP 7.2
19
if (!function_exists('is_countable')) {
20
    function is_countable($var)
21
    {
22
        return (is_array($var) || $var instanceof Countable);
23
    }
24
}
25
26
/**
27
 * Class Payload
28
 *
29
 * @package Pushok
30
 *
31
 * @see     http://bit.ly/payload-key-reference
32
 */
33
class Payload implements \JsonSerializable
34
{
35
    const PAYLOAD_ROOT_KEY = 'aps';
36
    const PAYLOAD_ALERT_KEY = 'alert';
37
    const PAYLOAD_BADGE_KEY = 'badge';
38
    const PAYLOAD_SOUND_KEY = 'sound';
39
    const PAYLOAD_CONTENT_AVAILABLE_KEY = 'content-available';
40
    const PAYLOAD_MUTABLE_CONTENT_KEY = 'mutable-content';
41
    const PAYLOAD_CATEGORY_KEY = 'category';
42
    const PAYLOAD_THREAD_ID_KEY = 'thread-id';
43
    const PAYLOAD_URL_ARGS_KEY = 'url-args';
44
45
    const PAYLOAD_HTTP2_REGULAR_NOTIFICATION_MAXIMUM_SIZE = 4096;
46
    const PAYLOAD_HTTP2_VOIP_NOTIFICATION_MAXIMUM_SIZE = 5120;
47
    const PAYLOAD_BINARY_REGULAR_NOTIFICATION_MAXIMUM_SIZE = 2048;
48
49
50
    /**
51
     * The notification settings for your app on the user’s device determine whether an alert or banner is displayed.
52
     *
53
     * @var Alert|string
54
     */
55
    private $alert;
56
57
    /**
58
     * The number to display as the badge of the app icon.
59
     * If this property is absent, the badge is not changed.
60
     *
61
     * @var int
62
     */
63
    private $badge;
64
65
    /**
66
     * The name of a sound file in the app bundle or in the Library/Sounds folder of the app’s data container.
67
     *
68
     * @var Sound|string
69
     */
70
    private $sound;
71
72
    /**
73
     * Include this key with a value of true to configure a silent notification.
74
     *
75
     * @var bool
76
     */
77
    private $contentAvailable;
78
79
    /**
80
     * Include this key with a value of true to configure a mutable content notification.
81
     *
82
     * @var bool
83
     */
84
    private $mutableContent;
85
86
    /**
87
     * Provide this key with a string value that represents the notification’s type.
88
     *
89
     * @var string
90
     */
91
    private $category;
92
93
    /**
94
     * Provide this key with a string value that represents the app-specific identifier for grouping notifications.
95
     *
96
     * @var string
97
     */
98
    private $threadId;
99
100
    /**
101
     * Provide this key with an array value that represents the url-args for Safari notifications.
102
     *
103
     * @var string
104
     */
105
    private $urlArgs;
106
107
    /**
108
     * Payload custom values.
109
     *
110
     * @var array
111
     */
112
    private $customValues;
113
114
    /**
115
     * Push notification type
116
     *
117
     * https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607
118
     *
119
     * @var string
120
     */
121
    private $pushType;
122
123
    protected function __construct()
124
    {
125
    }
126
127
    /**
128
     * @return Payload
129
     */
130
    public static function create(): Payload
131
    {
132
        return new self();
133
    }
134
135
    /**
136
     * Get Alert.
137
     *
138
     * @return Alert|null
139
     */
140
    public function getAlert()
141
    {
142
        return $this->alert;
143
    }
144
145
    /**
146
     * Set Alert.
147
     *
148
     * @param Alert|string $alert
149
     *
150
     * @return Payload
151
     */
152
    public function setAlert($alert): Payload
153
    {
154
        if ($alert instanceof Alert || is_string($alert)) {
155
            $this->alert = $alert;
156
        }
157
158
        return $this;
159
    }
160
161
    /**
162
     * Get badge.
163
     *
164
     * @return int|null
165
     */
166
    public function getBadge()
167
    {
168
        return $this->badge;
169
    }
170
171
    /**
172
     * Set badge.
173
     *
174
     * @param int $value
175
     *
176
     * @return Payload
177
     */
178
    public function setBadge(int $value): Payload
179
    {
180
        $this->badge = $value;
181
182
        return $this;
183
    }
184
185
    /**
186
     * Get sound.
187
     *
188
     * @return string|null
189
     */
190
    public function getSound()
191
    {
192
        return $this->sound;
193
    }
194
195
    /**
196
     * Set sound.
197
     *
198
     * @param Sound|string $sound
199
     *
200
     * @return Payload
201
     */
202
    public function setSound($sound): Payload
203
    {
204
        if ($sound instanceof Sound || is_string($sound)) {
205
            $this->sound = $sound;
206
        }
207
208
        return $this;
209
    }
210
211
    /**
212
     * Set content availability.
213
     *
214
     * @param bool $value
215
     *
216
     * @return Payload
217
     */
218
    public function setContentAvailability(bool $value): Payload
219
    {
220
        $this->contentAvailable = $value;
221
222
        return $this;
223
    }
224
225
    /**
226
     * Get content availability.
227
     *
228
     * @return bool|null
229
     */
230
    public function isContentAvailable()
231
    {
232
        return $this->contentAvailable;
233
    }
234
235
    /**
236
     * Set the mutable-content key for Notification Service Extensions on iOS10.
237
     *
238
     * @see http://bit.ly/mutable-content
239
     *
240
     * @param bool $value
241
     *
242
     * @return Payload
243
     */
244
    public function setMutableContent(bool $value): Payload
245
    {
246
        $this->mutableContent = $value;
247
248
        return $this;
249
    }
250
251
    /**
252
     * Is content mutable.
253
     *
254
     * @return bool|null
255
     */
256
    public function hasMutableContent()
257
    {
258
        return $this->mutableContent;
259
    }
260
261
    /**
262
     * Get category.
263
     *
264
     * @return string|null
265
     */
266
    public function getCategory()
267
    {
268
        return $this->category;
269
    }
270
271
    /**
272
     * Set category.
273
     *
274
     * @param string $value
275
     *
276
     * @return Payload
277
     */
278
    public function setCategory(string $value): Payload
279
    {
280
        $this->category = $value;
281
282
        return $this;
283
    }
284
285
    /**
286
     * Get thread-id.
287
     *
288
     * @return string|null
289
     */
290
    public function getThreadId()
291
    {
292
        return $this->threadId;
293
    }
294
295
    /**
296
     * Set thread-id.
297
     *
298
     * @param string $value
299
     *
300
     * @return Payload
301
     */
302
    public function setThreadId(string $value): Payload
303
    {
304
        $this->threadId = $value;
305
306
        return $this;
307
    }
308
309
    /**
310
     * Get url-args.
311
     *
312
     * @return array|null
313
     */
314
    public function getUrlArgs()
315
    {
316
        return $this->urlArgs;
317
    }
318
319
    /**
320
     * Set url-args.
321
     *
322
     * @param array $value
323
     *
324
     * @return Payload
325
     */
326
    public function setUrlArgs(array $value): Payload
327
    {
328
        $this->urlArgs = $value;
0 ignored issues
show
Documentation Bug introduced by
It seems like $value of type array is incompatible with the declared type string of property $urlArgs.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
329
330
        return $this;
331
    }
332
333
    /**
334
     * Set custom value for Payload.
335
     *
336
     * @param string $key
337
     * @param mixed $value
338
     *
339
     * @return Payload
340
     * @throws InvalidPayloadException
341
     */
342
    public function setCustomValue(string $key, $value): Payload
343
    {
344
        if ($key === self::PAYLOAD_ROOT_KEY) {
345
            throw InvalidPayloadException::reservedKey();
346
        }
347
348
        $this->customValues[$key] = $value;
349
350
        return $this;
351
    }
352
353
    /**
354
     * Get custom value.
355
     *
356
     * @param $key
357
     *
358
     * @return mixed
359
     * @throws InvalidPayloadException
360
     */
361
    public function getCustomValue($key)
362
    {
363
        if (!array_key_exists($key, $this->customValues)) {
364
            throw InvalidPayloadException::notExistingCustomValue($key);
365
        }
366
367
        return $this->customValues[$key];
368
    }
369
370
    /**
371
     * Set push type for Payload.
372
     *
373
     * @param string $pushType
374
     * @return Payload
375
     */
376
    public function setPushType($pushType) {
377
        $this->pushType = $pushType;
378
379
        return $this;
380
    }
381
382
    /**
383
     * Get push type for Payload.
384
     *
385
     * @return string
386
     */
387
    public function getPushType() {
388
        return $this->pushType;
389
    }
390
391
    /**
392
     * Convert Payload to JSON.
393
     *
394
     * @return string
395
     */
396
    public function toJson(): string
397
    {
398
        $str = json_encode($this, JSON_UNESCAPED_UNICODE);
399
400
        $this->checkPayloadSize($str);
401
402
        return $str;
403
    }
404
405
    /**
406
     * Specify data which should be serialized to JSON.
407
     *
408
     * @return array
409
     * @link   http://php.net/manual/en/jsonserializable.jsonserialize.php
410
     */
411
    public function jsonSerialize()
412
    {
413
        $payload = self::getDefaultPayloadStructure();
414
415
        if ($this->alert instanceof Alert || is_string($this->alert)) {
416
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_ALERT_KEY} = $this->alert;
417
        }
418
419
        if (is_int($this->badge)) {
420
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_BADGE_KEY} = $this->badge;
421
        }
422
423
        if ($this->sound instanceof Sound || is_string($this->sound)) {
424
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_SOUND_KEY} = $this->sound;
425
        }
426
427
        if (is_bool($this->contentAvailable)) {
428
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_CONTENT_AVAILABLE_KEY} = (int)$this->contentAvailable;
429
        }
430
431
        if (is_bool($this->mutableContent)) {
432
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_MUTABLE_CONTENT_KEY} = (int)$this->mutableContent;
433
        }
434
435
        if (is_string($this->category)) {
436
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_CATEGORY_KEY} = $this->category;
437
        }
438
439
        if (is_string($this->threadId)) {
440
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_THREAD_ID_KEY} = $this->threadId;
441
        }
442
443
        if (is_array($this->urlArgs)) {
444
            $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_URL_ARGS_KEY} = $this->urlArgs;
445
        }
446
447
        if (is_countable($this->customValues) && count($this->customValues)) {
448
            $payload = array_merge($payload, $this->customValues);
449
        }
450
451
        return $payload;
452
    }
453
454
    /**
455
     * Get default payload structure.
456
     *
457
     * @return array
458
     */
459
    private static function getDefaultPayloadStructure()
460
    {
461
        return [self::PAYLOAD_ROOT_KEY => new \stdClass];
462
    }
463
464
    /**
465
     * @param $jsonPayload
466
     * @return void
467
     * @throws InvalidPayloadException
468
     */
469
    private function checkPayloadSize($jsonPayload)
470
    {
471
        $strLength = strlen($jsonPayload);
472
        if ('voip' === $this->getPushType()) {
473
            if ($strLength > self::PAYLOAD_HTTP2_VOIP_NOTIFICATION_MAXIMUM_SIZE) {
474
                throw new InvalidPayloadException('Voip Payload size limit exceeded');
475
            }
476
        } elseif ($strLength > self::PAYLOAD_HTTP2_REGULAR_NOTIFICATION_MAXIMUM_SIZE) {
477
            throw new InvalidPayloadException('Payload size limit exceeded');
478
        }
479
    }
480
}
481