Completed
Branch ios (534a8a)
by Romain
02:05
created

GcmComponent::response()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4286
cc 2
eloc 4
nc 2
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 9 and the first side effect is on line 2.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
App::uses('Component', 'Controller');
3
App::uses('HttpSocket', 'Network/Http');
4
App::uses('Hash', 'Utility');
5
6
/**
7
* Gcm Exception classes
8
*/
9
class GcmException extends CakeException {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
10
}
11
12
/**
13
 * Gcm Component
14
 *
15
 */
16
class GcmComponent extends Component {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
17
18
	/**
19
	 * Default options
20
	 *
21
	 * @var array
22
	 */
23
	protected $_defaults = array(
24
		'api' => array(
25
			'key' => '',
26
			'url' => 'https://gcm-http.googleapis.com/gcm/send'
27
		),
28
		'parameters' => array(
29
			'collapse_key' => null,
30
			'priority' => 'normal',
31
			'delay_while_idle' => false,
32
			'dry_run' => false,
33
			'time_to_live' => 2419200,
34
			'restricted_package_name' => null
35
		)
36
	);
37
38
	/**
39
	 * Error code and message.
40
	 *
41
	 * @var array
42
	 */
43
	protected $_errorMessages = array();
44
45
	/**
46
	 * Response of the request
47
	 *
48
	 * @var object
49
	 */
50
	protected $_response = null;
51
52
	/**
53
	 * Controller reference
54
	 */
55
	protected $Controller = null;
56
57
	/**
58
	 * A Component collection, used to get more components.
59
	 *
60
	 * @var ComponentCollection
61
	 */
62
	protected $Collection;
63
64
	/**
65
	 * Constructor
66
	 *
67
	 * @param ComponentCollection $collection
68
	 * @param array $settings
69
	 */
70
	public function __construct(ComponentCollection $collection, $settings = array()) {
71
		$this->Collection = $collection;
72
		$this->_defaults = Hash::merge($this->_defaults, $settings);
73
74
		$this->_errorMessages = array(
75
			'400' => __('Error 400. The request could not be parsed as JSON or contained invalid fields.'),
76
			'401' => __('Error 401. Unable to authenticating the sender account.'),
77
			'500' => __('Error 500. Internal Server Error.'),
78
			'503' => __('Error 503. Service Unavailable.')
79
		);
80
	}
81
82
	/**
83
	 * Called before the Controller::beforeFilter().
84
	 *
85
	 * @param Controller $controller Controller with components to initialize
86
	 * @return void
87
	 */
88
	public function initialize(Controller $controller) {
89
		$this->Controller = $controller;
90
	}
91
92
	/**
93
	 * send method
94
	 *
95
	 * @param string|array $ids
96
	 * @param array $data
0 ignored issues
show
Bug introduced by
There is no parameter named $data. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
97
	 * @param array $parameters
98
	 * @param string $field
0 ignored issues
show
Bug introduced by
There is no parameter named $field. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
99
	 * @return void
100
	 */
101
	public function send($ids = false, $payload = array(), $parameters = array()) {
102
103
		if (is_string($ids)) {
104
			$ids = (array)$ids;
105
		}
106
107
		if ($ids === false || !is_array($ids) || empty($ids)) {
108
			throw new GcmException(__("Ids must be a string or an array."));
109
		}
110
111
		if (!is_array($payload)) {
112
			throw new GcmException(__("Payload must be an array."));
113
		}
114
115
		if (!is_array($parameters)) {
116
			throw new GcmException(__("Parameters must be an array."));
117
		}
118
119 View Code Duplication
		if (isset($payload['notification'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
120
			$payload['notification'] = $this->_checkNotification($payload['notification']);
121
			if (!$payload['notification']) {
122
				throw new GcmException(__("Unable to check notification."));
123
			}
124
		}
125
126 View Code Duplication
		if (isset($payload['data'])) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

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.

Loading history...
127
			$payload['data'] = $this->_checkData($payload['data']);
128
			if (!$payload['data']) {
129
				throw new GcmException(__("Unable to check data."));
130
			}
131
		}
132
133
		$parameters = $this->_checkParameters($parameters);
134
		if (!$parameters) {
135
			throw new GcmException(__("Unable to check parameters."));
136
		}
137
138
		$notification = $this->_buildMessage($ids, $payload, $parameters);
139
		if ($notification === false) {
140
			throw new GcmException(__("Unable to build the message."));
141
		}
142
143
		return $this->_executePush($notification);
144
	}
145
146
	/**
147
	 * sendNotification method
148
	 *
149
	 * @param string|array $ids
150
	 * @param array $notification
151
	 * @param array $parameters
152
	 * @return void
153
	 */
154
	public function sendNotification($ids = false, $notification = array(), $parameters = array()) {
155
		return $this->send($ids, array('notification' => $notification), $parameters);
156
	}
157
158
	/**
159
	 * sendData method
160
	 *
161
	 * @param string|array $ids
162
	 * @param array $data
163
	 * @param array $parameters
164
	 * @return void
165
	 */
166
	public function sendData($ids = false, $data = array(), $parameters = array()) {
167
		return $this->send($ids, array('data' => $data), $parameters);
168
	}
169
170
	/**
171
	 * response method
172
	 *
173
	 * @return void
174
	 */
175
	public function response() {
176
		if (array_key_exists($this->_response->code, $this->_errorMessages)) {
177
			return $this->_errorMessages[$this->_response->code];
178
		}
179
180
		return json_decode($this->_response->body, true);
181
	}
182
183
	/**
184
	 * _executePush method
185
	 *
186
	 * @param json $notification
187
	 * @return bool
188
	 */
189
	protected function _executePush($notification = false) {
190
		if ($notification === false) {
191
			return false;
192
		}
193
194
		if ($this->_defaults['api']['key'] === null) {
195
			throw new GcmException(__("No API key set. Push not triggered"));
196
		}
197
198
		$httpSocket = new HttpSocket();
199
		$this->_response = $httpSocket->post($this->_defaults['api']['url'], $notification, array(
200
			'header' => array(
201
				'Authorization' => 'key=' . $this->_defaults['api']['key'],
202
				'Content-Type' => 'application/json'
203
			)
204
		));
205
206
		if ($this->_response->code === '200') {
207
			return true;
208
		}
209
210
		return false;
211
	}
212
213
	/**
214
	 * _buildNotification method
215
	 *
216
	 * @param array $ids
217
	 * @param array $data
0 ignored issues
show
Bug introduced by
There is no parameter named $data. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
218
	 * @param array $parameters
219
	 * @param string $field
0 ignored issues
show
Bug introduced by
There is no parameter named $field. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
220
	 * @return json
221
	 */
222
	protected function _buildMessage($ids = false, $payload = false, $parameters = false) {
223
		if ($ids === false) {
224
			return false;
225
		}
226
227
		$message = array('registration_ids' => $ids);
228
229
		if (!empty($payload)) {
230
			$message += $payload;
231
		}
232
233
		if (!empty($parameters)) {
234
			$message += $parameters;
235
		}
236
237
		return json_encode($message);
238
	}
239
240
	/**
241
	 * _checkNotification method
242
	 *
243
	 * @param array $notification
244
	 * @return array $notification
245
	 */
246
	protected function _checkNotification($notification = false) {
247
		if ($notification === false) {
248
			return false;
249
		}
250
251
		if (!is_array($notification)) {
252
			throw new GcmException("Notification must be an array.");
253
		}
254
255
		if (empty($notification) || !isset($notification['title'])) {
256
			throw new GcmException("Notification's array must contain at least a key title.");
257
		}
258
259
		if (!isset($notification['icon'])) {
260
			$notification['icon'] = 'myicon';
261
		}
262
263
		return $notification;
264
	}
265
266
	/**
267
	 * _checkData method
268
	 *
269
	 * @param array $data
270
	 * @return array $data
271
	 */
272
	public function _checkData($data = false) {
273
		if ($data === false) {
274
			return false;
275
		}
276
277
		if (!is_array($data)) {
278
			throw new GcmException("Data must ba an array.");
279
		}
280
281
		if (empty($data)) {
282
			throw new GcmException("Data's array can't be empty.");
283
		}
284
285
		// Convert all data into string
286
		foreach ($data as $key => $value) {
287
			$data[$key] = strval($value);
288
		}
289
290
		return $data;
291
	}
292
293
	/**
294
	 * _checkParameters method
295
	 *
296
	 * @param array $parameters
297
	 * @return array $parameters
298
	 */
299
	protected function _checkParameters($parameters = false) {
300
		if ($parameters === false) {
301
			return false;
302
		}
303
304
		$parameters = Hash::merge($this->_defaults['parameters'], $parameters);
305
		$parameters = array_filter($parameters);
306
307
		if (isset($parameters['time_to_live']) && !is_int($parameters['time_to_live'])) {
308
			$parameters['time_to_live'] = (int)$parameters['time_to_live'];
309
		}
310
311
		if (isset($parameters['delay_while_idle']) && !is_bool($parameters['delay_while_idle'])) {
312
			$parameters['delay_while_idle'] = (bool)$parameters['delay_while_idle'];
313
		}
314
315
		if (isset($parameters['dry_run']) && !is_bool($parameters['dry_run'])) {
316
			$parameters['dry_run'] = (bool)$parameters['dry_run'];
317
		}
318
319
		return $parameters;
320
	}
321
}