Completed
Branch feature/fcm-adapter (e7bf97)
by Romain
02:12
created

FcmAdapter   B

Complexity

Total Complexity 39

Size/Duplication

Total Lines 310
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 0
Metric Value
wmc 39
lcom 1
cbo 9
dl 0
loc 310
rs 8.2857
c 0
b 0
f 0

19 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 9 2
A send() 0 4 1
A response() 0 4 1
A getTokens() 0 4 1
A setTokens() 0 7 1
A getNotification() 0 4 1
A setNotification() 0 10 2
A getDatas() 0 4 1
A setDatas() 0 13 4
A getParameters() 0 4 1
A setParameters() 0 7 1
A _checkTokens() 0 6 3
B _checkNotification() 0 18 6
A _checkDatas() 0 6 2
A _checkParameters() 0 6 2
A _executePush() 0 10 2
A _buildPayload() 0 12 3
A _buildMessage() 0 16 4
A _getHttpOptions() 0 12 1
1
<?php
2
namespace ker0x\Push\Adapter;
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\AdapterInterface;
9
use kerox\Push\Exception\InvalidAdapterException;
10
use ker0x\Push\Exception\InvalidDataException;
11
use ker0x\Push\Exception\InvalidNotificationException;
12
use ker0x\Push\Exception\InvalidParametersException;
13
use ker0x\Push\Exception\InvalidTokenException;
14
15
class FcmAdapter implements AdapterInterface
16
{
17
18
    use InstanceConfigTrait;
19
20
    /**
21
     * @var array
22
     */
23
    protected $tokens = [];
24
25
    /**
26
     * @var array
27
     */
28
    protected $notification = [];
29
30
    /**
31
     * @var array
32
     */
33
    protected $datas = [];
34
35
    /**
36
     * @var array
37
     */
38
    protected $parameters = [];
39
40
    /**
41
     * Default config
42
     *
43
     * @var array
44
     */
45
    protected $_defaultConfig = [
46
        'parameters' => [
47
            'collapse_key' => null,
48
            'priority' => 'normal',
49
            'dry_run' => false,
50
            'time_to_live' => 0,
51
            'restricted_package_name' => null
52
        ],
53
        'http' => []
54
    ];
55
56
    /**
57
     * List of keys allowed to be used in notification array.
58
     *
59
     * @var array
60
     */
61
    protected $_allowedNotificationParameters = [
62
        'title',
63
        'body',
64
        'icon',
65
        'sound',
66
        'badge',
67
        'tag',
68
        'color',
69
        'click_action',
70
        'body_loc_key',
71
        'body_loc_args',
72
        'title_loc_key',
73
        'title_loc_args',
74
    ];
75
76
    /**
77
     * FcmAdapter constructor.
78
     * @param array $config
79
     * @throws \kerox\Push\Exception\InvalidAdapterException
80
     */
81
    public function __construct(array $config = [])
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
82
    {
83
        $config = Configure::read('Push.adapters.Fcm');
84
        $this->config($config);
85
86
        if ($this->config('api.key') === null) {
87
            throw new InvalidAdapterException("No API key set. Push not triggered");
88
        }
89
    }
90
91
    /**
92
     * @return bool
93
     */
94
    public function send()
95
    {
96
        return $this->_executePush();
97
    }
98
99
    /**
100
     *
101
     */
102
    public function response()
103
    {
104
        // TODO: Implement response() method.
105
    }
106
107
    /**
108
     * @return array
109
     */
110
    public function getTokens(): array
111
    {
112
        return $this->tokens;
113
    }
114
115
    /**
116
     * @param array $tokens
117
     * @return $this
118
     */
119
    public function setTokens(array $tokens)
120
    {
121
        $this->_checkTokens($tokens);
122
        $this->tokens = $tokens;
123
124
        return $this;
125
    }
126
127
    /**
128
     * @return array
129
     */
130
    public function getNotification(): array
131
    {
132
        return $this->notification;
133
    }
134
135
    /**
136
     * @param array $notification
137
     * @return $this
138
     */
139
    public function setNotification(array $notification)
140
    {
141
        $this->_checkNotification($notification);
142
        if (!isset($notification['icon'])) {
143
            $notification['icon'] = 'myicon';
144
        }
145
        $this->notification = $notification;
146
147
        return $this;
148
    }
149
150
    /**
151
     * @return array
152
     */
153
    public function getDatas(): array
154
    {
155
        return $this->datas;
156
    }
157
158
    /**
159
     * @param array $datas
160
     * @return $this
161
     */
162
    public function setDatas(array $datas)
163
    {
164
        $this->_checkDatas($datas);
165
        foreach ($datas as $key => $value) {
166
            if (is_bool($value)) {
167
                $value = ($value) ? 'true' : 'false';
168
            }
169
            $datas[$key] = (string)$value;
170
        }
171
        $this->datas = $datas;
172
173
        return $this;
174
    }
175
176
    /**
177
     * @return array
178
     */
179
    public function getParameters(): array
180
    {
181
        return $this->parameters;
182
    }
183
184
    /**
185
     * @param array $parameters
186
     * @return $this
187
     */
188
    public function setParameters(array $parameters)
189
    {
190
        $this->_checkParameters($parameters);
191
        $this->parameters = Hash::merge($this->config('parameters'), $parameters);
192
193
        return $this;
194
    }
195
196
    /**
197
     * @param $tokens
198
     * @return void
199
     * @throws \ker0x\Push\Exception\InvalidTokenException
200
     */
201
    private function _checkTokens($tokens)
202
    {
203
        if (empty($tokens) || count($tokens) > 1000) {
204
            throw new InvalidTokenException("Array must contain at least 1 and at most 1000 tokens.");
205
        }
206
    }
207
208
    /**
209
     * @param $notification
210
     * @return void
211
     * @throws \ker0x\Push\Exception\InvalidNotificationException
212
     */
213
    private function _checkNotification($notification)
214
    {
215
        if (empty($notification) || !isset($notification['title'])) {
216
            throw new InvalidNotificationException("Array must contain at least a key title.");
217
        }
218
219
        $notAllowedKeys = [];
220
        foreach ($notification as $key => $value) {
221
            if (!in_array($key, $this->_allowedNotificationParameters)) {
222
                $notAllowedKeys[] = $key;
223
            }
224
        }
225
226
        if (!empty($notAllowedKeys)) {
227
            $notAllowedKeys = implode(', ', $notAllowedKeys);
228
            throw new InvalidNotificationException("The following keys are not allowed: {$notAllowedKeys}");
229
        }
230
    }
231
232
    /**
233
     * @param $datas
234
     * @return void
235
     * @throws \ker0x\Push\Exception\InvalidDataException
236
     */
237
    private function _checkDatas($datas)
238
    {
239
        if (empty($datas)) {
240
            throw new InvalidDataException("Array can not be empty.");
241
        }
242
    }
243
244
    /**
245
     * @param $parameters
246
     * @return void
247
     * @throws \ker0x\Push\Exception\InvalidParametersException
248
     */
249
    private function _checkParameters($parameters)
250
    {
251
        if (empty($parameters)) {
252
            throw new InvalidParametersException("Array can not be empty.");
253
        }
254
    }
255
256
    /**
257
     * @return bool
258
     */
259
    private function _executePush()
260
    {
261
        $message = $this->_buildMessage();
262
        $options = $this->_getHttpOptions();
263
264
        $http = new Client();
265
        $this->_response = $http->post($this->config('api.url'), $message, $options);
0 ignored issues
show
Bug introduced by
The property _response does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
266
267
        return ($this->_response->code === '200') ? true : false;
268
    }
269
270
    /**
271
     *
272
     */
273
    private function _buildPayload()
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
274
    {
275
        $notification = $this->getNotification();
276
        if (!empty($notification)) {
277
            $this->payload['notification'] = $notification;
0 ignored issues
show
Bug introduced by
The property payload does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
278
        }
279
280
        $datas = $this->getDatas();
281
        if (!empty($datas)) {
282
            $this->payload['datas'] = $datas;
283
        }
284
    }
285
286
    /**
287
     *
288
     */
289
    private function _buildMessage()
290
    {
291
        $tokens = $this->getTokens();
292
        $message = (count($tokens) > 1) ? ['registration_ids' => $tokens] : ['to' => current($tokens)];
293
294
        if (!empty($this->payload)) {
295
            $message += $this->payload;
296
        }
297
298
        $parameters = $this->getParameters();
299
        if (!empty($parameters)) {
300
            $message += $parameters;
301
        }
302
303
        return json_encode($message);
304
    }
305
306
    /**
307
     * Return options for the HTTP request
308
     *
309
     * @throws \Exception
310
     * @return array $options
311
     */
312
    private function _getHttpOptions()
313
    {
314
        $options = Hash::merge($this->config('http'), [
315
            'type' => 'json',
316
            'headers' => [
317
                'Authorization' => 'key=' . $this->config('api.key'),
318
                'Content-Type' => 'application/json'
319
            ]
320
        ]);
321
322
        return $options;
323
    }
324
}
325