Completed
Pull Request — master (#118)
by yann
01:15
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($payloadJson);
0 ignored issues
show
Bug introduced by
The variable $payloadJson does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
472
        if ('voip' === $this->getPushType()) {
473
            if ($strLength > 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