Fcm::__construct()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 3.7085

Importance

Changes 3
Bugs 0 Features 0
Metric Value
cc 3
eloc 7
c 3
b 0
f 0
nc 3
nop 0
dl 0
loc 13
ccs 4
cts 7
cp 0.5714
crap 3.7085
rs 10
1
<?php
2
3
namespace Kerox\Push\Adapter;
4
5
use Cake\Core\Configure;
6
use Cake\Http\Client;
7
use Cake\Http\Client\Message;
8
use Cake\Utility\Hash;
9
10
class Fcm extends AbstractAdapter
11
{
12
    const PRIORITY_NORMAL = 'normal';
13
    const PRIORITY_HIGH = 'high';
14
15
    /**
16
     * Array for devices's token
17
     *
18
     * @var array
19
     */
20
    protected $tokens = [];
21
22
    /**
23
     * Array for the notification
24
     *
25
     * @var array
26
     */
27
    protected $notification = [];
28
29
    /**
30
     * Array of datas
31
     *
32
     * @var array
33
     */
34
    protected $datas = [];
35
36
    /**
37
     * Array of request parameters
38
     *
39
     * @var array
40
     */
41
    protected $parameters = [];
42
43
    /**
44
     * Array of payload
45
     *
46
     * @var array
47
     */
48
    protected $payload = [];
49
50
    /**
51
     * Default config
52
     *
53
     * @var array
54
     */
55
    protected $_defaultConfig = [
56
        'parameters' => [
57
            'collapse_key' => null,
58
            'priority' => self::PRIORITY_NORMAL,
59
            'content_available' => false,
60
            'mutable_content' => false,
61
            'time_to_live' => 0,
62
            'restricted_package_name' => null,
63
            'dry_run' => false,
64
        ],
65
        'http' => [],
66
    ];
67
68
    /**
69
     * List of keys allowed to be used in notification array.
70
     *
71
     * @var array
72
     */
73
    protected $_allowedNotificationKeys = [
74
        'title',
75
        'body',
76
        'icon',
77
        'sound',
78
        'badge',
79
        'tag',
80
        'color',
81
        'click_action',
82
        'body_loc_key',
83
        'body_loc_args',
84
        'title_loc_key',
85
        'title_loc_args',
86
    ];
87
88
    /**
89
     * FcmAdapter constructor.
90
     *
91
     * @throws \Exception
92
     */
93 15
    public function __construct()
94
    {
95 15
        if (Configure::check('Push.adapters.Fcm') === false) {
96
            try {
97
                Configure::load('push');
98
            } catch (\Exception $e) {
99
                throw new \RuntimeException($e->getMessage());
100
            }
101
        }
102
103 15
        $config = Configure::read('Push.adapters.Fcm');
104
105 15
        parent::__construct($config);
106 15
    }
107
108
    /**
109
     * Getter for tokens
110
     *
111
     * @return array
112
     */
113 3
    public function getTokens()
114
    {
115 3
        return $this->tokens;
116
    }
117
118
    /**
119
     * Setter for tokens
120
     *
121
     * @param array $tokens Array of devices's token
122
     *
123
     * @return $this
124
     */
125 5
    public function setTokens(array $tokens)
126
    {
127 5
        $this->_checkTokens($tokens);
128 3
        $this->tokens = $tokens;
129
130 3
        return $this;
131
    }
132
133
    /**
134
     * Getter for notification
135
     *
136
     * @return array
137
     */
138 5
    public function getNotification()
139
    {
140 5
        return $this->notification;
141
    }
142
143
    /**
144
     * Setter for notification
145
     *
146
     * @param array $notification Array of keys for the notification
147
     *
148
     * @return $this
149
     */
150 6
    public function setNotification(array $notification)
151
    {
152 6
        $this->_checkNotification($notification);
153 4
        if (!isset($notification['icon'])) {
154 4
            $notification['icon'] = 'myicon';
155
        }
156 4
        $this->notification = $notification;
157
158 4
        return $this;
159
    }
160
161
    /**
162
     * Getter for datas
163
     *
164
     * @return array
165
     */
166 5
    public function getDatas()
167
    {
168 5
        return $this->datas;
169
    }
170
171
    /**
172
     * Setter for datas
173
     *
174
     * @param array $datas Array of datas for the push
175
     *
176
     * @return $this
177
     */
178 5
    public function setDatas(array $datas)
179
    {
180 5
        $this->_checkDatas($datas);
181 4
        foreach ($datas as $key => $value) {
182 4
            if (\is_bool($value)) {
183 4
                $value = $value ? 'true' : 'false';
184
            }
185 4
            $datas[$key] = (string)$value;
186
        }
187 4
        $this->datas = $datas;
188
189 4
        return $this;
190
    }
191
192
    /**
193
     * Getter for parameters
194
     *
195
     * @return array
196
     */
197 3
    public function getParameters()
198
    {
199 3
        return $this->parameters;
200
    }
201
202
    /**
203
     * Setter for parameters
204
     *
205
     * @param array $parameters Array of parameters for the push
206
     *
207
     * @return $this
208
     */
209 4
    public function setParameters(array $parameters)
210
    {
211 4
        $this->_checkParameters($parameters);
212 3
        $this->parameters = Hash::merge($this->getConfig('parameters'), $parameters);
213
214 3
        return $this;
215
    }
216
217
    /**
218
     * Getter for payload
219
     *
220
     * @return array
221
     */
222 4
    public function getPayload()
223
    {
224 4
        $notification = $this->getNotification();
225 4
        if (!empty($notification)) {
226 3
            $this->payload['notification'] = $notification;
227
        }
228
229 4
        $datas = $this->getDatas();
230 4
        if (!empty($datas)) {
231 3
            $this->payload['data'] = $datas;
232
        }
233
234 4
        return $this->payload;
235
    }
236
237
    /**
238
     * Execute the push
239
     *
240
     * @return bool
241
     */
242 2
    public function send()
243
    {
244 2
        $message = $this->_buildMessage();
245 2
        $options = $this->_getHttpOptions();
246
247 2
        $http = new Client();
248 2
        $this->response = $http->post($this->getConfig('api.url'), $message, $options);
249
250 2
        return $this->response->getStatusCode() === Message::STATUS_OK;
251
    }
252
253
    /**
254
     * Check tokens's array
255
     *
256
     * @param array $tokens Token's array
257
     *
258
     * @throws \InvalidArgumentException
259
     */
260 5
    private function _checkTokens(array $tokens)
261
    {
262 5
        if (empty($tokens) || \count($tokens) > 1000) {
263 2
            throw new \InvalidArgumentException('Array must contain at least 1 and at most 1000 tokens.');
264
        }
265 3
    }
266
267
    /**
268
     * Check notification's array
269
     *
270
     * @param array $notification Notification's array
271
     *
272
     * @throws \InvalidArgumentException
273
     */
274 6
    private function _checkNotification(array $notification)
275
    {
276 6
        if (empty($notification) || !isset($notification['title'])) {
277 1
            throw new \InvalidArgumentException('Array must contain at least a key title.');
278
        }
279
280 5
        $notAllowedKeys = [];
281 5
        foreach ($notification as $key => $value) {
282 5
            if (!\in_array($key, $this->_allowedNotificationKeys, true)) {
283 5
                $notAllowedKeys[] = $key;
284
            }
285
        }
286
287 5
        if (!empty($notAllowedKeys)) {
288 1
            $notAllowedKeys = implode(', ', $notAllowedKeys);
289 1
            throw new \InvalidArgumentException("The following keys are not allowed: {$notAllowedKeys}");
290
        }
291 4
    }
292
293
    /**
294
     * Check datas's array
295
     *
296
     * @param array $datas Datas's array
297
     *
298
     * @throws \InvalidArgumentException
299
     */
300 5
    private function _checkDatas(array $datas)
301
    {
302 5
        if (empty($datas)) {
303 1
            throw new \InvalidArgumentException('Array can not be empty.');
304
        }
305 4
    }
306
307
    /**
308
     * Check parameters's array
309
     *
310
     * @param array $parameters Parameters's array
311
     *
312
     * @throws \InvalidArgumentException
313
     */
314 4
    private function _checkParameters(array $parameters)
315
    {
316 4
        if (empty($parameters)) {
317 1
            throw new \InvalidArgumentException('Array can not be empty.');
318
        }
319 3
    }
320
321
    /**
322
     * Build the message
323
     *
324
     * @return string
325
     */
326 2
    private function _buildMessage()
327
    {
328 2
        $tokens = $this->getTokens();
329 2
        $message = (\count($tokens) > 1) ? ['registration_ids' => $tokens] : ['to' => current($tokens)];
330
331 2
        $payload = $this->getPayload();
332 2
        if (!empty($payload)) {
333 2
            $message += $payload;
334
        }
335
336 2
        $parameters = $this->getParameters();
337 2
        if (!empty($parameters)) {
338 2
            $message += $parameters;
339
        }
340
341 2
        return json_encode($message);
342
    }
343
344
    /**
345
     * Return options for the HTTP request
346
     *
347
     * @return array $options
348
     */
349 2
    private function _getHttpOptions()
350
    {
351 2
        $options = Hash::merge($this->getConfig('http'), [
352 2
            'type' => 'json',
353
            'headers' => [
354 2
                'Authorization' => 'key=' . $this->getConfig('api.key'),
355 2
                'Content-Type' => 'application/json',
356
            ],
357
        ]);
358
359 2
        return $options;
360
    }
361
}
362