Completed
Branch develop (fb7bac)
by Romain
03:39
created

GcmComponent::_checkParameters()   C

Complexity

Conditions 8
Paths 9

Size

Total Lines 23
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 23
rs 6.1403
cc 8
eloc 12
nc 9
nop 1
1
<?php
2
namespace CakeGcm\Controller\Component;
3
4
use Cake\Controller\Component;
5
use Cake\Controller\ComponentRegistry;
6
use Cake\Network\Http\Client;
7
use Cake\Utility\Hash;
8
use \Exception;
9
10
/**
11
 * Gcm Component
12
 *
13
 */
14
class GcmComponent extends Component
15
{
16
17
    /**
18
     * Default config
19
     *
20
     * @var array
21
     */
22
    protected $_defaultConfig = [
23
        'api' => [
24
            'key' => null,
25
            'url' => 'https://gcm-http.googleapis.com/gcm/send'
26
        ],
27
        'parameters' => [
28
            'collapse_key' => null,
29
            'priority' => 'normal',
30
            'delay_while_idle' => false,
31
            'dry_run' => false,
32
            'time_to_live' => 0,
33
            'restricted_package_name' => null
34
        ]
35
    ];
36
37
    /**
38
     * List of parameters available to use in notification messages.
39
     *
40
     * @var array
41
     */
42
    protected $_allowedNotificationParameters = [
43
        'title',
44
        'body',
45
        'icon',
46
        'sound',
47
        'badge',
48
        'tag',
49
        'color',
50
        'click_action',
51
        'body_loc_key',
52
        'body_loc_args',
53
        'title_loc_key',
54
        'title_loc_args'
55
    ];
56
57
    /**
58
     * Error code and message.
59
     *
60
     * @var array
61
     */
62
    protected $_errorMessages = [];
63
64
    /**
65
     * Response of the request
66
     *
67
     * @var object
68
     */
69
    protected $_response = null;
70
71
    /**
72
     * Constructor
73
     *
74
     * @param ComponentRegistry $registry A ComponentRegistry
75
     * @param array $config Array of configuration settings
76
     */
77
    public function __construct(ComponentRegistry $registry, array $config = [])
78
    {
79
        parent::__construct($registry, $config);
80
        $this->_errorMessages = [
81
            '400' => __('Error 400. The request could not be parsed as JSON.'),
82
            '401' => __('Error 401. Unable to authenticating the sender account.'),
83
            '500' => __('Error 500. Internal Server Error.'),
84
            '503' => __('Error 503. Service Unavailable.')
85
        ];
86
    }
87
88
    /**
89
     * send method
90
     *
91
     * @param string|array $ids
92
     * @param array $payload
93
     * @param array $parameters
94
     * @throws Exception
95
     * @return boolean
96
     */
97
    public function send($ids = null, array $payload = [], array $parameters = [])
98
    {
99
        $ids = $this->_checkIds($ids);
0 ignored issues
show
Bug introduced by
It seems like $ids can also be of type null; however, CakeGcm\Controller\Compo...mComponent::_checkIds() does only seem to accept string|array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
100
101
        if (!is_array($payload)) {
102
            throw new Exception(__('Payload must be an array.'));
103
        }
104
105
        if (isset($payload['notification'])) {
106
            $payload['notification'] = $this->_checkNotification($payload['notification']);
107
        }
108
109
        if (isset($payload['data'])) {
110
            $payload['data'] = $this->_checkData($payload['data']);
111
        }
112
113
        $parameters = $this->_checkParameters($parameters);
114
115
        $message = $this->_buildMessage($ids, $payload, $parameters);
116
117
        return $this->_executePush($message);
118
    }
119
120
    /**
121
     * sendNotification method
122
     *
123
     * @param string|array $ids
124
     * @param array $notification
125
     * @param array $parameters
126
     * @return boolean
127
     */
128
    public function sendNotification($ids = null, array $notification = [], array $parameters = [])
129
    {
130
        return $this->send($ids, ['notification' => $notification], $parameters);
131
    }
132
133
    /**
134
     * sendData method
135
     *
136
     * @param string|array $ids
137
     * @param array $data
138
     * @param array $parameters
139
     * @return boolean
140
     */
141
    public function sendData($ids = null, array $data = [], array $parameters = [])
142
    {
143
        return $this->send($ids, ['data' => $data], $parameters);
144
    }
145
146
    /**
147
     * response method
148
     *
149
     * @return string
150
     */
151
    public function response()
152
    {
153
        if (array_key_exists($this->_response->code, $this->_errorMessages)) {
154
            return $this->_errorMessages[$this->_response->code];
155
        }
156
157
        return json_decode($this->_response->body, true);
158
    }
159
160
    /**
161
     * _executePush method
162
     *
163
     * @param string $message
164
     * @throws Exception
165
     * @return boolean
166
     */
167
    protected function _executePush($message)
168
    {
169
        if ($this->config('api.key') === null) {
170
            throw new Exception(__('No API key set. Push not triggered'));
171
        }
172
173
        $http = new Client();
174
        $this->_response = $http->post($this->config('api.url'), $message, [
175
            'type' => 'json',
176
            'headers' => [
177
                'Authorization' => 'key=' . $this->config('api.key'),
178
                'Content-Type' => 'application/json'
179
            ]
180
        ]);
181
182
        if ($this->_response->code === '200') {
183
            return true;
184
        }
185
186
        return false;
187
    }
188
189
    /**
190
     * _buildMessage method
191
     *
192
     * @param array|string $ids
193
     * @param array $payload
194
     * @param array $parameters
195
     * @return string
196
     */
197
    protected function _buildMessage($ids, $payload, $parameters)
198
    {
199
        $message = (count($ids) > 1) ? ['registration_ids' => $ids] : ['to' => current($ids)];
200
201
        if (!empty($payload)) {
202
            $message += $payload;
203
        }
204
205
        if (!empty($parameters)) {
206
            $message += $parameters;
207
        }
208
209
        return json_encode($message);
210
    }
211
212
    /**
213
     * _checkIds method
214
     *
215
     * @param string|array $ids
216
     * @throws Exception
217
     * @return array
218
     */
219
    protected function _checkIds($ids)
220
    {
221
        if (is_string($ids)) {
222
            $ids = (array)$ids;
223
        }
224
225
        if (is_null($ids) || !is_array($ids) || empty($ids)) {
226
            throw new Exception(__('Ids must be a string or an array with at least 1 token.'));
227
        }
228
229
        if (is_array($ids) && count($ids) > 1000) {
230
            throw new Exception(__('Ids must contain at least 1 and at most 1000 registration tokens.'));
231
        }
232
233
        return $ids;
234
    }
235
236
    /**
237
     * _checkNotification method
238
     *
239
     * @param array $notification
240
     * @throws Exception
241
     * @return array $notification
242
     */
243
    protected function _checkNotification(array $notification = [])
244
    {
245
        if (!is_array($notification)) {
246
            throw new Exception('Notification must be an array.');
247
        }
248
249
        if (empty($notification) || !isset($notification['title'])) {
250
            throw new Exception('Notification\'s array must contain at least a key title.');
251
        }
252
253
        if (!isset($notification['icon'])) {
254
            $notification['icon'] = 'myicon';
255
        }
256
257
        foreach ($notification as $key => $value) {
258
            if (!in_array($key, $this->_allowedNotificationParameters)) {
259
                throw new Exception("The key {$key} is not allowed in notifications.");
260
            }
261
        }
262
263
        return $notification;
264
    }
265
266
    /**
267
     * _checkData method
268
     *
269
     * @param array $data
270
     * @throws Exception
271
     * @return array $data
272
     */
273
    protected function _checkData(array $data = [])
274
    {
275
        if (!is_array($data)) {
276
            throw new Exception('Data must ba an array.');
277
        }
278
279
        if (empty($data)) {
280
            throw new Exception('Data\'s array can\'t be empty.');
281
        }
282
283
        // Convert all data into string
284
        foreach ($data as $key => $value) {
285
            $data[$key] = (string)$value;
286
        }
287
288
        return $data;
289
    }
290
291
    /**
292
     * _checkParameters method
293
     *
294
     * @param array $parameters
295
     * @return array $parameters
296
     */
297
    protected function _checkParameters(array $parameters = [])
298
    {
299
        if (!is_array($parameters)) {
300
            throw new Exception(__('Parameters must be an array.'));
301
        }
302
303
        $parameters = Hash::merge($this->config('parameters'), $parameters);
304
        $parameters = array_filter($parameters);
305
306
        if (isset($parameters['time_to_live']) && !is_int($parameters['time_to_live'])) {
307
            $parameters['time_to_live'] = (int)$parameters['time_to_live'];
308
        }
309
310
        if (isset($parameters['delay_while_idle']) && !is_bool($parameters['delay_while_idle'])) {
311
            $parameters['delay_while_idle'] = (bool)$parameters['delay_while_idle'];
312
        }
313
314
        if (isset($parameters['dry_run']) && !is_bool($parameters['dry_run'])) {
315
            $parameters['dry_run'] = (bool)$parameters['dry_run'];
316
        }
317
318
        return $parameters;
319
    }
320
}
321