PNPayload   C
last analyzed

Complexity

Total Complexity 54

Size/Duplication

Total Lines 226
Duplicated Lines 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 46
dl 0
loc 226
rs 6.4799
c 2
b 0
f 0
wmc 54

14 Methods

Rating   Name   Duplication   Size   Complexity  
A setSound() 0 4 4
A setURL() 0 7 6
A setImage() 0 4 4
A addAction() 0 7 6
A getPayload() 0 3 1
A __construct() 0 7 1
A setVibration() 0 7 5
A setTag() 0 5 4
A toJSON() 0 4 2
A setSilent() 0 7 6
A requireInteraction() 0 4 4
A setTimestamp() 0 13 6
A __toString() 0 3 1
A setBadge() 0 4 4

How to fix   Complexity   

Complex Class

Complex classes like PNPayload often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use PNPayload, and based on these observations, apply Extract Interface, too.

1
<?php
2
declare(strict_types=1);
3
4
namespace SKien\PNServer;
5
6
/**
7
 * Class representing payload for push notification.
8
 *
9
 * the class provides functions to define the properties of a push
10
 * notification. As result, a JSON string is generated to push to the client.
11
 *
12
 * Most properties directly map the showNotification() options and are
13
 * passed on directly within the service worker.
14
 *
15
 * @package PNServer
16
 * @author Stefanius <[email protected]>
17
 * @copyright MIT License - see the LICENSE file for details
18
 */
19
class PNPayload
20
{
21
    use PNServerHelper;
22
23
    /** @var array<mixed>  */
24
    protected array $aPayload;
25
26
    /**
27
     * Create instance of payload with title, text and icon to display.
28
     * - title should be short and meaningfull.
29
     * - The text should not increase 200 characters - the different browsers and
30
     *   platforms limit the display differently (partly according to the number of
31
     *   lines, others according to the number of characters)
32
     * - icon should be square (if not, some browsers/platforms cut a square). There
33
     *   is no exact specification for the 'optimal' size, 64dp (px * device pixel ratio)
34
     *   should be a good decision (... 192px for highest device pixel ratio)
35
     *
36
     * @param string $strTitle Title to display
37
     * @param string $strText A string representing an extra content to display within the notification.
38
     * @param string $strIcon containing the URL of an image to be used as an icon by the notification.
39
     */
40
    public function __construct(string $strTitle, ?string $strText = null, ?string $strIcon = null)
41
    {
42
        $this->aPayload = array(
43
                'title' => $strTitle,
44
                'opt' => array(
45
                        'body' => $strText,
46
                        'icon' => $strIcon,
47
                    ),
48
            );
49
    }
50
51
    /**
52
     * Note: the URL is no part of the JS showNotification() - Options!
53
     * @param string $strURL    URL to open when user click on the notification.
54
     */
55
    public function setURL(string $strURL) : void
56
    {
57
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
58
            if (!isset($this->aPayload['opt']['data']) || !is_array($this->aPayload['opt']['data'])) {
59
                $this->aPayload['opt']['data'] = array();
60
            }
61
            $this->aPayload['opt']['data']['url'] = $strURL;
62
        }
63
    }
64
65
    /**
66
     * An ID for a given notification that allows you to find, replace, or remove the notification using
67
     * a script if necessary.
68
     * If set, multiple notifications with the same tag will only reappear if $bReNotify is set to true.
69
     * Usualy the last notification with same tag is displayed in this case.
70
     *
71
     * @param string $strTag
72
     * @param bool $bReNotify
73
     */
74
    public function setTag(string $strTag, bool $bReNotify = false) : void
75
    {
76
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
77
            $this->aPayload['opt']['tag'] = $strTag;
78
            $this->aPayload['opt']['renotify'] = $bReNotify;
79
        }
80
    }
81
82
    /**
83
     * containing the URL of an larger image to be displayed in the notification.
84
     * Size, position and cropping vary with the different browsers and platforms
85
     * @param string $strImage
86
     */
87
    public function setImage(string $strImage) : void
88
    {
89
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
90
            $this->aPayload['opt']['image'] = $strImage;
91
        }
92
    }
93
94
    /**
95
     * containing the URL of an badge assigend to the notification.
96
     * The badge is a small monochrome icon that is used to portray a little
97
     * more information to the user about where the notification is from.
98
     * So far I have only found Chrome for Android that supports the badge...
99
     * ... in most cases the browsers icon is displayed.
100
     *
101
     * @param string $strBadge
102
     */
103
    public function setBadge(string $strBadge) : void
104
    {
105
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
106
            $this->aPayload['opt']['badge'] = $strBadge;
107
        }
108
    }
109
110
    /**
111
     * Add action to display in the notification.
112
     *
113
     * The count of action that can be displayed vary between browser/platform. On
114
     * the client it can be detected with javascript: Notification.maxActions
115
     *
116
     * Appropriate responses have to be implemented within the notificationclick event.
117
     * the event.action property contains the $strAction clicked on
118
     *
119
     * @param string $strAction     identifying a user action to be displayed on the notification.
120
     * @param string $strTitle      containing action text to be shown to the user.
121
     * @param string $strIcon       containing the URL of an icon to display with the action.
122
     * @param string $strCustom     custom info - not part of the showNotification()- Options!
123
     */
124
    public function addAction(string $strAction, string $strTitle, ?string $strIcon = null, string $strCustom = '') : void
125
    {
126
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
127
            if (!isset($this->aPayload['opt']['actions']) || !is_array($this->aPayload['opt']['actions'])) {
128
                $this->aPayload['opt']['actions'] = array();
129
            }
130
            $this->aPayload['opt']['actions'][] = array('action' => $strAction, 'title' => $strTitle, 'icon' => $strIcon, 'custom' => $strCustom);
131
        }
132
    }
133
134
    /**
135
     * Set the time when the notification was created.
136
     * It can be used to indicate the time at which a notification is actual. For example, this could
137
     * be in the past when a notification is used for a message that couldn’t immediately be delivered
138
     * because the device was offline, or in the future for a meeting that is about to start.
139
     *
140
     * @param mixed $timestamp  DateTime object, UNIX timestamp or English textual datetime description
141
     */
142
    public function setTimestamp($timestamp) : void
143
    {
144
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
145
            $iTimestamp = $timestamp;
146
            if (self::className($timestamp) == 'DateTime') {
147
                // DateTime -object
148
                $iTimestamp = $timestamp->getTimestamp();
149
            } else if (is_string($timestamp)) {
150
                // string
151
                $iTimestamp = strtotime($timestamp);
152
            }
153
            // timestamp in milliseconds!
154
            $this->aPayload['opt']['timestamp'] = bcmul((string) $iTimestamp, '1000');
155
        }
156
    }
157
158
    /**
159
     * Indicates that on devices with sufficiently large screens, a notification should remain active until
160
     * the user clicks or dismisses it. If this value is absent or false, the desktop version of Chrome
161
     * will auto-minimize notifications after approximately twenty seconds. Implementation depends on
162
     * browser and plattform.
163
     *
164
     * @param bool $bSet
165
     */
166
    public function requireInteraction(bool $bSet = true) : void
167
    {
168
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
169
            $this->aPayload['opt']['requireInteraction'] = $bSet;
170
        }
171
    }
172
173
    /**
174
     * Indicates that no sounds or vibrations should be made.
175
     * If this 'mute' function is activated, a previously set vibration is reset to prevent a TypeError exception.
176
     * @param bool $bSet
177
     */
178
    public function setSilent(bool $bSet = true) : void
179
    {
180
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
181
            $this->aPayload['opt']['silent'] = $bSet;
182
            if ($bSet && isset($this->aPayload['opt']['vibrate'])) {
183
                // silent=true and defined vibation causes TypeError
184
                unset($this->aPayload['opt']['vibrate']);
185
            }
186
        }
187
    }
188
189
    /**
190
     * A vibration pattern to run with the display of the notification.
191
     * A vibration pattern can be an array with as few as one member. The values are times in milliseconds
192
     * where the even indices (0, 2, 4, etc.) indicate how long to vibrate and the odd indices indicate
193
     * how long to pause. For example, [300, 100, 400] would vibrate 300ms, pause 100ms, then vibrate 400ms.
194
     *
195
     * @param array<int> $aPattern
196
     */
197
    public function setVibration(array $aPattern) : void
198
    {
199
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
200
            $this->aPayload['opt']['vibrate'] = $aPattern;
201
            if (isset($this->aPayload['opt']['silent'])) {
202
                // silent=true and vibation pattern causes TypeError
203
                $this->aPayload['opt']['silent'] = false;
204
            }
205
        }
206
    }
207
208
    /**
209
     * containing the URL of an sound - file (mp3 or wav).
210
     * currently not found any browser supports sounds
211
     * @param string $strSound
212
     */
213
    public function setSound(string $strSound) : void
214
    {
215
        if (is_array($this->aPayload) && isset($this->aPayload['opt']) && is_array($this->aPayload['opt'])) {
216
            $this->aPayload['opt']['sound'] = $strSound;
217
        }
218
    }
219
220
    /**
221
     * Get the Payload data as array
222
     * @return array<mixed>
223
     */
224
    public function getPayload() : array
225
    {
226
        return $this->aPayload;
227
    }
228
229
    /**
230
     * Convert payload dasta to JSON string.
231
     * @return string JSON string representing payloal
232
     */
233
    public function toJSON() : string
234
    {
235
        $strJson = json_encode($this->aPayload);
236
        return utf8_encode($strJson !== false ? $strJson : '');
237
    }
238
239
    /**
240
     * @return string JSON string representing payloal
241
     */
242
    public function __toString() : string
243
    {
244
        return $this->toJSON();
245
    }
246
247
}
248