1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org) |
4
|
|
|
* Copyright (c) Romain Monteil |
5
|
|
|
* |
6
|
|
|
* Licensed under The MIT License |
7
|
|
|
* For full copyright and license information, please see the LICENSE.txt |
8
|
|
|
* Redistributions of files must retain the above copyright notice. |
9
|
|
|
* |
10
|
|
|
* @copyright Copyright (c) Romain Monteil |
11
|
|
|
* @link http://cakephp.org CakePHP(tm) Project |
12
|
|
|
* @license http://www.opensource.org/licenses/mit-license.php MIT License |
13
|
|
|
*/ |
14
|
|
|
namespace CakeGcm\Controller\Component; |
15
|
|
|
|
16
|
|
|
use Cake\Controller\Component; |
17
|
|
|
use Cake\Controller\ComponentRegistry; |
18
|
|
|
use Cake\Network\Http\Client; |
19
|
|
|
use Cake\Utility\Hash; |
20
|
|
|
use \Exception; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Gcm Component |
24
|
|
|
* |
25
|
|
|
*/ |
26
|
|
|
class GcmComponent extends Component |
27
|
|
|
{ |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* Default config |
31
|
|
|
* |
32
|
|
|
* @var array |
33
|
|
|
*/ |
34
|
|
|
protected $_defaultConfig = [ |
35
|
|
|
'api' => [ |
36
|
|
|
'key' => null, |
37
|
|
|
'url' => 'https://gcm-http.googleapis.com/gcm/send' |
38
|
|
|
], |
39
|
|
|
'parameters' => [ |
40
|
|
|
'collapse_key' => null, |
41
|
|
|
'priority' => 'normal', |
42
|
|
|
'delay_while_idle' => false, |
43
|
|
|
'dry_run' => false, |
44
|
|
|
'time_to_live' => 0, |
45
|
|
|
'restricted_package_name' => null |
46
|
|
|
] |
47
|
|
|
]; |
48
|
|
|
|
49
|
|
|
/** |
50
|
|
|
* List of parameters available to use in notification messages. |
51
|
|
|
* |
52
|
|
|
* @var array |
53
|
|
|
*/ |
54
|
|
|
protected $_allowedNotificationParameters = [ |
55
|
|
|
'title', |
56
|
|
|
'body', |
57
|
|
|
'icon', |
58
|
|
|
'sound', |
59
|
|
|
'badge', |
60
|
|
|
'tag', |
61
|
|
|
'color', |
62
|
|
|
'click_action', |
63
|
|
|
'body_loc_key', |
64
|
|
|
'body_loc_args', |
65
|
|
|
'title_loc_key', |
66
|
|
|
'title_loc_args' |
67
|
|
|
]; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* Error code and message. |
71
|
|
|
* |
72
|
|
|
* @var array |
73
|
|
|
*/ |
74
|
|
|
protected $_errorMessages = []; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Response of the request |
78
|
|
|
* |
79
|
|
|
* @var object |
80
|
|
|
*/ |
81
|
|
|
protected $_response = null; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* Constructor |
85
|
|
|
* |
86
|
|
|
* @param ComponentRegistry $registry A ComponentRegistry |
87
|
|
|
* @param array $config Array of configuration settings |
88
|
|
|
*/ |
89
|
|
|
public function __construct(ComponentRegistry $registry, array $config = []) |
90
|
|
|
{ |
91
|
|
|
parent::__construct($registry, $config); |
92
|
|
|
$this->_errorMessages = [ |
93
|
|
|
'400' => __('Error 400. The request could not be parsed as JSON.'), |
94
|
|
|
'401' => __('Error 401. Unable to authenticating the sender account.'), |
95
|
|
|
'500' => __('Error 500. Internal Server Error.'), |
96
|
|
|
'503' => __('Error 503. Service Unavailable.') |
97
|
|
|
]; |
98
|
|
|
} |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* send method |
102
|
|
|
* |
103
|
|
|
* @param string|array $ids |
104
|
|
|
* @param array $payload |
105
|
|
|
* @param array $parameters |
106
|
|
|
* @throws Exception |
107
|
|
|
* @return boolean |
108
|
|
|
*/ |
109
|
|
|
public function send($ids = null, array $payload = [], array $parameters = []) |
110
|
|
|
{ |
111
|
|
|
if (is_string($ids)) { |
112
|
|
|
$ids = (array)$ids; |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
if (is_null($ids) || !is_array($ids) || empty($ids)) { |
116
|
|
|
throw new Exception(__('Ids must be a string or an array with at least 1 token.')); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
if (is_array($ids) && count($ids) > 1000) { |
120
|
|
|
throw new Exception(__('Ids must contain at least 1 and at most 1000 registration tokens.')); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
if (!is_array($payload)) { |
124
|
|
|
throw new Exception(__('Payload must be an array.')); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
if (!is_array($parameters)) { |
128
|
|
|
throw new Exception(__('Parameters must be an array.')); |
129
|
|
|
} |
130
|
|
|
|
131
|
|
View Code Duplication |
if (isset($payload['notification'])) { |
|
|
|
|
132
|
|
|
$payload['notification'] = $this->_checkNotification($payload['notification']); |
133
|
|
|
if (!$payload['notification']) { |
134
|
|
|
throw new Exception(__("Unable to check notification.")); |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
View Code Duplication |
if (isset($payload['data'])) { |
|
|
|
|
139
|
|
|
$payload['data'] = $this->_checkData($payload['data']); |
140
|
|
|
if (!$payload['data']) { |
141
|
|
|
throw new Exception(__("Unable to check data.")); |
142
|
|
|
} |
143
|
|
|
} |
144
|
|
|
|
145
|
|
|
$parameters = $this->_checkParameters($parameters); |
146
|
|
|
$message = $this->_buildMessage($ids, $payload, $parameters); |
147
|
|
|
|
148
|
|
|
return $this->_executePush($message); |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* sendNotification method |
153
|
|
|
* |
154
|
|
|
* @param string|array $ids |
155
|
|
|
* @param array $notification |
156
|
|
|
* @param array $parameters |
157
|
|
|
* @return boolean |
158
|
|
|
*/ |
159
|
|
|
public function sendNotification($ids = null, array $notification = [], array $parameters = []) |
160
|
|
|
{ |
161
|
|
|
return $this->send($ids, ['notification' => $notification], $parameters); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* sendData method |
166
|
|
|
* |
167
|
|
|
* @param string|array $ids |
168
|
|
|
* @param array $data |
169
|
|
|
* @param array $parameters |
170
|
|
|
* @return boolean |
171
|
|
|
*/ |
172
|
|
|
public function sendData($ids = null, array $data = [], array $parameters = []) |
173
|
|
|
{ |
174
|
|
|
return $this->send($ids, ['data' => $data], $parameters); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
/** |
178
|
|
|
* response method |
179
|
|
|
* |
180
|
|
|
* @return string |
181
|
|
|
*/ |
182
|
|
|
public function response() |
183
|
|
|
{ |
184
|
|
|
if (array_key_exists($this->_response->code, $this->_errorMessages)) { |
185
|
|
|
return $this->_errorMessages[$this->_response->code]; |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
return json_decode($this->_response->body, true); |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
/** |
192
|
|
|
* _executePush method |
193
|
|
|
* |
194
|
|
|
* @param string $message |
195
|
|
|
* @throws Exception |
196
|
|
|
* @return boolean |
197
|
|
|
*/ |
198
|
|
|
protected function _executePush($message) |
199
|
|
|
{ |
200
|
|
|
if ($this->config('api.key') === null) { |
201
|
|
|
throw new Exception(__('No API key set. Push not triggered')); |
202
|
|
|
} |
203
|
|
|
|
204
|
|
|
$http = new Client(); |
205
|
|
|
$this->_response = $http->post($this->config('api.url'), $message, [ |
206
|
|
|
'type' => 'json', |
207
|
|
|
'headers' => [ |
208
|
|
|
'Authorization' => 'key=' . $this->config('api.key'), |
209
|
|
|
'Content-Type' => 'application/json' |
210
|
|
|
] |
211
|
|
|
]); |
212
|
|
|
|
213
|
|
|
if ($this->_response->code === '200') { |
214
|
|
|
return true; |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
return false; |
218
|
|
|
} |
219
|
|
|
|
220
|
|
|
/** |
221
|
|
|
* _buildMessage method |
222
|
|
|
* |
223
|
|
|
* @param array|string $ids |
224
|
|
|
* @param array $payload |
225
|
|
|
* @param array $parameters |
226
|
|
|
* @return string |
227
|
|
|
*/ |
228
|
|
|
protected function _buildMessage($ids, $payload, $parameters) |
229
|
|
|
{ |
230
|
|
|
$message = (count($ids) > 1) ? ['registration_ids' => $ids] : ['to' => current($ids)]; |
231
|
|
|
|
232
|
|
|
if (!empty($payload)) { |
233
|
|
|
$message += $payload; |
234
|
|
|
} |
235
|
|
|
|
236
|
|
|
if (!empty($parameters)) { |
237
|
|
|
$message += $parameters; |
238
|
|
|
} |
239
|
|
|
|
240
|
|
|
return json_encode($message); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* _checkNotification method |
245
|
|
|
* |
246
|
|
|
* @param array $notification |
247
|
|
|
* @throws Exception |
248
|
|
|
* @return array $notification |
249
|
|
|
*/ |
250
|
|
|
protected function _checkNotification(array $notification = []) |
251
|
|
|
{ |
252
|
|
|
if (!is_array($notification)) { |
253
|
|
|
throw new Exception('Notification must be an array.'); |
254
|
|
|
} |
255
|
|
|
|
256
|
|
|
if (empty($notification) || !isset($notification['title'])) { |
257
|
|
|
throw new Exception('Notification\'s array must contain at least a key title.'); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
if (!isset($notification['icon'])) { |
261
|
|
|
$notification['icon'] = 'myicon'; |
262
|
|
|
} |
263
|
|
|
|
264
|
|
|
foreach ($notification as $key => $value) { |
265
|
|
|
if (!in_array($key, $this->_allowedNotificationParameters)) { |
266
|
|
|
throw new Exception("The key {$key} is not allowed in notifications."); |
267
|
|
|
} |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
return $notification; |
271
|
|
|
} |
272
|
|
|
|
273
|
|
|
/** |
274
|
|
|
* _checkData method |
275
|
|
|
* |
276
|
|
|
* @param array $data |
277
|
|
|
* @throws Exception |
278
|
|
|
* @return array $data |
279
|
|
|
*/ |
280
|
|
|
public function _checkData(array $data = []) |
281
|
|
|
{ |
282
|
|
|
if (!is_array($data)) { |
283
|
|
|
throw new Exception('Data must ba an array.'); |
284
|
|
|
} |
285
|
|
|
|
286
|
|
|
if (empty($data)) { |
287
|
|
|
throw new Exception('Data\'s array can\'t be empty.'); |
288
|
|
|
} |
289
|
|
|
|
290
|
|
|
// Convert all data into string |
291
|
|
|
foreach ($data as $key => $value) { |
292
|
|
|
$data[$key] = (string)$value; |
293
|
|
|
} |
294
|
|
|
|
295
|
|
|
return $data; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* _checkParameters method |
300
|
|
|
* |
301
|
|
|
* @param array $parameters |
302
|
|
|
* @return array $parameters |
303
|
|
|
*/ |
304
|
|
|
protected function _checkParameters(array $parameters = []) |
305
|
|
|
{ |
306
|
|
|
$parameters = Hash::merge($this->config('parameters'), $parameters); |
307
|
|
|
$parameters = array_filter($parameters); |
308
|
|
|
|
309
|
|
|
if (isset($parameters['time_to_live']) && !is_int($parameters['time_to_live'])) { |
310
|
|
|
$parameters['time_to_live'] = (int)$parameters['time_to_live']; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
if (isset($parameters['delay_while_idle']) && !is_bool($parameters['delay_while_idle'])) { |
314
|
|
|
$parameters['delay_while_idle'] = (bool)$parameters['delay_while_idle']; |
315
|
|
|
} |
316
|
|
|
|
317
|
|
|
if (isset($parameters['dry_run']) && !is_bool($parameters['dry_run'])) { |
318
|
|
|
$parameters['dry_run'] = (bool)$parameters['dry_run']; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
return $parameters; |
322
|
|
|
} |
323
|
|
|
} |
324
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.