Subversion Repositories SmartDukaan

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
13637 anikendra 1
<?php
2
App::uses('DboSource', 'Model/Datasource');
3
 
4
class RestSource extends DboSource {
5
	public $description = 'Rest Source';
6
 
7
	public $headers = array();
8
 
9
/**
10
 * __construct
11
 *
12
 * We are not a dbo source - we are secretly a datasource and just want the log functions, hence we extend
13
 * DboSource
14
 *
15
 * @param mixed $config
16
 * @param mixed $autoConnect
17
 * @return void
18
 */
19
	public function __construct($config = null, $autoConnect = true) {
20
		DataSource::__construct($config);
21
		$this->fullDebug = Configure::read('debug') > 1;
22
	}
23
 
24
/**
25
* Execute a custom query against the REST server
26
*
27
* $model->get('custom_method',)
28
* $model->post('custom_method', array())
29
*
30
* @param string $method The HTTP verb to execute (get, post, pull, delete)
31
* @param array $pass	The raw configuration
32
* @param Model $model	The model that triggered the call
33
* @return mixed
34
*/
35
	public function query($method, $pass, Model $model) {
36
		if (empty($pass)) {
37
			throw new Exception('Missing information about the HTTP request');
38
		}
39
 
40
		$t = microtime(true);
41
 
42
		$config = $pass[0];
43
		if (!is_array($config)) {
44
			$config = array('action' => $config);
45
		}
46
 
47
		if (empty($config['action'])) {
48
			throw new Exception('Missing action key');
49
		}
50
 
51
		$url = sprintf('/%s/%s', $model->remoteResource, $config['action']);
52
 
53
		$cu = new \Nodes\Curl($this->getBaseUrl() . $url);
54
		$this->applyConfiguration($cu);
55
 
56
		$data = null;
57
		if (in_array($method, array('put', 'post')) && isset($pass[1])) {
58
			$data = $pass[1];
59
		}
60
 
61
		try {
62
			$response = call_user_func(array($cu, $method), $data);
63
 
64
			if ($this->fullDebug) {
65
				$this->took = round((microtime(true) - $t) * 1000, 0);
66
				$this->numRows = $this->affected = $response['data'] ? count(current($response['data'])) : 0;
67
				$this->logQuery($url, $params);
68
			}
69
 
70
			return $response;
71
 
72
		} catch (Exception $e) {
73
			$this->logQuery($url, $params);
74
 
75
			CakeLog::error($e);
76
			return array();
77
		}
78
	}
79
 
80
/**
81
* Execute a HTTP POST request against a REST resource
82
*
83
* @param Model $model	The model that is executing the save()
84
* @param array $fields	A list of fields that needs to be saved
85
* @param array $values	A list of values that need to be saved
86
* @return mixed
87
*/
88
	public function create(Model $model, $fields = null, $values = null) {
89
		$t = microtime(true);
90
 
91
		$method = 'post';
92
		$url	= sprintf('/%s', $model->remoteResource);
93
		if(!empty($data['id'])) {
94
			$url = sprintf('/%s/%s', $model->remoteResource, $data['id']);
95
			$method = 'put';
96
		}
97
 
98
		$data = array();
99
		if (!empty($fields) && !empty($values)) {
100
			$data = array_combine($fields, $values);
101
		}
102
 
103
		$cu = new \Nodes\Curl($this->getBaseUrl() . $url);
104
		$this->applyConfiguration($cu);
105
 
106
		try {
107
			$response = call_user_func(array($cu, $method), $data);
108
 
109
			if ($this->fullDebug) {
110
				$this->took = round((microtime(true) - $t) * 1000, 0);
111
				$responseData = $response->getResponseBody('data');
112
				$this->numRows = $this->affected = isset($responseData['data']) ? count(current($responseData['data'])) : 0;
113
				$this->logQuery($url, $data);
114
			}
115
 
116
			return $response;
117
		} catch (Exception $e) {
118
			if ($this->fullDebug) {
119
				$this->logQuery($url);
120
			}
121
			CakeLog::error($e);
122
			return array();
123
		}
124
	}
125
 
126
/**
127
* Execute a GET request against a REST resource
128
*
129
* @param Model $model		The model that is executing find() / read()
130
* @param array $queryData	The conditions for the find - currently we only support "id" => $value
131
* @return mixed
132
*/
133
	public function read(Model $model, $queryData = array()) {
134
		$t = microtime(true);
135
 
136
		$url = $this->config['host'] . DS . $model->remoteResource;
137
 
138
		if (isset($queryData['action'])) {
139
			$url .= DS . $queryData['action'];
140
		}
141
 
142
		if (!empty($queryData['conditions']['id'])) {
143
			$url .= DS . $queryData['conditions']['id'];
144
			unset($queryData['conditions']['id']);
145
		}
146
 
147
		if (!empty($this->config['format'])) {
148
			$url = trim($url, DS) . '.' . $this->config['format'];
149
		}
150
 
151
		if (!empty($queryData['limit'])) {
152
			$queryData['conditions']['limit'] = $queryData['limit'];
153
		}
154
 
155
		if (!empty($queryData['offset'])) {
156
			$queryData['conditions']['offset'] = $queryData['offset'];
157
		}
158
 
159
		if (!empty($queryData['order'])) {
160
			$queryData['conditions']['order'] = $queryData['order'];
161
		}
162
 
163
		if (!empty($queryData['page'])) {
164
			$queryData['conditions']['page'] = $queryData['page'];
165
		}
166
 
167
		if (!empty($queryData['conditions'])) {
168
			$url .= '?' . http_build_query($queryData['conditions']);
169
		}
170
 
171
		try {
172
			$cu = new \Nodes\Curl($url);
173
			$this->applyConfiguration($cu);
174
 
175
			$response = $cu->get()->getResponseBody();
176
 
177
			if ($this->fullDebug) {
178
				$this->took = round((microtime(true) - $t) * 1000, 0);
179
				$current = is_array($response['data']) ? current($response['data']) : array();
180
				$this->numRows = $this->affected = $response['data'] ? count($current) : 0;
181
				$this->logQuery($url, $queryData);
182
			}
183
 
184
			if (empty($response['success'])) {
185
				return array();
186
			}
187
			return $response['data'];
188
		} catch (Exception $e) {
189
			if ($this->fullDebug) {
190
				$this->logQuery($url, $queryData);
191
			}
192
 
193
			CakeLog::error($e);
194
			return array();
195
		}
196
	}
197
 
198
/**
199
* Execute a PUT request against a REST resource
200
*
201
* @param Model $model		The model that is executing the save()
202
* @param array $fields		A list of fields that needs to be saved
203
* @param array $values		A list of values that need to be saved
204
* @param array $conditions	Update conditions - currently not used
205
* @return mixed
206
*/
207
	public function update(Model $model, $fields = array(), $values = null, $conditions = null) {
208
		$data	= array_combine($fields, $values);
209
		$url	= sprintf('/%s', $model->remoteResource);
210
		$cu		= new \Nodes\Curl($this->getBaseUrl() . $url);
211
		$this->applyConfiguration($cu);
212
 
213
		try {
214
			return $cu->put($data);
215
		} catch (Exception $e) {
216
			CakeLog::error($e);
217
			return array();
218
		}
219
	}
220
 
221
/**
222
* Execute a DELETE request against a REST resource
223
*
224
* @param Model $model	The model that is executing the delete()
225
* @param mixed $id		The resource ID to delete
226
* @return mixed
227
*/
228
	public function delete(Model $model, $id = null) {
229
		$url	= sprintf('/%s/%s', $model->remoteResource, $id);
230
		$cu		= new \Nodes\Curl($this->getBaseUrl() . $url);
231
		$this->applyConfiguration($cu);
232
 
233
		try {
234
			return $cu->delete();
235
		} catch (Exception $e) {
236
			CakeLog::error($e);
237
			return array();
238
		}
239
	}
240
 
241
/**
242
* Build the baseURL based on configuration options
243
*  - protocol	string	Can be HTTP or HTTPS (default)
244
*  - hostname	string	The hostname of the application server
245
*  - admin		boolean If the remote URL is within an admin routing
246
*
247
* @return string
248
*/
249
	public function getBaseUrl() {
250
		return $this->config['host'];
251
	}
252
 
253
/**
254
 * Caches/returns cached results for child instances
255
 *
256
 * @param mixed $data
257
 * @return array Array of sources available in this datasource.
258
 */
259
	public function listSources($data = null) {
260
		return true;
261
	}
262
 
263
/**
264
* Apply some custom confiuration to our cURL object
265
* - Set the Platform-Token HTTP header for remote authentication
266
* - Set the
267
*
268
* @param Curl $cu	The cURL object we want to apply configuration for
269
* @return void
270
*/
271
	public function applyConfiguration(\Nodes\Curl $cu) {
272
		$check = array_map(function($h) { return current(explode(':', $h)); }, $this->headers);
273
		if (!in_array('X-Authorization', $check)) {
274
			throw new InternalErrorException('No API token provided');
275
		}
276
		$cu->setOption(CURLOPT_HTTPHEADER, $this->headers);
277
	}
278
}