Completed
Push — master ( cec9d1...f544c6 )
by Romain
11s
created

Fcm::_checkTokens()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

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