forked from ding2/ting-client
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathting_client_class.inc
More file actions
384 lines (330 loc) · 12.2 KB
/
ting_client_class.inc
File metadata and controls
384 lines (330 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
<?php
/* \brief
* class depends heavily on ting-client module.
* builds requests for opensearch, openscan, openspell, openadhl and useraccessinfomedia webservices
*/
class ting_client_class {
private static $request_factory;
private static $ting_client;
private static $enable_cache = FALSE;
private static $enable_logging = FALSE;
private static $module;
private static $searchKey;
private $error = NULL;
public function __construct() {
// client_class tries to get some settings from the module using it.
// this is done to clear away drupal specific methods, so this library
// can be used by other frameworks
// where is this class used
// ting_client_class needs to know to get its settings; e.g urls for webservices and cache settings
// @TODO; get module name from somewhere else
self::$module = 'ting_client';
if (function_exists(self::$module . '_enable_cache')) {
$function = self::$module . '_enable_cache';
self::$enable_cache = call_user_func($function);
}
if (function_exists(self::$module . '_enable_logging')) {
$function = self::$module . '_enable_logging';
self::$enable_logging = call_user_func($function);
}
}
/**
* @param $requestName
* @param $params
* @param $cache_me; override configuration cache settings if needed
* @return bool|stdClass|string
*
*/
public function do_request($requestName, $params, $cache_me=TRUE) {
// set appropiate agent for testing
if ($simpletest_prefix = drupal_valid_test_ua()) {
NanoSOAPClient::setUserAgent(drupal_generate_test_ua($simpletest_prefix));
}
$settings = $this->request_factory()->getSettings($requestName);
$request = $this->request_factory()->getNamedRequest($requestName, $settings['class']);
if (empty($request)) {
$this->set_message('REMEMBER TO IMPLEMENT ' . $requestName . ' CLASS BEFORE USING IT', 'error');
return;
}
// set namespace(s) if set in settings
if (isset($settings['xsdNamespace'])) {
$request->setXsdNamespace($settings['xsdNamespace']);
}
$this->_set_params($request, $params);
$result = $this->execute($request, $cache_me);
// add cachekey to result
if (is_object($result)) {
if (method_exists($request, 'cacheKey')) {
$result->cacheKey = $request->cacheKey();
}
if (method_exists($request, 'searchKey')) {
$result->searchKey = $request->searchKey();
}
}
// Cache result in ting_mockup.
module_invoke_all('ting_client_mockup_cache_set', $request->cacheKey(), $result);
if (isset($settings['custom_parse'])) {
if (method_exists($request, $settings['custom_parse'])) {
$function = $settings['custom_parse'];
return $request->$function($result);
}
}
return $result;
}
/**
* @return array.
* List of variable names for XSD URLs. Fex. array('holdingstatus'=>'open_holdingstatus_xsd_url')
*/
public function getXSDurls() {
return $this->request_factory()->getXSDurls();
}
/**
* Get service definitions
*
* @return array.
* List of variable webservices
*/
public function getUrls() {
return $this->request_factory()->getUrls();
}
/** \brief
* initialize requestfactory
* return TingClientRequestFactory (@see ting-client/lib/request/TingClientRequestFactory.php
* */
private static function request_factory() {
// self::$request_factory=NULL;
if (!isset(self::$request_factory)) {
$url_variables = array(
'search' => array('url' => 'ting_search_url', 'class' => 'TingClientSearchRequest'),
// 'scan' => array('url' => 'ting_scan_url', 'class' => ''),
'object' => array('url' => 'ting_search_url', 'class' => 'TingClientObjectRequest'),
'collection' => array('url' => 'ting_search_url', 'class' => 'TingCollectionRequest'),
// 'spell' => array('url' => 'ting_spell_url', 'class' => ''),
);
$urls = array();
// get the real urls from the module using ting-client
if (function_exists(self::$module . '_set_request_factory')) {
$function = self::$module . '_set_request_factory';
$urls = call_user_func_array($function, array($url_variables));
}
self::$request_factory = new TingClientRequestFactory($urls);
}
return self::$request_factory;
}
/**
* helper method to set parameters on a TingClientRequest (or extending) object
* */
private function _set_params($request, $params) {
foreach ($params as $key => $value) {
$setter = 'set' . ucfirst($key);
if (method_exists($request, $setter)) {
$request->$setter($value);
}
else {
$message = get_class($request) . ' does not implement: ' . $setter;
$error['message'] = $message;
$error['status'] = 'error';
$error['repeat'] = FALSE;
$error['watchdog'] = array(
'type' => 'error',
'message' => $message,
'link' => '',
);
self::_invoke('set_message', $error);
}
}
}
private function get_from_cache($request, &$cache) {
if (!function_exists(self::$module . '_cache_get')) {
return FALSE;
}
else {
$cache_function = self::$module . '_cache_get';
}
// overall caching variable (for all requests)
$requestcache = self::$enable_cache;
if ($requestcache && self::_class_implements($request, 'ITingClientRequestCache')) {
if ($request->cacheEnable()) {
// everything is okay for caching; set passed cache variable for execute method
$cache = TRUE;
// call getRequest method to set parameters for cachekey
$request->getRequest();
$cached_result = call_user_func_array($cache_function, array($request->cacheKey(), $request->cacheBin()));
}
}
// Return cache information from ting_mockup.
// @see bibdk_mockup module
$mockup_cache_result = module_invoke_all('ting_client_mockup_cache_get', $request->cacheKey());
if (!empty($mockup_cache_result) && $mockup_cache_result['status'] === TRUE) {
return $mockup_cache_result['record'];
}
if (!empty($cached_result)) {
$res = $cached_result->data;
return $res;
}
return FALSE;
}
public function get_all_cache_classes() {
static $ret;
if (!isset($ret)) {
$ret = array();
$factory = $this->request_factory();
$request_methods = get_class_methods($factory);
foreach ($factory->urls as $name => $settings) {
if (!empty($settings['class'])) {
if (class_exists($settings['class']) && self::_class_implements($settings['class'], 'ITingClientRequestCache')) {
// do not handle extending classes
// disabled for handling infomediaRequests.
// DO NOT DELETE this might come in handy later on
// $parents = class_parents($settings['class']);
//if (count($parents) == 1) {
$arr['name'] = $name;
$arr['className'] = $settings['class'];
$ret[] = $arr;
// }
}
}
}
}
return $ret;
}
/* \brief check whether a given class implements a specific interface
* @param class ; the class to check
* @param interface ; the interface to check for
* return bool
*/
private static function _class_implements($class, $interface) {
$interfaces = class_implements($class);
if (in_array($interface, $interfaces)) {
return true;
}
return false;
}
/**
* execute a request
* */
private function execute($request, $cache_me = TRUE) {
// set useragent for simpletest framework
if ($simpletest_prefix = drupal_valid_test_ua()) {
NanoSOAPClient::setUserAgent(drupal_generate_test_ua($simpletest_prefix));
}
$cache = FALSE;
if (($res = $this->get_from_cache($request, $cache)) && $cache_me) {
return $res;
}
else {
try {
// Start timer
self::_invoke('timer', array('start', 'search_client'));
// make request
$res = self::ting_client()->execute($request);
// stop timer
self::_invoke('timer', array('stop', 'search_client'));
/** @var TingClientRequest $request */
if ($request->checkResponse($res)) {
if ($cache) {
$expire = REQUEST_TIME + (60 * $request->cacheTimeout());
if (function_exists(self::$module . '_cache_set')) {
$function = self::$module . '_cache_set';
call_user_func_array($function, array($request->cacheKey(), $res, $request->cacheBin(), $expire));
}
}
}
else{
watchdog('ting client', '%class returned FALSE in checkResponse NO caching done', array('%class' => get_class($request)), WATCHDOG_NOTICE);
}
return $res;
} catch (Exception $e) {
self::_invoke('timer', array('stop', 'search_client'));
$this->_handleRequestExceptions($e, $request->getWsdlUrl());
return FALSE;
}
}
}
private function _handleRequestExceptions($e, $url) {
// set message if ting-client throws an exeception
$message = t('something_went_wrong', array(), array('context' => 'ting_client'));
$status = 'error';
$watchdog['type'] = 'ting_client';
$watchdog['message'] = 'Error performing request: ' . $e->getMessage();
if ( !empty($url) ) {
$watchdog['message'] .= '. URL: ' . $url;
}
$watchdog['variables'] = NULL;
$watchdog['status'] = $status;
$watchdog['link'] = $_SERVER["HTTP_HOST"] . $_SERVER['REQUEST_URI'];
self::_invoke('set_message', array($message, 'error', NULL, $watchdog));
$this->setError($e);
}
private function setError($e) {
$this->error['message'] = $e->getMessage();
$this->error['code'] = $e->getCode();
}
public function getError() {
return $this->error;
}
private static function _invoke($function, $params) {
if (empty(self::$module)) {
return;
}
$function = self::$module . '_' . $function;
if (function_exists($function)) {
call_user_func_array($function, $params);
}
}
private static function _set_internal_error_message() {
return t('Please contact site administrator if problem persists');
}
/* \brief
* Initialize TingClient.
* return TingClient. TingClient takes a logger and an adapter in constructor
* @see ting-client/lib/TingClient.php
* @see ting-client/lib/adapter/TingClientRequestAdapter.php
* @see ting-client/lib/log/TingClientDrupalWatchDogLogger.php
* */
// @TODO; get TingClientDrupalWatchDogLogger out of this class
private static function ting_client() {
if (!isset(self::$client)) {
// $logger = (variable_get('ting_enable_logging', FALSE)) ? new TingClientDrupalWatchDogLogger($this->request_factory()) : new TingClientVoidLogger();
$logger = (self::$enable_logging) ? new TingClientDrupalWatchDogLogger(self::request_factory()) : new TingClientVoidLogger();
self::$ting_client = new TingClient(new TingClientRequestAdapter(), $logger);
}
return self::$ting_client;
}
/**
* Attempt to quote reserved words in a search query.
*
* As proper quoting would require a full CQL parser, we cheat and
* just work on the part we know is the free text part.
*
* Also, we don't mess with uppercase reserved words.
*/
public static function quote($string) {
if (preg_match('/^(.*?)(AND \(.*|$)/', $string, $rx)) {
$keys = $rx[1];
$new_keys = preg_replace_callback('/(?:(".*?(?<!\\\)")|\b(and|or|not|prox)\b)/i', array('ting_client_class', 'quote_callback'), $keys);
$string = preg_replace('/^' . preg_quote($keys) . '/', $new_keys, $string);
}
return $string;
}
/**
*
*/
private static function quote_callback($matches) {
// If $matches[2] is empty, it's because the quote pattern
// matched. Don't do anything with it.
if (!empty($matches[2])) {
// Boolean operator, but not uppercase, quote it.
if ($matches[2] != drupal_strtoupper($matches[2])) {
return '"' . $matches[2] . '"';
}
// Uppercase boolean operator, return as is.
return $matches[2];
}
// We have a quote. Just return it.
return $matches[1];
}
public static function getAllUrls() {
return self::request_factory()->getUrls();
}
}