cdm-dataportal / modules / cdm_dataportal / cdm_api / cdm_api.module @ 64cfdac1
History | View | Annotate | Download (88.8 KB)
1 |
<?php |
---|---|
2 |
/** |
3 |
* @file |
4 |
* Required or useful functions for using CDM Data Store Webservices. |
5 |
* |
6 |
* Naming conventions: |
7 |
* ---------------------- |
8 |
* - All webservice access methods are prefixed with cdm_ws. |
9 |
* |
10 |
* @copyright |
11 |
* (C) 2007-2012 EDIT |
12 |
* European Distributed Institute of Taxonomy |
13 |
* http://www.e-taxonomy.eu |
14 |
* |
15 |
* The contents of this module are subject to the Mozilla |
16 |
* Public License Version 1.1. |
17 |
* @see http://www.mozilla.org/MPL/MPL-1.1.html |
18 |
* |
19 |
* @author |
20 |
* - Andreas Kohlbecker <a.kohlbecker@BGBM.org> |
21 |
* - Wouter Addink <w.addink@eti.uva.nl> (migration from Drupal 5 to Drupal7) |
22 |
*/ |
23 |
|
24 |
module_load_include('php', 'cdm_api', 'xml2json'); |
25 |
module_load_include('php', 'cdm_api', 'commons'); |
26 |
module_load_include('php', 'cdm_api', 'uuids'); |
27 |
module_load_include('php', 'cdm_api', 'enums'); |
28 |
module_load_include('php', 'cdm_api', 'webservice_uris'); |
29 |
module_load_include('php', 'cdm_api', 'cdm_node'); |
30 |
module_load_include('inc', 'cdm_api', 'tagged_text'); |
31 |
|
32 |
/** |
33 |
* Timeout used to override the default of 30 seconds |
34 |
* in @see drupal_http_request() |
35 |
* |
36 |
* @var CDM_HTTP_REQUEST_TIMEOUT: A float representing the maximum number of seconds the function |
37 |
* call may take |
38 |
*/ |
39 |
define('CDM_HTTP_REQUEST_TIMEOUT', 90.0); |
40 |
|
41 |
|
42 |
|
43 |
/** |
44 |
* orderBy webservice query parameter value |
45 |
*/ |
46 |
define('CDM_ORDER_BY_ID_ASC', 'BY_ID_ASC'); |
47 |
|
48 |
/** |
49 |
* orderBy webservice query parameter value |
50 |
*/ |
51 |
define('CDM_ORDER_BY_ID_DESC', 'BY_ID_DESC'); |
52 |
/** |
53 |
* orderBy webservice query parameter value |
54 |
*/ |
55 |
define('CDM_ORDER_BY_TITLE_CACHE_ASC', 'BY_TITLE_CACHE_ASC'); |
56 |
/** |
57 |
* orderBy webservice query parameter value |
58 |
*/ |
59 |
define('CDM_ORDER_BY_TITLE_CACHE_DESC', 'BY_TITLE_CACHE_DESC'); |
60 |
/** |
61 |
* orderBy webservice query parameter value |
62 |
*/ |
63 |
define('CDM_ORDER_BY_NOMENCLATURAL_ORDER_ASC', 'BY_NOMENCLATURAL_ORDER_ASC'); |
64 |
/** |
65 |
* orderBy webservice query parameter value |
66 |
*/ |
67 |
define('CDM_ORDER_BY_NOMENCLATURAL_ORDER_DESC', 'BY_NOMENCLATURAL_ORDER_DESC'); |
68 |
/** |
69 |
* orderBy webservice query parameter value |
70 |
*/ |
71 |
define('CDM_ORDER_BY_ORDER_INDEX_ASC', 'BY_ORDER_INDEX_ASC'); |
72 |
/** |
73 |
* orderBy webservice query parameter value |
74 |
*/ |
75 |
define('CDM_ORDER_BY_ORDER_INDEX_DESC', 'BY_ORDER_INDEX_DESC'); |
76 |
|
77 |
|
78 |
/** |
79 |
* Implements hook_menu(). |
80 |
*/ |
81 |
function cdm_api_menu() { |
82 |
$items = array(); |
83 |
|
84 |
// usage: url('cdm_api/proxy/'.urlencode($content_url)."/$theme"); |
85 |
$items['cdm_api/proxy'] = array( |
86 |
'page callback' => 'proxy_content', |
87 |
'access arguments' => array( |
88 |
'access cdm content', |
89 |
), |
90 |
'type' => MENU_CALLBACK, |
91 |
); |
92 |
|
93 |
$items['cdm_api/setvalue/session'] = array( |
94 |
'page callback' => 'setvalue_session', |
95 |
'access arguments' => array( |
96 |
'access cdm content', |
97 |
), |
98 |
'type' => MENU_CALLBACK, |
99 |
); |
100 |
|
101 |
return $items; |
102 |
} |
103 |
|
104 |
/** |
105 |
* Implements hook_block_info(). |
106 |
*/ |
107 |
function cdm_api_block_info() { |
108 |
|
109 |
$block['cdm_ws_debug'] = array( |
110 |
"info" => t("CDM web service debug"), |
111 |
"cache" => DRUPAL_NO_CACHE |
112 |
); |
113 |
return $block; |
114 |
} |
115 |
|
116 |
/** |
117 |
* Implements hook_block_view(). |
118 |
*/ |
119 |
function cdm_api_block_view($delta) { |
120 |
switch ($delta) { |
121 |
case 'cdm_ws_debug': |
122 |
|
123 |
$cdm_ws_url = variable_get('cdm_webservice_url', ''); |
124 |
|
125 |
$field_map = array( |
126 |
'ws_uri' => t('URI') . ' <code>(' . $cdm_ws_url .'...)</code>', |
127 |
'time' => t('Time'), |
128 |
'fetch_seconds' => t('Fetching [s]'), |
129 |
'parse_seconds' => t('Parsing [s]'), |
130 |
'size_kb' => t('Size [kb]'), |
131 |
'status' => t('Status'), |
132 |
'data_links' => t('Links'), |
133 |
); |
134 |
|
135 |
|
136 |
if (!isset($_SESSION['cdm']['ws_debug'])) { |
137 |
$_SESSION['cdm']['ws_debug'] = array(); |
138 |
} |
139 |
|
140 |
$header = '<thead><tr><th>' . join('</th><th>' , array_values($field_map)) . '</th></thead>'; |
141 |
$footer = '<tfoot><tr><th>' . join('</th><th>' , array_values($field_map)) . '</th></tfoot>'; |
142 |
$rows = array(); |
143 |
|
144 |
foreach ($_SESSION['cdm']['ws_debug'] as $data){ |
145 |
|
146 |
$data = unserialize($data); |
147 |
|
148 |
// stip of webservice base url |
149 |
$data['ws_uri'] = str_replace($cdm_ws_url, '', $data['ws_uri']); |
150 |
if($data['method'] == 'POST'){ |
151 |
$data['ws_uri'] = 'POST: ' . $data['ws_uri'] . '?' . $data['post_data']; |
152 |
} |
153 |
|
154 |
$cells = array(); |
155 |
foreach ($field_map as $field => $label){ |
156 |
$cells[] = '<td class="' . $field . '">' . $data[$field] . '</td>'; |
157 |
} |
158 |
$rows[] = '<tr class="' . $data['status'] . '">' . join('' , $cells). '</tr>'; |
159 |
} |
160 |
// clear session again |
161 |
$_SESSION['cdm']['ws_debug'] = array(); |
162 |
|
163 |
_add_js_ws_debug(); |
164 |
|
165 |
$block['subject'] = ''; // no subject, title in content for having a defined element id |
166 |
// otherwise it would depend on the theme |
167 |
$block['content'] = array( |
168 |
'#markup' => '<h4 id="cdm-ws-debug-button">' . t('CDM Debug') . '</h4>' |
169 |
// cannot use theme_table() since table footer is not jet supported in D7 |
170 |
. '<div id="cdm-ws-debug-table-container"><table id="cdm-ws-debug-table">' |
171 |
. $header |
172 |
. '<tbody>' . join('', $rows) . '</tbody>' |
173 |
. $footer |
174 |
. '</table></div>', |
175 |
'#attached' => array( |
176 |
'css' => array( |
177 |
drupal_get_path('module', 'cdm_dataportal') . '/cdm_dataportal_ws_debug.css' |
178 |
) |
179 |
) |
180 |
); |
181 |
return $block; |
182 |
} |
183 |
} |
184 |
|
185 |
/** |
186 |
* Implements hook_cron(). |
187 |
* |
188 |
* Expire outdated cache entries. |
189 |
*/ |
190 |
function cdm_api_cron() { |
191 |
cache_clear_all(NULL, 'cache_cdm_ws'); |
192 |
} |
193 |
|
194 |
/** |
195 |
* Lists the classifications a taxon belongs to |
196 |
* |
197 |
* @param CDM type Taxon $taxon |
198 |
* the taxon |
199 |
* |
200 |
* @return array |
201 |
* aray of CDM instances of Type Classification |
202 |
*/ |
203 |
function get_classifications_for_taxon($taxon) { |
204 |
|
205 |
return cdm_ws_get(CDM_WS_TAXON_CLASSIFICATIONS, $taxon->uuid); |
206 |
} |
207 |
|
208 |
/** |
209 |
* Returns the chosen FeatureTree to be used as FeatureTree for the taxon profile. |
210 |
* |
211 |
* The FeatureTree returned is the term tree one that has been set in the |
212 |
* dataportal settings (layout->taxon:profile). |
213 |
* When the chosen FeatureTree is not found in the database, |
214 |
* the standard feature tree (UUID_DEFAULT_FEATURETREE) will be returned. |
215 |
* |
216 |
* @return object |
217 |
* A cdm TermTree object. |
218 |
*/ |
219 |
function get_profile_feature_tree() { |
220 |
static $profile_featureTree; |
221 |
|
222 |
if($profile_featureTree == NULL) { |
223 |
$profile_featureTree = cdm_ws_get( |
224 |
CDM_WS_TERMTREE, |
225 |
variable_get(CDM_PROFILE_FEATURETREE_UUID, UUID_DEFAULT_FEATURETREE) |
226 |
); |
227 |
if (!$profile_featureTree) { |
228 |
$profile_featureTree = cdm_ws_get(CDM_WS_TERMTREE, UUID_DEFAULT_FEATURETREE); |
229 |
} |
230 |
} |
231 |
|
232 |
return $profile_featureTree; |
233 |
} |
234 |
|
235 |
/** |
236 |
* Returns the chosen TermTree to be used as FeatureTree for SpecimenDescriptions. |
237 |
* |
238 |
* The TermTree returned is the one that has been set in the |
239 |
* dataportal settings (layout->taxon:specimen). |
240 |
* When the chosen TermTree is not found in the database, |
241 |
* the standard term tree (UUID_DEFAULT_TERMTREE) will be returned. |
242 |
* |
243 |
* @return object |
244 |
* A cdm TermTree object. |
245 |
*/ |
246 |
function cdm_get_occurrence_featureTree() { |
247 |
static $occurrence_featureTree; |
248 |
|
249 |
if($occurrence_featureTree == NULL) { |
250 |
$occurrence_featureTree = cdm_ws_get( |
251 |
CDM_WS_TERMTREE, |
252 |
variable_get(CDM_OCCURRENCE_FEATURETREE_UUID, UUID_DEFAULT_FEATURETREE) |
253 |
); |
254 |
if (!$occurrence_featureTree) { |
255 |
$occurrence_featureTree = cdm_ws_get(CDM_WS_TERMTREE, UUID_DEFAULT_FEATURETREE); |
256 |
} |
257 |
} |
258 |
return $occurrence_featureTree; |
259 |
} |
260 |
|
261 |
/** |
262 |
* Returns the FeatureTree for structured descriptions |
263 |
* |
264 |
* The FeatureTree returned is the one that has been set in the |
265 |
* dataportal settings (layout->taxon:profile). |
266 |
* When the chosen FeatureTree is not found in the database, |
267 |
* the standard feature tree (UUID_DEFAULT_FEATURETREE) will be returned. |
268 |
* |
269 |
* @return mixed |
270 |
* A cdm FeatureTree object. |
271 |
*/ |
272 |
function get_structured_description_featureTree() { |
273 |
static $structured_description_featureTree; |
274 |
|
275 |
if($structured_description_featureTree == NULL) { |
276 |
$structured_description_featureTree = cdm_ws_get( |
277 |
CDM_WS_TERMTREE, |
278 |
variable_get(CDM_DATAPORTAL_STRUCTURED_DESCRIPTION_FEATURETREE_UUID, UUID_DEFAULT_FEATURETREE) |
279 |
); |
280 |
if (!$structured_description_featureTree) { |
281 |
$structured_description_featureTree = cdm_ws_get( |
282 |
CDM_WS_TERMTREE, |
283 |
UUID_DEFAULT_FEATURETREE |
284 |
); |
285 |
} |
286 |
} |
287 |
return $structured_description_featureTree; |
288 |
} |
289 |
|
290 |
|
291 |
/** |
292 |
* @todo Please document this function. |
293 |
* @see http://drupal.org/node/1354 |
294 |
*/ |
295 |
function set_last_taxon_page_tab($taxonPageTab) { |
296 |
$_SESSION['cdm']['taxon_page_tab'] = $taxonPageTab; |
297 |
} |
298 |
|
299 |
/** |
300 |
* @todo Please document this function. |
301 |
* @see http://drupal.org/node/1354 |
302 |
*/ |
303 |
function get_last_taxon_page_tab() { |
304 |
if (isset($_SESSION['cdm']['taxon_page_tab'])) { |
305 |
return $_SESSION['cdm']['taxon_page_tab']; |
306 |
} |
307 |
else { |
308 |
return FALSE; |
309 |
} |
310 |
} |
311 |
|
312 |
/** |
313 |
* NOTE: The cdm-library provides a very similar server side function. See |
314 |
* eu.etaxonomy.cdm.model.media.MediaUtils.filterAndOrderMediaRepresentations() |
315 |
* |
316 |
* @param object $media |
317 |
* @param array $mimeTypes |
318 |
* an array of mimetypes in their order of preference. e.g: |
319 |
* array('application/pdf', 'image/png', 'image/jpeg', 'image/gif', 'text/html') |
320 |
* @param int $width |
321 |
* The width of the optimal image. If null, the method will return the representation with the biggest expansion |
322 |
* @param int $height |
323 |
* The height of the optimal image. If null, the method will return the representation with the biggest expansion |
324 |
* |
325 |
* @return array |
326 |
* An array with preferred media representations or else an empty array. |
327 |
*/ |
328 |
function cdm_preferred_media_representations($media, array $mimeTypes, $width = NULL, $height = NULL) { |
329 |
$prefRepr = array(); |
330 |
if (!isset($media->representations[0])) { |
331 |
return $prefRepr; |
332 |
} |
333 |
|
334 |
while (count($mimeTypes) > 0) { |
335 |
// getRepresentationByMimeType |
336 |
$mimeType = array_shift($mimeTypes); |
337 |
|
338 |
foreach ($media->representations as &$representation) { |
339 |
// If the mimetype is not known, try inferring it. |
340 |
if (!$representation->mimeType) { |
341 |
if (isset($representation->parts[0])) { |
342 |
$representation->mimeType = infer_mime_type($representation->parts[0]->uri); |
343 |
} |
344 |
} |
345 |
|
346 |
if ($representation->mimeType == $mimeType) { |
347 |
// Preferred mimetype found -> erase all remaining mimetypes |
348 |
// to end loop. |
349 |
$mimeTypes = array(); |
350 |
$expansionDeltaSum = 0; |
351 |
$valid_parts_cnt = 0; |
352 |
// Look for part with the best matching size. |
353 |
foreach ($representation->parts as $part) { |
354 |
if (empty($part->uri)) { |
355 |
// skip part if URI is missing |
356 |
continue; |
357 |
} |
358 |
$valid_parts_cnt++; |
359 |
$expansionDelta = PHP_INT_MAX; // biggest delta for unknown sizes |
360 |
|
361 |
// determine the optimal size |
362 |
if (isset($part->width) && isset($part->height)) { |
363 |
$expansion = $part->width * $part->height; |
364 |
if ($width != null && $height != null) { |
365 |
$optimalExpansion = $height * $width; |
366 |
} else { |
367 |
$optimalExpansion = PHP_INT_MAX; |
368 |
} |
369 |
// determine the difference |
370 |
$expansionDelta = $expansion > $optimalExpansion ? $expansion - $optimalExpansion : $optimalExpansion - $expansion; |
371 |
} |
372 |
// sum up the expansionDeltas of all parts contained in the representation |
373 |
$expansionDeltaSum += $expansionDelta; |
374 |
} |
375 |
if($valid_parts_cnt > 0){ |
376 |
$expansionDeltaSum = $expansionDeltaSum / $valid_parts_cnt; |
377 |
$prefRepr[$expansionDeltaSum] = $representation; |
378 |
} |
379 |
} |
380 |
} |
381 |
} |
382 |
// Sort the array so that the smallest key value is the first in the array |
383 |
ksort($prefRepr); |
384 |
return $prefRepr; |
385 |
} |
386 |
|
387 |
/** |
388 |
* Infers the mime type of a file using the filename extension. |
389 |
* |
390 |
* The filename extension is used to infer the mime type. |
391 |
* |
392 |
* @param string $filepath |
393 |
* The path to the respective file. |
394 |
* |
395 |
* @return string |
396 |
* The mimetype for the file or FALSE if the according mime type could |
397 |
* not be found. |
398 |
*/ |
399 |
function infer_mime_type($filepath) { |
400 |
static $mimemap = NULL; |
401 |
if (!$mimemap) { |
402 |
$mimemap = array( |
403 |
'jpg' => 'image/jpeg', |
404 |
'jpeg' => 'image/jpeg', |
405 |
'png' => 'image/png', |
406 |
'gif' => 'image/gif', |
407 |
'giff' => 'image/gif', |
408 |
'tif' => 'image/tif', |
409 |
'tiff' => 'image/tif', |
410 |
'pdf' => 'application/pdf', |
411 |
'html' => 'text/html', |
412 |
'htm' => 'text/html', |
413 |
); |
414 |
} |
415 |
$extension = substr($filepath, strrpos($filepath, '.') + 1); |
416 |
if (isset($mimemap[$extension])) { |
417 |
return $mimemap[$extension]; |
418 |
} |
419 |
else { |
420 |
// FIXME remove this hack just return FALSE; |
421 |
return 'text/html'; |
422 |
} |
423 |
} |
424 |
|
425 |
/** |
426 |
* Formats a mysql datatime as string |
427 |
* |
428 |
* @param $datetime |
429 |
* @param string $format |
430 |
* |
431 |
* @return |
432 |
* the formatted string representation of the $datetime |
433 |
*/ |
434 |
function format_datetime($datetime, $format = 'Y-m-d H:i:s', $strip_zeros = true){ |
435 |
return date($format, strtotime($datetime)); |
436 |
} |
437 |
|
438 |
/** |
439 |
* Converts an ISO 8601 org.joda.time.Partial to a year. |
440 |
* |
441 |
* The function expects an ISO 8601 time representation of a |
442 |
* org.joda.time.Partial of the form yyyy-MM-dd. |
443 |
* |
444 |
* @param string $partial |
445 |
* ISO 8601 time representation of a org.joda.time.Partial. |
446 |
* |
447 |
* @return string |
448 |
* Returns the year. In case the year is unknown (= ????), it returns NULL. |
449 |
*/ |
450 |
function partialToYear($partial) { |
451 |
if (is_string($partial)) { |
452 |
$year = drupal_substr($partial, 0, 4); |
453 |
if (preg_match("/[0-9][0-9][0-9][0-9]/", $year)) { |
454 |
return $year; |
455 |
} |
456 |
} |
457 |
return ''; |
458 |
} |
459 |
|
460 |
/** |
461 |
* Converts an ISO 8601 org.joda.time.Partial to a month. |
462 |
* |
463 |
* This function expects an ISO 8601 time representation of a |
464 |
* org.joda.time.Partial of the form yyyy-MM-dd. |
465 |
* In case the month is unknown (= ???) NULL is returned. |
466 |
* |
467 |
* @param string $partial |
468 |
* ISO 8601 time representation of a org.joda.time.Partial. |
469 |
* |
470 |
* @return string |
471 |
* A month. |
472 |
*/ |
473 |
function partialToMonth($partial) { |
474 |
if (is_string($partial)) { |
475 |
$month = drupal_substr($partial, 5, 2); |
476 |
if (preg_match("/[0-9][0-9]/", $month)) { |
477 |
return $month; |
478 |
} |
479 |
} |
480 |
return ''; |
481 |
} |
482 |
|
483 |
/** |
484 |
* Converts an ISO 8601 org.joda.time.Partial to a day. |
485 |
* |
486 |
* This function expects an ISO 8601 time representation of a |
487 |
* org.joda.time.Partial of the form yyyy-MM-dd and returns the day as string. |
488 |
* In case the day is unknown (= ???) NULL is returned. |
489 |
* |
490 |
* @param string $partial |
491 |
* ISO 8601 time representation of a org.joda.time.Partial. |
492 |
* |
493 |
* @return string |
494 |
* A day. |
495 |
*/ |
496 |
function partialToDay($partial) { |
497 |
if (is_string($partial)) { |
498 |
$day = drupal_substr($partial, 8, 2); |
499 |
if (preg_match("/[0-9][0-9]/", $day)) { |
500 |
return $day; |
501 |
} |
502 |
} |
503 |
return ''; |
504 |
} |
505 |
|
506 |
/** |
507 |
* Converts an ISO 8601 org.joda.time.Partial to YYYY-MM-DD. |
508 |
* |
509 |
* This function expects an ISO 8601 time representations of a |
510 |
* org.joda.time.Partial of the form yyyy-MM-dd and returns |
511 |
* four digit year, month and day with dashes: |
512 |
* YYYY-MM-DD eg: "2012-06-30", "1956-00-00" |
513 |
* |
514 |
* The partial may contain question marks eg: "1973-??-??", |
515 |
* these are turned in to '00' or are stripped depending of the $stripZeros |
516 |
* parameter. |
517 |
* |
518 |
* @param string $partial |
519 |
* org.joda.time.Partial. |
520 |
* @param bool $stripZeros |
521 |
* If set to TRUE the zero (00) month and days will be hidden: |
522 |
* eg 1956-00-00 becomes 1956. The default is TRUE. |
523 |
* @param string @format |
524 |
* Can ve used to specify the format of the date string, currently the following format strings are supported |
525 |
* - "YYYY": Year only |
526 |
* - "YYYY-MM-DD": this is the default |
527 |
* |
528 |
* @return string |
529 |
* YYYY-MM-DD formatted year, month, day. |
530 |
*/ |
531 |
function partialToDate($partial, $stripZeros = TRUE, $format= "YYYY-MM-DD") { |
532 |
|
533 |
$y = NULL; $m = NULL; $d = NULL; |
534 |
|
535 |
if(strpos($format, 'YY') !== FALSE){ |
536 |
$y = partialToYear($partial); |
537 |
} |
538 |
if(strpos($format, 'MM') !== FALSE){ |
539 |
$m = partialToMonth($partial); |
540 |
} |
541 |
if(strpos($format, 'DD') !== FALSE){ |
542 |
$d = partialToDay($partial); |
543 |
} |
544 |
|
545 |
$y = $y ? $y : '0000'; |
546 |
$m = $m ? $m : '00'; |
547 |
$d = $d ? $d : '00'; |
548 |
|
549 |
$date = ''; |
550 |
|
551 |
if ($y == '0000' && $stripZeros && $m == '00' && $d == '00') { |
552 |
return ''; |
553 |
} |
554 |
else { |
555 |
$date = $y; |
556 |
} |
557 |
|
558 |
if ($m == '00' && $stripZeros && $d == '00') { |
559 |
return $date; |
560 |
} |
561 |
else { |
562 |
$date .= "-" . $m; |
563 |
} |
564 |
|
565 |
if ($d == '00' && $stripZeros) { |
566 |
return $date; |
567 |
} |
568 |
else { |
569 |
$date .= "-" . $d; |
570 |
} |
571 |
return $date; |
572 |
} |
573 |
|
574 |
/** |
575 |
* Converts a time period to a string. |
576 |
* |
577 |
* See also partialToDate($partial, $stripZeros). |
578 |
* |
579 |
* @param object $period |
580 |
* An JodaTime org.joda.time.Period object. |
581 |
* @param bool $stripZeros |
582 |
* If set to True, the zero (00) month and days will be hidden: |
583 |
* eg 1956-00-00 becomes 1956. The default is TRUE. |
584 |
* @param string @format |
585 |
* Can ve used to specify the format of the date string, currently the following format strings are supported |
586 |
* - "YYYY": Year only |
587 |
* - "YYYY-MM-DD": this is the default |
588 |
* |
589 |
* @return string |
590 |
* Returns a date in the form of a string. |
591 |
*/ |
592 |
function timePeriodToString($period, $stripZeros = TRUE, $format = "YYYY-MM-DD") { |
593 |
$dateString = ''; |
594 |
if($period->freeText){ |
595 |
$dateString = $period->freeText; |
596 |
} else { |
597 |
if ($period->start) { |
598 |
$dateString = partialToDate($period->start, $stripZeros, $format); |
599 |
} |
600 |
if ($period->end) { |
601 |
$end_str = partialToDate($period->end, $stripZeros, $format); |
602 |
$dateString .= ($dateString && $end_str ? ' ' . t('to') . ' ' : '') . $end_str; |
603 |
} |
604 |
} |
605 |
return $dateString; |
606 |
} |
607 |
|
608 |
/** |
609 |
* returns the earliest date available in the $period in a normalized |
610 |
* form suitable for sorting, e.g.: |
611 |
* |
612 |
* - 1956-00-00 |
613 |
* - 0000-00-00 |
614 |
* - 1957-03-00 |
615 |
* |
616 |
* that is either the start date is returned if set otherwise the |
617 |
* end date |
618 |
* |
619 |
* @param $period |
620 |
* An JodaTime org.joda.time.Period object. |
621 |
* @return string normalized form of the date |
622 |
* suitable for sorting |
623 |
*/ |
624 |
function timePeriodAsOrderKey($period) { |
625 |
$dateString = ''; |
626 |
if ($period->start) { |
627 |
$dateString = partialToDate($period->start, false); |
628 |
} |
629 |
if ($period->end) { |
630 |
$dateString .= partialToDate($period->end, false); |
631 |
} |
632 |
return $dateString; |
633 |
} |
634 |
|
635 |
/** |
636 |
* Composes a absolute CDM web service URI with parameters and querystring. |
637 |
* |
638 |
* @param string $uri_pattern |
639 |
* String with place holders ($0, $1, ..) that should be replaced by the |
640 |
* according element of the $pathParameters array. |
641 |
* @param array $pathParameters |
642 |
* An array of path elements, or a single element. |
643 |
* @param string $query |
644 |
* A query string to append to the URL. |
645 |
* |
646 |
* @return string |
647 |
* A complete URL with parameters to a CDM webservice. |
648 |
*/ |
649 |
function cdm_compose_url($uri_pattern, $pathParameters = array(), $query = NULL) { |
650 |
if (empty($pathParameters)) { |
651 |
$pathParameters = array(); |
652 |
} |
653 |
|
654 |
// (1) |
655 |
// Substitute all place holders ($0, $1, ..) in the $uri_pattern by the |
656 |
// according element of the $pathParameters array. |
657 |
static $helperArray = array(); |
658 |
if (isset($pathParameters) && !is_array($pathParameters)) { |
659 |
$helperArray[0] = $pathParameters; |
660 |
$pathParameters = $helperArray; |
661 |
} |
662 |
|
663 |
$i = 0; |
664 |
while (strpos($uri_pattern, "$" . $i) !== FALSE) { |
665 |
if (count($pathParameters) <= $i) { |
666 |
drupal_set_message( |
667 |
t('cdm_compose_url(): missing pathParameter @index for !uri_pattern', |
668 |
array('@index' => $i, '!uri_pattern' => $uri_pattern )), |
669 |
'error'); |
670 |
break; |
671 |
} |
672 |
$uri_pattern = str_replace("$" . $i, rawurlencode($pathParameters[$i]), $uri_pattern); |
673 |
++$i; |
674 |
} |
675 |
|
676 |
// (2) |
677 |
// Append all remaining element of the $pathParameters array as path |
678 |
// elements. |
679 |
if (count($pathParameters) > $i) { |
680 |
// Strip trailing slashes. |
681 |
if (strrchr($uri_pattern, '/') == strlen($uri_pattern)) { |
682 |
$uri_pattern = substr($uri_pattern, 0, strlen($uri_pattern) - 1); |
683 |
} |
684 |
while (count($pathParameters) > $i) { |
685 |
$uri_pattern .= '/' . rawurlencode($pathParameters[$i]); |
686 |
++$i; |
687 |
} |
688 |
} |
689 |
|
690 |
// (3) |
691 |
// Append the query string supplied by $query. |
692 |
if (isset($query)) { |
693 |
$uri_pattern .= (strpos($uri_pattern, '?') !== FALSE ? '&' : '?') . $query; |
694 |
} |
695 |
|
696 |
$path = $uri_pattern; |
697 |
|
698 |
$uri = variable_get('cdm_webservice_url', '') . $path; |
699 |
return $uri; |
700 |
} |
701 |
|
702 |
/** |
703 |
* @todo wouldn't it more elegant and secure to only pass a uuid and additional function parameters |
704 |
* together with a theme name to such a proxy function? |
705 |
* Well this would not be covering all use cases but maybe all which involve AHAH. |
706 |
* Maybe we want to have two different proxy functions, one with theming and one without? |
707 |
* |
708 |
* @param string $uri |
709 |
* A URI to a CDM Rest service from which to retrieve an object |
710 |
* @param string|null $hook |
711 |
* (optional) The hook name to which the retrieved object should be passed. |
712 |
* Hooks can either be a theme_hook() or compose_hook() implementation |
713 |
* 'theme' hook functions return a string whereas 'compose' hooks are returning render arrays |
714 |
* suitable for drupal_render() |
715 |
* |
716 |
* @todo Please document this function. |
717 |
* @see http://drupal.org/node/1354 |
718 |
*/ |
719 |
function proxy_content($uri, $hook = NULL) { |
720 |
|
721 |
$args = func_get_args(); |
722 |
$do_gzip = function_exists('gzencode'); |
723 |
$uriEncoded = array_shift($args); |
724 |
$uri = urldecode($uriEncoded); |
725 |
$hook = array_shift($args); |
726 |
$request_method = strtoupper($_SERVER["REQUEST_METHOD"]); |
727 |
|
728 |
$post_data = null; |
729 |
|
730 |
if ($request_method == "POST" || $request_method == "PUT") { |
731 |
// read response body via inputstream module |
732 |
$post_data = file_get_contents("php://input"); |
733 |
} |
734 |
|
735 |
// Find and deserialize arrays. |
736 |
foreach ($args as &$arg) { |
737 |
// FIXME use regex to find serialized arrays. |
738 |
// or should we accept json instead of php serializations? |
739 |
if (strpos($arg, "a:") === 0) { |
740 |
$arg = unserialize($arg); |
741 |
} |
742 |
} |
743 |
|
744 |
// In all these cases perform a simple get request. |
745 |
// TODO reconsider caching logic in this function. |
746 |
|
747 |
if (empty($hook)) { |
748 |
// simply return the webservice response |
749 |
// Print out JSON, the cache cannot be used since it contains objects. |
750 |
$http_response = cdm_http_request($uri, $request_method, $post_data); |
751 |
if (isset($http_response->headers)) { |
752 |
foreach ($http_response->headers as $hname => $hvalue) { |
753 |
drupal_add_http_header($hname, $hvalue); |
754 |
} |
755 |
} |
756 |
if (isset($http_response->data)) { |
757 |
print $http_response->data; |
758 |
flush(); |
759 |
} |
760 |
exit(); // leave drupal here |
761 |
} else { |
762 |
// $hook has been supplied |
763 |
// handle $hook either as compose or theme hook |
764 |
// pass through theme or compose hook |
765 |
// compose hooks can be called without data, therefore |
766 |
// passing the $uri in this case is not always a requirement |
767 |
|
768 |
if($uri && $uri != 'NULL') { |
769 |
// do a security check since the $uri will be passed |
770 |
// as absolute URI to cdm_ws_get() |
771 |
if (!_is_cdm_ws_uri($uri)) { |
772 |
drupal_set_message( |
773 |
'Invalid call of proxy_content() with callback parameter \'' . $hook . '\' and URI:' . $uri, |
774 |
'error' |
775 |
); |
776 |
return ''; |
777 |
} |
778 |
|
779 |
$obj = cdm_ws_get($uri, NULL, $post_data, $request_method, TRUE); |
780 |
} else { |
781 |
$obj = NULL; |
782 |
} |
783 |
|
784 |
$reponse_data = NULL; |
785 |
|
786 |
if (function_exists('compose_' . $hook)){ |
787 |
// call compose hook |
788 |
|
789 |
$elements = call_user_func('compose_' . $hook, $obj); |
790 |
// pass the render array to drupal_render() |
791 |
$reponse_data = drupal_render($elements); |
792 |
} else { |
793 |
// call theme hook |
794 |
|
795 |
// TODO use theme registry to get the registered hook info and |
796 |
// use these defaults |
797 |
switch($hook) { |
798 |
case 'cdm_taxontree': |
799 |
$variables = array( |
800 |
'tree' => $obj, |
801 |
'filterIncludes' => isset($args[0]) ? $args[0] : NULL, |
802 |
'show_filter_switch' => isset($args[1]) ? $args[1] : FALSE, |
803 |
'tree_node_callback' => isset($args[2]) ? $args[2] : FALSE, |
804 |
'element_name'=> isset($args[3]) ? $args[3] : FALSE, |
805 |
); |
806 |
$reponse_data = theme($hook, $variables); |
807 |
break; |
808 |
|
809 |
case 'cdm_list_of_taxa': |
810 |
$variables = array( |
811 |
'records' => $obj, |
812 |
'freetextSearchResults' => isset($args[0]) ? $args[0] : array(), |
813 |
'show_classification' => isset($args[1]) ? $args[1] : FALSE); |
814 |
$reponse_data = theme($hook, $variables); |
815 |
break; |
816 |
|
817 |
case 'cdm_media_caption': |
818 |
$variables = $arg; |
819 |
$variables['media'] = $obj; |
820 |
|
821 |
$reponse_data = theme($hook, $variables); |
822 |
break; |
823 |
|
824 |
default: |
825 |
drupal_set_message(t( |
826 |
'Theme !theme is not yet supported by the function !function.', array( |
827 |
'!theme' => $hook, |
828 |
'!function' => __FUNCTION__, |
829 |
)), 'error'); |
830 |
break; |
831 |
} // END of theme hook switch |
832 |
} // END of tread as theme hook |
833 |
|
834 |
|
835 |
if($do_gzip){ |
836 |
$reponse_data = gzencode($reponse_data, 2, FORCE_GZIP); |
837 |
drupal_add_http_header('Content-Encoding', 'gzip'); |
838 |
} |
839 |
drupal_add_http_header('Content-Type', 'text/html; charset=utf-8'); |
840 |
drupal_add_http_header('Content-Length', strlen($reponse_data)); |
841 |
|
842 |
print $reponse_data; |
843 |
} // END of handle $hook either as compose ot theme hook |
844 |
|
845 |
} |
846 |
|
847 |
/** |
848 |
* @todo Please document this function. |
849 |
* @see http://drupal.org/node/1354 |
850 |
*/ |
851 |
function setvalue_session() { |
852 |
if ($_REQUEST['var'] && strlen($_REQUEST['var']) > 4) { |
853 |
$var_keys = substr($_REQUEST['var'], 1, strlen($_REQUEST['var']) - 2); |
854 |
$var_keys = explode('][', $var_keys); |
855 |
} |
856 |
else { |
857 |
return; |
858 |
} |
859 |
$val = isset($_REQUEST['val']) ? $_REQUEST['val'] : NULL; |
860 |
|
861 |
// Prevent from malicous tags. |
862 |
$val = strip_tags($val); |
863 |
|
864 |
$session_var = &$_SESSION; |
865 |
//$i = 0; |
866 |
foreach ($var_keys as $key) { |
867 |
// $hasMoreKeys = ++$i < count($session); |
868 |
if (!isset($session_var[$key]) || !is_array($session_var[$key])) { |
869 |
$session_var[$key] = array(); |
870 |
} |
871 |
$session_var = &$session_var[$key]; |
872 |
} |
873 |
$session_var = $val; |
874 |
if (isset($_REQUEST['destination'])) { |
875 |
drupal_goto($_REQUEST['destination']); |
876 |
} |
877 |
} |
878 |
|
879 |
/** |
880 |
* @todo Please document this function. |
881 |
* @see http://drupal.org/node/1354 |
882 |
*/ |
883 |
function uri_uriByProxy($uri, $theme = FALSE) { |
884 |
// usage: url('cdm_api/proxy/'.urlencode($content_url)."/$theme");) |
885 |
return url('cdm_api/proxy/' . urlencode($uri) . (isset($theme) ? "/$theme" : '')); |
886 |
} |
887 |
|
888 |
/** |
889 |
* Composes the the absolute REST service URI to the annotations pager |
890 |
* for the given CDM entity. |
891 |
* |
892 |
* NOTE: Not all CDM Base types are yet supported. |
893 |
* |
894 |
* @param $cdmBase |
895 |
* The CDM entity to construct the annotations pager uri for |
896 |
*/ |
897 |
function cdm_compose_annotations_uri($cdmBase) { |
898 |
|
899 |
if (!$cdmBase->uuid) { |
900 |
return; |
901 |
} |
902 |
|
903 |
$ws_base_uri = cdm_ws_base_uri($cdmBase->class); |
904 |
|
905 |
if($ws_base_uri === null){ |
906 |
trigger_error(check_plain('Unsupported CDM Class - no annotations available for ' . $cdmBase->class), E_USER_ERROR); |
907 |
} |
908 |
return cdm_compose_url($ws_base_uri, array( |
909 |
$cdmBase->uuid, |
910 |
'annotations', |
911 |
)); |
912 |
} |
913 |
|
914 |
/** |
915 |
* Provides the base URI of the cdm REST service responsible for the passed simple name |
916 |
* of a CDM java class. For example 'TaxonName' is the simple name of 'eu.etaxonomy.cdm.model.name.TaxonName' |
917 |
* |
918 |
* @param $cdm_type_simple |
919 |
* simple name of a CDM java class |
920 |
* @return null|string |
921 |
*/ |
922 |
function cdm_ws_base_uri($cdm_type_simple) |
923 |
{ |
924 |
$ws_base_uri = NULL; |
925 |
switch ($cdm_type_simple) { |
926 |
|
927 |
case 'TaxonNode': |
928 |
case 'TaxonNodeDto': |
929 |
$ws_base_uri = CDM_WS_TAXONNODE; |
930 |
case 'TaxonBase': |
931 |
case 'Taxon': |
932 |
case 'Synonym': |
933 |
$ws_base_uri = CDM_WS_TAXON; |
934 |
break; |
935 |
|
936 |
case 'TaxonName': |
937 |
$ws_base_uri = CDM_WS_NAME; |
938 |
break; |
939 |
|
940 |
case 'Media': |
941 |
$ws_base_uri = CDM_WS_MEDIA; |
942 |
break; |
943 |
|
944 |
case 'Reference': |
945 |
$ws_base_uri = CDM_WS_REFERENCE; |
946 |
break; |
947 |
|
948 |
case 'Registration': |
949 |
$ws_base_uri = CDM_WS_REFERENCE; |
950 |
break; |
951 |
|
952 |
case 'FieldUnit': |
953 |
case 'DerivedUnit': |
954 |
case 'DnaSample': |
955 |
case 'MediaSpecimen': |
956 |
$ws_base_uri = CDM_WS_OCCURRENCE; |
957 |
break; |
958 |
|
959 |
case 'Amplification': |
960 |
case 'DerivationEvent': |
961 |
case 'DeterminationEvent': |
962 |
case 'GatheringEvent': |
963 |
case 'MaterialOrMethodEvent': |
964 |
case 'SingleRead': |
965 |
$ws_base_uri = CDM_WS_EVENTBASE; |
966 |
break; |
967 |
|
968 |
case 'Distribution': |
969 |
case 'TextData': |
970 |
case 'TaxonInteraction': |
971 |
case 'QuantitativeData': |
972 |
case 'IndividualsAssociation': |
973 |
case 'CommonTaxonName': |
974 |
case 'CategoricalData': |
975 |
$ws_base_uri = CDM_WS_DESCRIPTIONELEMENT; |
976 |
break; |
977 |
|
978 |
case 'Person': |
979 |
case 'Team': |
980 |
case 'AgentBase': |
981 |
$ws_base_uri = CDM_WS_AGENT; |
982 |
break; |
983 |
|
984 |
case 'PolytomousKey': |
985 |
case 'MediaKey': |
986 |
case 'MultiAccessKey': |
987 |
$ws_base_uri = $cdm_type_simple; |
988 |
$ws_base_uri{0} = strtolower($ws_base_uri{0}); |
989 |
break; |
990 |
|
991 |
case 'TextualTypeDesignation': |
992 |
case 'SpecimenTypeDesignation': |
993 |
case 'NameTypeDesignation': |
994 |
$ws_base_uri = CDM_WS_TYPEDESIGNATION; |
995 |
break; |
996 |
default: |
997 |
$ws_base_uri = null; |
998 |
drupal_set_message( |
999 |
t('cdm_ws_base_uri() - cdm type name "@cdm_type_simple" unsupported', |
1000 |
array('@cdm_type_simple' => $cdm_type_simple )), |
1001 |
'error'); |
1002 |
} |
1003 |
return $ws_base_uri; |
1004 |
} |
1005 |
|
1006 |
/** |
1007 |
* Enter description here... |
1008 |
* |
1009 |
* @param string $resource_uri |
1010 |
* @param int $page_size |
1011 |
* The maximum number of entities returned per page. |
1012 |
* The default page size as configured in the cdm server |
1013 |
* will be used if set to NULL |
1014 |
* to return all entities in a single page). |
1015 |
* @param int $page_index |
1016 |
* The number of the page to be returned, the first page has the |
1017 |
* page_index = 0 |
1018 |
* @param array $query |
1019 |
* A array holding the HTTP request query parameters for the request |
1020 |
* @param string $method |
1021 |
* The HTTP method to use, valid values are "GET" or "POST" |
1022 |
* @param bool $absolute_uri |
1023 |
* TRUE when the URL should be treated as absolute URL. |
1024 |
* |
1025 |
* @return object |
1026 |
* A CDM Pager object |
1027 |
* |
1028 |
*/ |
1029 |
function cdm_ws_page($resource_uri, $page_size, $page_index, array $query = array(), $method = 'GET', $absolute_uri = FALSE) { |
1030 |
|
1031 |
$query['page_index'] = $page_index; |
1032 |
$query['page_size'] = $page_size; |
1033 |
|
1034 |
$pager = cdm_ws_get($resource_uri, NULL, queryString($query), $method, $absolute_uri); |
1035 |
if(is_array($pager)){ |
1036 |
trigger_error("Expecting web service to return pager objects but received an array:<br/>" . $resource_uri . '?' . queryString($query) . '<br/>Wrapping response in pager to recover from error.', E_USER_WARNING); |
1037 |
$records = $pager; |
1038 |
$pager = new stdClass(); |
1039 |
$pager->records = $records; |
1040 |
$pager->count = count($records); |
1041 |
$pager->pageSize = $pager->count; |
1042 |
$pager->nextIndex = null; |
1043 |
} |
1044 |
return $pager; |
1045 |
} |
1046 |
|
1047 |
|
1048 |
/** |
1049 |
* Sends a http GET request to the generic page method which allows for filtering entities by Restrictions. |
1050 |
* |
1051 |
* @param $cdm_entity_type |
1052 |
* @param $class_restriction |
1053 |
* Optional param to narrow down polymorph types to a specific type. |
1054 |
* @param array $restrictions |
1055 |
* An array of Restriction objects |
1056 |
* @param array $init_strategy |
1057 |
* The init strategy to initialize the entity beans while being loaded from the |
1058 |
* persistent storage by the cdm |
1059 |
* @param int $page_size |
1060 |
* The maximum number of entities returned per page. |
1061 |
* The default page size as configured in the cdm server |
1062 |
* will be used if set to NULL |
1063 |
* to return all entities in a single page). |
1064 |
* @param int $page_index |
1065 |
* The number of the page to be returned, the first page has the |
1066 |
* pageNumber = 0 |
1067 |
* |
1068 |
* @return object |
1069 |
* A CDM Pager object |
1070 |
*/ |
1071 |
function cdm_ws_page_by_restriction($cdm_entity_type, $class_restriction, array $restrictions, array $init_strategy, $page_size, $page_index) { |
1072 |
|
1073 |
$restrictions_json = array(); // json_encode($restrictions); |
1074 |
foreach ($restrictions as $restr){ |
1075 |
$restrictions_json[] = json_encode($restr); |
1076 |
} |
1077 |
$filter_parameters = [ |
1078 |
'restriction' => $restrictions_json, |
1079 |
'initStrategy' => $init_strategy |
1080 |
]; |
1081 |
if($class_restriction){ |
1082 |
$filter_parameters['class'] = $class_restriction; |
1083 |
} |
1084 |
|
1085 |
return cdm_ws_page( |
1086 |
'portal/' . cdm_ws_base_uri($cdm_entity_type), |
1087 |
$page_size, |
1088 |
$page_index, |
1089 |
$filter_parameters, |
1090 |
"GET" |
1091 |
); |
1092 |
} |
1093 |
|
1094 |
/** |
1095 |
* Fetches all entities returned by the the generic page method for the Restrictions applied as filter. |
1096 |
* |
1097 |
* @param $cdm_entity_type |
1098 |
* @param $class_restriction |
1099 |
* Optional param to narrow down polymorph types to a specific type. |
1100 |
* @param array $restrictions |
1101 |
* An array of Restriction objects |
1102 |
* @param array $init_strategy |
1103 |
* The init strategy to initialize the entity beans while being loaded from the |
1104 |
* persistent storage by the cdm |
1105 |
* |
1106 |
* @return array |
1107 |
* A array of CDM entities |
1108 |
*/ |
1109 |
function cdm_ws_fetch_all_by_restriction($cdm_entity_type, $class_restriction, array $restrictions, array $init_strategy){ |
1110 |
$page_index = 0; |
1111 |
// using a bigger page size to avoid to many multiple requests |
1112 |
$page_size = 500; |
1113 |
$entities = array(); |
1114 |
|
1115 |
while ($page_index !== FALSE && $page_index < 1){ |
1116 |
$pager = cdm_ws_page_by_restriction($cdm_entity_type, $class_restriction, $restrictions, $init_strategy, $page_size, $page_index); |
1117 |
if(isset($pager->records) && is_array($pager->records)) { |
1118 |
$entities = array_merge($entities, $pager->records); |
1119 |
if(!empty($pager->nextIndex)){ |
1120 |
$page_index = $pager->nextIndex; |
1121 |
} else { |
1122 |
$page_index = FALSE; |
1123 |
} |
1124 |
} else { |
1125 |
$page_index = FALSE; |
1126 |
} |
1127 |
} |
1128 |
return $entities; |
1129 |
} |
1130 |
|
1131 |
|
1132 |
/** |
1133 |
* Fetches all entities from the given REST endpoint using the pager mechanism. |
1134 |
* |
1135 |
* @param string $resourceURI |
1136 |
* @param array $query |
1137 |
* A array holding the HTTP request query parameters for the request |
1138 |
* @param string $method |
1139 |
* The HTTP method to use, valid values are "GET" or "POST"; |
1140 |
* @param bool $absoluteURI |
1141 |
* TRUE when the URL should be treated as absolute URL. |
1142 |
* |
1143 |
* @return array |
1144 |
* A list of CDM entitites |
1145 |
* |
1146 |
*/ |
1147 |
function cdm_ws_fetch_all($resourceURI, array $query = array(), $method = 'GET', $absoluteURI = FALSE) { |
1148 |
$page_index = 0; |
1149 |
// using a bigger page size to avoid to many multiple requests |
1150 |
$page_size = 500; |
1151 |
$entities = array(); |
1152 |
|
1153 |
while ($page_index !== FALSE){ |
1154 |
$pager = cdm_ws_page($resourceURI, $page_size, $page_index, $query, $method, $absoluteURI); |
1155 |
if(isset($pager->records) && is_array($pager->records)) { |
1156 |
$entities = array_merge($entities, $pager->records); |
1157 |
if(!empty($pager->nextIndex)){ |
1158 |
$page_index = $pager->nextIndex; |
1159 |
} else { |
1160 |
$page_index = FALSE; |
1161 |
} |
1162 |
} else { |
1163 |
$page_index = FALSE; |
1164 |
} |
1165 |
} |
1166 |
return $entities; |
1167 |
} |
1168 |
|
1169 |
/* |
1170 |
function cdm_ws_taxonomy_compose_resourcePath($path = NULL){ |
1171 |
$viewrank = _cdm_taxonomy_compose_viewrank(); |
1172 |
return CDM_WS_PORTAL_TAXONOMY . '/' . ($viewrank ? $viewrank : '' ) . ($path |
1173 |
? '/' . $path : '') ; |
1174 |
} |
1175 |
*/ |
1176 |
|
1177 |
/** |
1178 |
* @todo Enter description here... |
1179 |
* |
1180 |
* @param string $taxon_uuid |
1181 |
* The UUID of a cdm taxon instance |
1182 |
* @param string $ignore_rank_limit |
1183 |
* Whether to ignore the variable 'taxontree_ranklimit' set by admin in the settings |
1184 |
* |
1185 |
* @return string |
1186 |
* A cdm REST service URL path to a Classification |
1187 |
*/ |
1188 |
function cdm_compose_taxonomy_root_level_path($taxon_uuid = FALSE, $ignore_rank_limit = FALSE) { |
1189 |
|
1190 |
$view_uuid = get_current_classification_uuid(); |
1191 |
$rank_uuid = NULL; |
1192 |
if (!$ignore_rank_limit) { |
1193 |
$rank_uuid = variable_get(TAXONTREE_RANKLIMIT, TAXONTREE_RANKLIMIT_DEFAULT); |
1194 |
} |
1195 |
|
1196 |
if (!empty($taxon_uuid)) { |
1197 |
return cdm_compose_url(CDM_WS_PORTAL_TAXONOMY_CHILDNODES_OF_TAXON, array( |
1198 |
$view_uuid, |
1199 |
$taxon_uuid, |
1200 |
)); |
1201 |
} |
1202 |
else { |
1203 |
if (is_uuid($rank_uuid)) { |
1204 |
return cdm_compose_url(CDM_WS_PORTAL_TAXONOMY_CHILDNODES_AT_RANK, array( |
1205 |
$view_uuid, |
1206 |
$rank_uuid, |
1207 |
)); |
1208 |
} |
1209 |
else { |
1210 |
return cdm_compose_url(CDM_WS_PORTAL_TAXONOMY_CHILDNODES, array( |
1211 |
$view_uuid, |
1212 |
)); |
1213 |
} |
1214 |
} |
1215 |
} |
1216 |
|
1217 |
/** |
1218 |
* Retrieves from the cdm web service with the first level of childnodes of a classification. |
1219 |
* |
1220 |
* The level is either the real root level ot it is a lover level if a rank limit has been set. |
1221 |
* (@see cdm_compose_taxonomy_root_level_path() for more on the rank limit). |
1222 |
* |
1223 |
* Operates in two modes depending on whether the parameter |
1224 |
* $taxon_uuid is set or NULL. |
1225 |
* |
1226 |
* A) $taxon_uuid = NULL: |
1227 |
* 1. retrieve the Classification for the uuid set in the $_SESSION['cdm']['taxonomictree_uuid'] |
1228 |
* 2. otherwise return the default classification as defined by the admin via the settings |
1229 |
* |
1230 |
* b) $taxon_uuid is set: |
1231 |
* return the classification to whcih the taxon belongs to. |
1232 |
* |
1233 |
* @param UUID $taxon_uuid |
1234 |
* The UUID of a cdm taxon instance |
1235 |
*/ |
1236 |
function cdm_ws_taxonomy_root_level($taxon_uuid = NULL) { |
1237 |
|
1238 |
$response = NULL; |
1239 |
|
1240 |
// 1st try |
1241 |
$response = cdm_ws_get(cdm_compose_taxonomy_root_level_path($taxon_uuid), NULL, NULL, 'GET', TRUE); |
1242 |
|
1243 |
if ($response == NULL) { |
1244 |
// 2dn try by ignoring the rank limit |
1245 |
$response = cdm_ws_get(cdm_compose_taxonomy_root_level_path($taxon_uuid, TRUE), NULL, NULL, 'GET', TRUE); |
1246 |
} |
1247 |
|
1248 |
if ($response == NULL) { |
1249 |
// 3rd try, last fallback: |
1250 |
// return the default classification |
1251 |
if (isset($_SESSION['cdm']['taxonomictree_uuid']) && is_uuid($_SESSION['cdm']['taxonomictree_uuid'])) { |
1252 |
// Delete the session value and try again with the default. |
1253 |
unset($_SESSION['cdm']['taxonomictree_uuid']); |
1254 |
drupal_set_message("Could not find a valid classification, falling back to the default classification.", 'warning'); |
1255 |
return cdm_ws_taxonomy_root_level($taxon_uuid); |
1256 |
} |
1257 |
else { |
1258 |
// Check if taxonomictree_uuid is valid. |
1259 |
// expecting an array of taxonNodes, |
1260 |
// empty classifications are ok so no warning in this case! |
1261 |
$test = cdm_ws_get(cdm_compose_taxonomy_root_level_path(), NULL, NULL, 'GET', TRUE); |
1262 |
if (!is_array($test)) { |
1263 |
// The default set by the admin seems to be invalid or is not even set. |
1264 |
drupal_set_message(_no_classfication_uuid_message(), 'warning'); |
1265 |
} |
1266 |
if (count($test) == 0) { |
1267 |
// The default set by the admin seems to be invalid or is not even set. |
1268 |
drupal_set_message("The chosen classification is empty.", 'status'); |
1269 |
} |
1270 |
} |
1271 |
} |
1272 |
|
1273 |
return $response; |
1274 |
} |
1275 |
|
1276 |
/** |
1277 |
* Determines the tree path of the taxon given as uuid to the root of the classification tree. |
1278 |
* |
1279 |
* The root either is the absolute root of the tree or a rank specific root if the TAXONTREE_RANKLIMIT |
1280 |
* variable is set. |
1281 |
* |
1282 |
* @param string $taxon_uuid |
1283 |
* |
1284 |
* @return array |
1285 |
* An array of CDM TaxonNodeDTO objects |
1286 |
*/ |
1287 |
function cdm_ws_taxonomy_pathFromRoot($taxon_uuid) { |
1288 |
$view_uuid = get_current_classification_uuid(); |
1289 |
$rank_uuid = variable_get(TAXONTREE_RANKLIMIT, TAXONTREE_RANKLIMIT_DEFAULT); |
1290 |
|
1291 |
$response = NULL; |
1292 |
if (is_uuid($rank_uuid)) { |
1293 |
$response = cdm_ws_get(CDM_WS_PORTAL_TAXONOMY_PATH_FROM_TO_RANK, array( |
1294 |
$view_uuid, |
1295 |
$taxon_uuid, |
1296 |
$rank_uuid, |
1297 |
)); |
1298 |
} |
1299 |
else { |
1300 |
$response = cdm_ws_get(CDM_WS_PORTAL_TAXONOMY_PATH_FROM, array( |
1301 |
$view_uuid, |
1302 |
$taxon_uuid, |
1303 |
)); |
1304 |
} |
1305 |
|
1306 |
if ($response == NULL) { |
1307 |
// Error handing. |
1308 |
// if (is_uuid($_SESSION['cdm']['taxonomictree_uuid'])) { |
1309 |
// // Delete the session value and try again with the default. |
1310 |
// unset($_SESSION['cdm']['taxonomictree_uuid']); |
1311 |
// return cdm_ws_taxonomy_pathFromRoot($taxon_uuid); |
1312 |
// } |
1313 |
// else { |
1314 |
// Check if taxonomictree_uuid is valid. |
1315 |
$test = cdm_ws_get(cdm_compose_taxonomy_root_level_path(), NULL, NULL, 'GET', TRUE); |
1316 |
if ($test == NULL) { |
1317 |
// The default set by the admin seems to be invalid or is not even set. |
1318 |
drupal_set_message(_no_classfication_uuid_message(), 'warning'); |
1319 |
} |
1320 |
// } |
1321 |
} |
1322 |
|
1323 |
return $response; |
1324 |
} |
1325 |
|
1326 |
|
1327 |
// =============================Terms and Vocabularies ========================================= // |
1328 |
|
1329 |
/** |
1330 |
* Returns the localized representation for the given term. |
1331 |
* |
1332 |
* @param Object $definedTermBase |
1333 |
* of cdm type DefinedTermBase |
1334 |
* @return string |
1335 |
* the localized representation_L10n of the term, |
1336 |
* otherwise the titleCache as fall back, |
1337 |
* otherwise the default_representation which defaults to an empty string |
1338 |
*/ |
1339 |
function cdm_term_representation($definedTermBase, $default_representation = '') { |
1340 |
if ( isset($definedTermBase->representation_L10n) ) { |
1341 |
return $definedTermBase->representation_L10n; |
1342 |
} elseif ( isset($definedTermBase->titleCache)) { |
1343 |
return $definedTermBase->titleCache; |
1344 |
} |
1345 |
return $default_representation; |
1346 |
} |
1347 |
|
1348 |
/** |
1349 |
* Returns the abbreviated localized representation for the given term. |
1350 |
* |
1351 |
* @param Object $definedTermBase |
1352 |
* of cdm type DefinedTermBase |
1353 |
* @return string |
1354 |
* the localized representation_L10n_abbreviatedLabel of the term, |
1355 |
* if this representation is not available the function delegates the |
1356 |
* call to cdm_term_representation() |
1357 |
*/ |
1358 |
function cdm_term_representation_abbreviated($definedTermBase, $default_representation = '') { |
1359 |
if ( isset($definedTermBase->representation_L10n_abbreviatedLabel) ) { |
1360 |
return $definedTermBase->representation_L10n_abbreviatedLabel; |
1361 |
} else { |
1362 |
cdm_term_representation($definedTermBase, $default_representation); |
1363 |
} |
1364 |
} |
1365 |
|
1366 |
/** |
1367 |
* Transforms the list of the given term base instances to a alphabetical ordered options array. |
1368 |
* |
1369 |
* The options array is suitable for drupal form API elements that allow multiple choices. |
1370 |
* @see http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#options |
1371 |
* |
1372 |
* @param array $terms |
1373 |
* a list of CDM DefinedTermBase instances |
1374 |
* |
1375 |
* @param $term_label_callback |
1376 |
* A callback function to override the term representations |
1377 |
* |
1378 |
* @param bool $empty_option |
1379 |
* An additional element do be placed at the beginning og the list. This element will be the default option. |
1380 |
* |
1381 |
* @return array |
1382 |
* the terms in an array (key: uuid => value: label) as options for a form element that allows multiple choices. |
1383 |
|
1384 |
*/ |
1385 |
function cdm_terms_as_options($terms, $term_label_callback = NULL, $empty_option = FALSE){ |
1386 |
$options = array(); |
1387 |
if(isset($terms) && is_array($terms)) { |
1388 |
foreach ($terms as $term) { |
1389 |
if ($term_label_callback && function_exists($term_label_callback)) { |
1390 |
$options[$term->uuid] = call_user_func($term_label_callback, $term); |
1391 |
} else { |
1392 |
//TODO use cdm_term_representation() here? |
1393 |
$options[$term->uuid] = t('@term', array('@term' => $term->representation_L10n)); |
1394 |
} |
1395 |
} |
1396 |
} |
1397 |
|
1398 |
if($empty_option !== FALSE){ |
1399 |
array_unshift ($options, ""); |
1400 |
} |
1401 |
|
1402 |
return $options; |
1403 |
} |
1404 |
|
1405 |
/** |
1406 |
* Creates and array of options for drupal select form elements. |
1407 |
* |
1408 |
* @param $vocabulary_uuid |
1409 |
* The UUID of the CDM Term Vocabulary |
1410 |
* @param $term_label_callback |
1411 |
* An optional call back function which can be used to modify the term label |
1412 |
* @param bool $empty_option |
1413 |
* An additional element do be placed at the beginning og the list. This element will be the default option. |
1414 |
* @param array $include_filter |
1415 |
* An associative array consisting of a field name an regular expression. All term matching |
1416 |
* these filter are included. The value of the field is converted to a String by var_export() |
1417 |
* so a boolean 'true' can be matched by '/true/' |
1418 |
* @param string $order_by |
1419 |
* One of the order by constants defined in this file |
1420 |
* @return array |
1421 |
* the terms in an array (key: uuid => value: label) as options for a form element that allows multiple choices. |
1422 |
*/ |
1423 |
function cdm_vocabulary_as_option($vocabulary_uuid, $term_label_callback = NULL, $empty_option = FALSE, |
1424 |
array $include_filter = null, $order_by = CDM_ORDER_BY_ORDER_INDEX_ASC) { |
1425 |
|
1426 |
static $vocabularyOptions = array(); |
1427 |
|
1428 |
if (!isset($vocabularyOptions[$vocabulary_uuid])) { |
1429 |
$terms = cdm_ws_fetch_all('termVocabulary/' . $vocabulary_uuid . '/terms', |
1430 |
array( |
1431 |
'orderBy' => $order_by |
1432 |
) |
1433 |
); |
1434 |
|
1435 |
// apply the include filter |
1436 |
if($include_filter != null){ |
1437 |
$included_terms = array(); |
1438 |
|
1439 |
foreach ($terms as $term){ |
1440 |
$include = true; |
1441 |
foreach ($include_filter as $field=>$regex){ |
1442 |
$include = preg_match($regex, var_export($term->$field, true)) === 1; |
1443 |
if(!$include){ |
1444 |
break; |
1445 |
} |
1446 |
} |
1447 |
if($include){ |
1448 |
$included_terms[] = $term; |
1449 |
} |
1450 |
} |
1451 |
|
1452 |
$terms = $included_terms; |
1453 |
} |
1454 |
|
1455 |
// make options list |
1456 |
$vocabularyOptions[$vocabulary_uuid] = cdm_terms_as_options($terms, $term_label_callback, $empty_option); |
1457 |
} |
1458 |
|
1459 |
$options = $vocabularyOptions[$vocabulary_uuid]; |
1460 |
|
1461 |
return $options; |
1462 |
} |
1463 |
|
1464 |
/** |
1465 |
* Creates and array of defaults for drupal select form elements. |
1466 |
* |
1467 |
* @param $vocabulary_uuid |
1468 |
* The UUID of the CDM Term Vocabulary |
1469 |
* @param $term_label_callback |
1470 |
* An optional call back function which can be used to modify the term label |
1471 |
* @param bool $empty_option |
1472 |
* An additional element do be placed at the beginning og the list. This element will be the default option. |
1473 |
* @param array $include_filter |
1474 |
* An associative array consisting of a field name an regular expression. All term matching |
1475 |
* these filter are included. The value of the field is converted to a String by var_export() |
1476 |
* so a boolean 'true' can be matched by '/true/' |
1477 |
* @param string $order_by |
1478 |
* One of the order by constants defined in this file |
1479 |
* @return array |
1480 |
* the terms in an array (key: uuid => value: uuid) as defaults for a form element that allows multiple choices. |
1481 |
*/ |
1482 |
function cdm_vocabulary_as_defaults($vocabulary_uuid, array $include_filter = null) { |
1483 |
|
1484 |
$options = cdm_vocabulary_as_option($vocabulary_uuid, null, null, $include_filter); |
1485 |
$defaults = array(); |
1486 |
foreach ($options as $uuid => $value){ |
1487 |
$defaults[$uuid] = $uuid; |
1488 |
} |
1489 |
|
1490 |
return $defaults; |
1491 |
} |
1492 |
|
1493 |
/** |
1494 |
* @param $term_type string one of |
1495 |
* - Unknown |
1496 |
* - Language |
1497 |
* - NamedArea |
1498 |
* - Rank |
1499 |
* - Feature |
1500 |
* - AnnotationType |
1501 |
* - MarkerType |
1502 |
* - ExtensionType |
1503 |
* - DerivationEventType |
1504 |
* - PresenceAbsenceTerm |
1505 |
* - NomenclaturalStatusType |
1506 |
* - NameRelationshipType |
1507 |
* - HybridRelationshipType |
1508 |
* - SynonymRelationshipType |
1509 |
* - TaxonRelationshipType |
1510 |
* - NameTypeDesignationStatus |
1511 |
* - SpecimenTypeDesignationStatus |
1512 |
* - InstitutionType |
1513 |
* - NamedAreaType |
1514 |
* - NamedAreaLevel |
1515 |
* - RightsType |
1516 |
* - MeasurementUnit |
1517 |
* - StatisticalMeasure |
1518 |
* - MaterialOrMethod |
1519 |
* - Material |
1520 |
* - Method |
1521 |
* - Modifier |
1522 |
* - Scope |
1523 |
* - Stage |
1524 |
* - KindOfUnit |
1525 |
* - Sex |
1526 |
* - ReferenceSystem |
1527 |
* - State |
1528 |
* - NaturalLanguageTerm |
1529 |
* - TextFormat |
1530 |
* - DeterminationModifier |
1531 |
* - DnaMarker |
1532 |
* |
1533 |
* @param $order_by |
1534 |
* Optionally sort option (default: CDM_ORDER_BY_TITLE_CACHE_ASC) |
1535 |
* possible values: |
1536 |
* - CDM_ORDER_BY_ID_ASC |
1537 |
* - CDM_ORDER_BY_ID_DESC |
1538 |
* - CDM_ORDER_BY_TITLE_CACHE_ASC |
1539 |
* - CDM_ORDER_BY_TITLE_CACHE_DESC |
1540 |
* - CDM_ORDER_BY_ORDER_INDEX_ASC (can only be used with OrderedTerms!!) |
1541 |
* - CDM_ORDER_BY_ORDER_INDEX_DESC (can only be used with OrderedTerms!!) |
1542 |
* @param bool $empty_option |
1543 |
* An additional element do be placed at the beginning og the list. This element will be the default option. |
1544 |
* @return array |
1545 |
* the terms in an array (key: uuid => value: label) as options for a form element that allows multiple choices. |
1546 |
*/ |
1547 |
function cdm_terms_by_type_as_option($term_type, $order_by = CDM_ORDER_BY_TITLE_CACHE_ASC, $term_label_callback = NULL, $empty_option = FALSE){ |
1548 |
$terms = cdm_ws_fetch_all( |
1549 |
CDM_WS_TERM, |
1550 |
array( |
1551 |
'class' => $term_type, |
1552 |
'orderBy' => $order_by |
1553 |
) |
1554 |
); |
1555 |
return cdm_terms_as_options($terms, $term_label_callback, $empty_option); |
1556 |
} |
1557 |
|
1558 |
/** |
1559 |
* @param array $none_option |
1560 |
* Will add a filter option to search for NULL values |
1561 |
* @param $with_empty_option |
1562 |
* Will add an empty option to the beginning. Choosing this option will disable the filtering. |
1563 |
* @return array |
1564 |
* An array of options with uuids as key and the localized term representation as value |
1565 |
*/ |
1566 |
function cdm_type_designation_status_filter_terms_as_options($none_option_label, $with_empty_option = false){ |
1567 |
$filter_terms = cdm_ws_get(CDM_WS_TYPE_DESIGNATION_STATUS_FILTER_TERMS); |
1568 |
|
1569 |
if(isset($filter_terms) && is_array($filter_terms)) { |
1570 |
foreach ($filter_terms as $filter_term) { |
1571 |
$options[join(',', $filter_term->uuids)] = $filter_term->label; |
1572 |
} |
1573 |
} |
1574 |
|
1575 |
if(is_string($none_option_label)){ |
1576 |
$options = array_merge(array('NULL' => $none_option_label), $options); |
1577 |
} |
1578 |
|
1579 |
if($with_empty_option !== FALSE){ |
1580 |
array_unshift ($options, ""); |
1581 |
} |
1582 |
|
1583 |
|
1584 |
return $options; |
1585 |
} |
1586 |
|
1587 |
|
1588 |
|
1589 |
/** |
1590 |
* Callback function which provides the localized representation of a cdm term. |
1591 |
* |
1592 |
* The representation is build by concatenating the abbreviated label with the label |
1593 |
* and thus is especially useful for relationship terms |
1594 |
* The localized representation provided by the cdm can be overwritten by |
1595 |
* providing a drupal translation. |
1596 |
* |
1597 |
*/ |
1598 |
function _cdm_relationship_type_term_label_callback($term) { |
1599 |
if (isset($term->representation_L10n_abbreviatedLabel)) { |
1600 |
return $term->representation_L10n_abbreviatedLabel . ' : ' |
1601 |
. t('@term', array('@term' => $term->representation_L10n)); |
1602 |
} |
1603 |
else { |
1604 |
return t('@term', array('@term' => $term->representation_L10n)); |
1605 |
} |
1606 |
} |
1607 |
|
1608 |
/** |
1609 |
* Callback function which provides the localized inverse representation of a cdm term. |
1610 |
* |
1611 |
* The representation is build by concatenating the abbreviated label with the label |
1612 |
* and thus is especially useful for relationship terms |
1613 |
* The localized representation provided by the cdm can be overwritten by |
1614 |
* providing a drupal translation. |
1615 |
* |
1616 |
*/ |
1617 |
function _cdm_relationship_type_term_inverse_label_callback($term) { |
1618 |
if (isset($term->inverseRepresentation_L10n_abbreviatedLabel)) { |
1619 |
return $term->inverseRepresentation_L10n_abbreviatedLabel . ' : ' |
1620 |
. t('@term', array('@term' => $term->inverseRepresentation_L10n)); |
1621 |
} |
1622 |
else { |
1623 |
return t('@term', array('@term' => $term->inverseRepresentation_L10n)); |
1624 |
} |
1625 |
} |
1626 |
|
1627 |
/** |
1628 |
* Returns the localized abbreviated label of the relationship term. |
1629 |
* |
1630 |
* In case the abbreviated label is not set the normal representation is returned. |
1631 |
* |
1632 |
* @param $term |
1633 |
* @param bool $is_inverse_relation |
1634 |
* @return string |
1635 |
* The abbreviated label |
1636 |
*/ |
1637 |
function cdm_relationship_type_term_abbreviated_label($term, $is_inverse_relation = false){ |
1638 |
|
1639 |
if($is_inverse_relation) { |
1640 |
if (isset($term->inverseRepresentation_L10n_abbreviatedLabel) && $term->inverseRepresentation_L10n_abbreviatedLabel) { |
1641 |
$abbr_label = $term->inverseResentation_L10n_abbreviatedLabel; |
1642 |
} else { |
1643 |
$abbr_label = $term->inverseRepresentation_L10n; |
1644 |
} |
1645 |
} else { |
1646 |
if (isset($term->representation_L10n_abbreviatedLabel) && $term->representation_L10n_abbreviatedLabel) { |
1647 |
$abbr_label = $term->representation_L10n_abbreviatedLabel; |
1648 |
} else { |
1649 |
$abbr_label = $term->representation_L10n; |
1650 |
} |
1651 |
} |
1652 |
return $abbr_label; |
1653 |
} |
1654 |
|
1655 |
/** |
1656 |
* Returns the symbol of the relationship term. |
1657 |
* |
1658 |
* In case the symbol is not set the function falls back to use the abbreviated label or |
1659 |
* the normal representation.. |
1660 |
* |
1661 |
* @param $term |
1662 |
* @param bool $is_inverse_relation |
1663 |
* @return string |
1664 |
* The abbreviated label |
1665 |
*/ |
1666 |
function cdm_relationship_type_term_symbol($term, $is_inverse_relation = false){ |
1667 |
|
1668 |
if($is_inverse_relation) { |
1669 |
if (isset($term->inverseSymbol) && $term->inverseSymbol) { |
1670 |
$symbol = $term->inverseSymbol; |
1671 |
} else if (isset($term->inverseRepresentation_L10n_abbreviatedLabel) && $term->inverseRepresentation_L10n_abbreviatedLabel) { |
1672 |
$symbol = $term->inverseResentation_L10n_abbreviatedLabel; |
1673 |
} else { |
1674 |
$symbol = $term->inverseRepresentation_L10n; |
1675 |
} |
1676 |
} else { |
1677 |
if (isset($term->symbol) && $term->symbol) { |
1678 |
$symbol = $term->symbol; |
1679 |
} else if (isset($term->representation_L10n_abbreviatedLabel) && $term->representation_L10n_abbreviatedLabel) { |
1680 |
$symbol = $term->representation_L10n_abbreviatedLabel; |
1681 |
} else { |
1682 |
$symbol = $term->representation_L10n; |
1683 |
} |
1684 |
} |
1685 |
return $symbol; |
1686 |
} |
1687 |
|
1688 |
// ========================================================================================== // |
1689 |
/** |
1690 |
* @todo Improve documentation of this function. |
1691 |
* |
1692 |
* eu.etaxonomy.cdm.model.description. |
1693 |
* CategoricalData |
1694 |
* CommonTaxonName |
1695 |
* Distribution |
1696 |
* IndividualsAssociation |
1697 |
* QuantitativeData |
1698 |
* TaxonInteraction |
1699 |
* TextData |
1700 |
*/ |
1701 |
function cdm_descriptionElementTypes_as_option($prependEmptyElement = FALSE) { |
1702 |
static $types = array( |
1703 |
"CategoricalData", |
1704 |
"CommonTaxonName", |
1705 |
"Distribution", |
1706 |
"IndividualsAssociation", |
1707 |
"QuantitativeData", |
1708 |
"TaxonInteraction", |
1709 |
"TextData", |
1710 |
); |
1711 |
|
1712 |
static $options = NULL; |
1713 |
if ($options == NULL) { |
1714 |
$options = array(); |
1715 |
if ($prependEmptyElement) { |
1716 |
$options[' '] = ''; |
1717 |
} |
1718 |
foreach ($types as $type) { |
1719 |
// No internatianalization here since these are purely technical terms. |
1720 |
$options["eu.etaxonomy.cdm.model.description." . $type] = $type; |
1721 |
} |
1722 |
} |
1723 |
return $options; |
1724 |
} |
1725 |
|
1726 |
|
1727 |
/** |
1728 |
* Fetches all TaxonDescription descriptions elements which are associated to the |
1729 |
* Taxon specified by the $taxon_uuid and merges the elements into the given |
1730 |
* feature tree. |
1731 |
* @param $feature_tree |
1732 |
* The CDM FeatureTree to be used as template |
1733 |
* @param $taxon_uuid |
1734 |
* The UUID of the taxon |
1735 |
* @param $excludes |
1736 |
* UUIDs of features to be excluded |
1737 |
* @return object |
1738 |
* The CDM FeatureTree which was given as parameter merged tree whereas the |
1739 |
* CDM FeatureNodes are extended by an additional field 'descriptionElements' |
1740 |
* witch will hold the according $descriptionElements. |
1741 |
*/ |
1742 |
function cdm_ws_descriptions_by_featuretree($feature_tree, $taxon_uuid, $exclude_uuids = array()) { |
1743 |
|
1744 |
if (!$feature_tree) { |
1745 |
drupal_set_message(check_plain(t("No 'FeatureTree' has been set so far. |
1746 |
In order to see the species profiles of your taxa, please select a |
1747 |
'FeatureTree' in the !settings"), array('!settings' => l(t('CDM Dataportal Settings'), 'admin/config/cdm_dataportal/layout'))), 'warning'); |
1748 |
return FALSE; |
1749 |
} |
1750 |
|
1751 |
$description_elements = cdm_ws_fetch_all(CDM_WS_DESCRIPTIONELEMENT_BY_TAXON, |
1752 |
array( |
1753 |
'taxon' => $taxon_uuid, |
1754 |
'features' => cdm_featureTree_elements_toString($feature_tree->root, ',', 'uuid', $exclude_uuids) |
1755 |
), |
1756 |
'POST' |
1757 |
); |
1758 |
|
1759 |
// Combine all descriptions into one feature tree. |
1760 |
$merged_nodes = _mergeFeatureTreeDescriptions($feature_tree->root->childNodes, $description_elements); |
1761 |
$feature_tree->root->childNodes = $merged_nodes; |
1762 |
|
1763 |
return $feature_tree; |
1764 |
} |
1765 |
|
1766 |
/** |
1767 |
* Returns a filtered a list of annotations for the cdm entity given as parameter $cdm_entity. |
1768 |
* If the annotations are not yet already loded with the cdm entity the cdm REST service will |
1769 |
* be requested for the annotations. |
1770 |
* |
1771 |
* @param string $cdm_entity |
1772 |
* An annotatable cdm entity. |
1773 |
* @param array $include_types |
1774 |
* If an array of annotation type uuids is supplied by this parameter the |
1775 |
* list of annotations is resticted to those which belong to this type. |
1776 |
* |
1777 |
* @return array |
1778 |
* An array of Annotation objects or an empty array. |
1779 |
*/ |
1780 |
function cdm_ws_getAnnotationsFor(&$cdm_entity, $include_types = FALSE) { |
1781 |
|
1782 |
if(!isset($cdm_entity->annotations)){ |
1783 |
$annotation_url = cdm_compose_annotations_uri($cdm_entity); |
1784 |
$cdm_entity->annotations = cdm_ws_fetch_all($annotation_url, array(), 'GET', TRUE); |
1785 |
} |
1786 |
|
1787 |
$annotations = array(); |
1788 |
foreach ($cdm_entity->annotations as $annotation) { |
1789 |
if ($include_types) { |
1790 |
if ( |
1791 |
( isset($annotation->annotationType->uuid) && in_array($annotation->annotationType->uuid, $include_types, TRUE) ) |
1792 |
|| ($annotation->annotationType === NULL && in_array('NULL_VALUE', $include_types, TRUE)) |
1793 |
) { |
1794 |
$annotations[] = $annotation; |
1795 |
} |
1796 |
} |
1797 |
else { |
1798 |
$annotations[] = $annotation; |
1799 |
} |
1800 |
} |
1801 |
return $annotations; |
1802 |
|
1803 |
} |
1804 |
|
1805 |
/** |
1806 |
* Provides the list of visible annotations for the $cdm_entity. |
1807 |
* |
1808 |
* @param $cdm_entity |
1809 |
* The annotatable CDM entity |
1810 |
* |
1811 |
* @return array of the annotations which are visible according to the settings as stored in ANNOTATION_TYPES_VISIBLE |
1812 |
*/ |
1813 |
function cdm_fetch_visible_annotations($cdm_entity){ |
1814 |
|
1815 |
static $annotations_types_filter = null; |
1816 |
if(!$annotations_types_filter) { |
1817 |
$annotations_types_filter = unserialize(EXTENSION_TYPES_VISIBLE_DEFAULT); |
1818 |
} |
1819 |
return cdm_ws_getAnnotationsFor($cdm_entity, variable_get(ANNOTATION_TYPES_VISIBLE, $annotations_types_filter)); |
1820 |
} |
1821 |
|
1822 |
/** |
1823 |
* Loads the annotations from the REST service an adds them as field to the given $annotatable_entity. |
1824 |
* |
1825 |
* NOTE: The annotations are not filtered by the ANNOTATION_TYPES_VISIBLE settings since this method is meant to act |
1826 |
* like the annotations have been fetched in the ORM-framework in the service. |
1827 |
* |
1828 |
* @param object $annotatable_entity |
1829 |
* The CDM AnnotatableEntity to load annotations for |
1830 |
*/ |
1831 |
function cdm_load_annotations(&$annotatable_entity) { |
1832 |
if (isset($annotatable_entity) && !isset($annotatable_entity->annotations)) { |
1833 |
$annotations = cdm_ws_getAnnotationsFor($annotatable_entity); |
1834 |
if (is_array($annotations)) { |
1835 |
$annotatable_entity->annotations = $annotations; |
1836 |
} |
1837 |
} |
1838 |
} |
1839 |
|
1840 |
function cdm_load_tagged_full_title($taxon_name){ |
1841 |
if(isset($taxon_name) && !isset($taxon_name->taggedFullTitle)){ |
1842 |
$tagged_full_title = cdm_ws_get(CDM_WS_NAME, array($taxon_name->uuid, 'taggedFullTitle')); |
1843 |
if(is_array($tagged_full_title)){ |
1844 |
$taxon_name->taggedFullTitle = $tagged_full_title; |
1845 |
|
1846 |
} |
1847 |
} |
1848 |
} |
1849 |
|
1850 |
/** |
1851 |
* Extends the $cdm_entity object by the field if it is not already existing. |
1852 |
* |
1853 |
* This function can only be used for fields with 1 to many relations. |
1854 |
* |
1855 |
* @param $cdm_base_type |
1856 |
* @param $field_name |
1857 |
* @param $cdm_entity |
1858 |
*/ |
1859 |
function cdm_lazyload_array_field($cdm_base_type, $field_name, &$cdm_entity) |
1860 |
{ |
1861 |
if (!isset($cdm_entity->$field_name)) { |
1862 |
$items = cdm_ws_fetch_all('portal/' . $cdm_base_type . '/' . $cdm_entity->uuid . '/' . $field_name); |
1863 |
$cdm_entity->$field_name = $items; |
1864 |
} |
1865 |
} |
1866 |
|
1867 |
|
1868 |
/** |
1869 |
* Get a NomenclaturalReference string. |
1870 |
* |
1871 |
* Returns the NomenclaturalReference string with correctly placed |
1872 |
* microreference (= reference detail) e.g. |
1873 |
* in Phytotaxa 43: 1-48. 2012. |
1874 |
* |
1875 |
* @param string $referenceUuid |
1876 |
* UUID of the reference. |
1877 |
* @param string $microreference |
1878 |
* Reference detail. |
1879 |
* |
1880 |
* @return string |
1881 |
* a NomenclaturalReference. |
1882 |
*/ |
1883 |
function cdm_ws_getNomenclaturalReference($referenceUuid, $microreference) { |
1884 |
|
1885 |
// TODO the below statement avoids error boxes due to #4644 remove it once this ticket is solved |
1886 |
if(is_array($microreference) || is_object($microreference)) { |
1887 |
return ''; |
1888 |
} |
1889 |
|
1890 |
$obj = cdm_ws_get(CDM_WS_NOMENCLATURAL_REFERENCE_CITATION, array( |
1891 |
$referenceUuid, |
1892 |
), "microReference=" . urlencode($microreference)); |
1893 |
|
1894 |
if ($obj) { |
1895 |
return $obj->String; |
1896 |
} |
1897 |
else { |
1898 |
return NULL; |
1899 |
} |
1900 |
} |
1901 |
|
1902 |
/** |
1903 |
* finds and returns the FeatureNode denoted by the given $feature_uuid |
1904 |
* |
1905 |
* @param $feature_tree_nodes |
1906 |
* The nodes contained in CDM FeatureTree entitiy: $feature->root->childNodes |
1907 |
* @param $feature_uuid |
1908 |
* The UUID of the Feature |
1909 |
* @return object |
1910 |
* the FeatureNode or null |
1911 |
*/ |
1912 |
function &cdm_feature_tree_find_node($feature_tree_nodes, $feature_uuid){ |
1913 |
|
1914 |
// 1. scan this level |
1915 |
foreach ($feature_tree_nodes as $node){ |
1916 |
if($node->term->uuid == $feature_uuid){ |
1917 |
return $node; |
1918 |
} |
1919 |
} |
1920 |
|
1921 |
// 2. descend into childen |
1922 |
foreach ($feature_tree_nodes as $node){ |
1923 |
if(is_array($node->childNodes)){ |
1924 |
$node = cdm_feature_tree_find_node($node->childNodes, $feature_uuid); |
1925 |
if($node) { |
1926 |
return $node; |
1927 |
} |
1928 |
} |
1929 |
} |
1930 |
$null_var = null; // kludgy workaround to avoid "PHP Notice: Only variable references should be returned by reference" |
1931 |
return $null_var; |
1932 |
} |
1933 |
|
1934 |
/** |
1935 |
* Merges the given featureNodes structure with the descriptionElements. |
1936 |
* |
1937 |
* This method is used in preparation for rendering the descriptionElements. |
1938 |
* The descriptionElements which belong to a specific feature node are appended |
1939 |
* to a the feature node by creating a new field: |
1940 |
* - descriptionElements: the CDM DescriptionElements which belong to this feature |
1941 |
* The descriptionElements will be cleared in advance in order to allow reusing the |
1942 |
* same feature tree without the risk of mixing sets of description elements. |
1943 |
* |
1944 |
* which originally is not existing in the cdm. |
1945 |
* |
1946 |
* |
1947 |
* |
1948 |
* @param array $featureNodes |
1949 |
* An array of cdm FeatureNodes which may be hierarchical since feature nodes |
1950 |
* may have children. |
1951 |
* @param array $descriptionElements |
1952 |
* An flat array of cdm DescriptionElements |
1953 |
* @return array |
1954 |
* The $featureNodes structure enriched with the according $descriptionElements |
1955 |
*/ |
1956 |
function _mergeFeatureTreeDescriptions($featureNodes, $descriptionElements) { |
1957 |
|
1958 |
foreach ($featureNodes as &$feature_node) { |
1959 |
// since the $featureNodes array is reused for each description |
1960 |
// it is necessary to clear the custom node fields in advance |
1961 |
if(isset($feature_node->descriptionElements)){ |
1962 |
unset($feature_node->descriptionElements); |
1963 |
} |
1964 |
|
1965 |
// Append corresponding elements to an additional node field: |
1966 |
// $node->descriptionElements. |
1967 |
foreach ($descriptionElements as $element) { |
1968 |
if ($element->feature->uuid == $feature_node->term->uuid) { |
1969 |
if (!isset($feature_node->descriptionElements)) { |
1970 |
$feature_node->descriptionElements = array(); |
1971 |
} |
1972 |
$feature_node->descriptionElements[] = $element; |
1973 |
} |
1974 |
} |
1975 |
|
1976 |
// Recurse into node children. |
1977 |
if (isset($feature_node->childNodes[0])) { |
1978 |
$mergedChildNodes = _mergeFeatureTreeDescriptions($feature_node->childNodes, $descriptionElements); |
1979 |
$feature_node->childNodes = $mergedChildNodes; |
1980 |
} |
1981 |
|
1982 |
if(!isset($feature_node->descriptionElements) && !isset($feature_node->childNodes[0])){ |
1983 |
unset($feature_node); |
1984 |
} |
1985 |
|
1986 |
} |
1987 |
|
1988 |
return $featureNodes; |
1989 |
} |
1990 |
|
1991 |
/** |
1992 |
* Sends a GET or POST request to a CDM RESTService and returns a de-serialized object. |
1993 |
* |
1994 |
* The response from the HTTP GET request is returned as object. |
1995 |
* The response objects coming from the webservice configured in the |
1996 |
* 'cdm_webservice_url' variable are being cached in a level 1 (L1) and / or |
1997 |
* in a level 2 (L2) cache. |
1998 |
* |
1999 |
* Since the L1 cache is implemented as static variable of the cdm_ws_get() |
2000 |
* function, this cache persists only per each single page execution. |
2001 |
* Any object coming from the webservice is stored into it by default. |
2002 |
* In contrast to this default caching mechanism the L2 cache only is used if |
2003 |
* the 'cdm_webservice_cache' variable is set to TRUE, |
2004 |
* which can be set using the modules administrative settings section. |
2005 |
* Objects stored in this L2 cache are serialized and stored |
2006 |
* using the drupal cache in the '{prefix}cache_cdm_ws' cache table. So the |
2007 |
* objects that are stored in the database will persist as |
2008 |
* long as the drupal cache is not being cleared and are available across |
2009 |
* multiple script executions. |
2010 |
* |
2011 |
* @param string $uri |
2012 |
* URL to the webservice. |
2013 |
* @param array $pathParameters |
2014 |
* An array of path parameters. |
2015 |
* @param string $query |
2016 |
* A query string to be appended to the URL. |
2017 |
* @param string $method |
2018 |
* The HTTP method to use, valid values are "GET" or "POST"; |
2019 |
* @param bool $absoluteURI |
2020 |
* TRUE when the URL should be treated as absolute URL. |
2021 |
* |
2022 |
* @return object| array |
2023 |
* The de-serialized webservice response object. |
2024 |
*/ |
2025 |
function cdm_ws_get($uri, $pathParameters = array(), $query = NULL, $method = "GET", $absoluteURI = FALSE) { |
2026 |
|
2027 |
static $cacheL1 = array(); |
2028 |
|
2029 |
$data = NULL; |
2030 |
// store query string in $data and clear the query, $data will be set as HTTP request body |
2031 |
if($method == 'POST'){ |
2032 |
$data = $query; |
2033 |
$query = NULL; |
2034 |
} |
2035 |
|
2036 |
// Transform the given uri path or pattern into a proper webservice uri. |
2037 |
if (!$absoluteURI) { |
2038 |
$uri = cdm_compose_url($uri, $pathParameters, $query); |
2039 |
} |
2040 |
cdm_ws_apply_classification_subtree_filter($uri); |
2041 |
|
2042 |
// read request parameter 'cacheL2_refresh' |
2043 |
// which allows refreshing the level 2 cache |
2044 |
$do_cacheL2_refresh = isset($_REQUEST['cacheL2_refresh']) && $_REQUEST['cacheL2_refresh'] == 1; |
2045 |
|
2046 |
$is_cdm_ws_uri = _is_cdm_ws_uri($uri); |
2047 |
$use_cacheL2 = variable_get('cdm_webservice_cache', 1); |
2048 |
|
2049 |
if($method == 'GET'){ |
2050 |
$cache_key = $uri; |
2051 |
} else { |
2052 |
// sha1 creates longer hashes and thus will cause fewer collisions than md5. |
2053 |
// crc32 is faster but creates much shorter hashes |
2054 |
$cache_key = $uri . '[' . $method . ':' . sha1($data) .']'; |
2055 |
} |
2056 |
|
2057 |
if (array_key_exists($cache_key, $cacheL1)) { |
2058 |
$cacheL1_obj = $cacheL1[$uri]; |
2059 |
} |
2060 |
|
2061 |
$set_cacheL1 = FALSE; |
2062 |
if ($is_cdm_ws_uri && !isset($cacheL1_obj)) { |
2063 |
$set_cacheL1 = TRUE; |
2064 |
} |
2065 |
|
2066 |
// Only cache cdm webservice URIs. |
2067 |
$set_cacheL2 = $use_cacheL2 && $is_cdm_ws_uri && $set_cacheL1; |
2068 |
$cacheL2_entry = FALSE; |
2069 |
|
2070 |
if ($use_cacheL2 && !$do_cacheL2_refresh) { |
2071 |
// Try to get object from cacheL2. |
2072 |
$cacheL2_entry = cache_get($cache_key, 'cache_cdm_ws'); |
2073 |
} |
2074 |
|
2075 |
if (isset($cacheL1_obj)) { |
2076 |
// |
2077 |
// The object has been found in the L1 cache. |
2078 |
// |
2079 |
$obj = $cacheL1_obj; |
2080 |
if (cdm_debug_block_visible()) { |
2081 |
cdm_ws_debug_add($uri, $method, $data, 0, 0, NULL, 'cacheL1'); |
2082 |
} |
2083 |
} |
2084 |
elseif ($cacheL2_entry) { |
2085 |
// |
2086 |
// The object has been found in the L2 cache. |
2087 |
// |
2088 |
$duration_parse_start = microtime(TRUE); |
2089 |
$obj = unserialize($cacheL2_entry->data); |
2090 |
$duration_parse = microtime(TRUE) - $duration_parse_start; |
2091 |
|
2092 |
if (cdm_debug_block_visible()) { |
2093 |
cdm_ws_debug_add($uri, $method, $data, 0, $duration_parse, NULL, 'cacheL2'); |
2094 |
} |
2095 |
} |
2096 |
else { |
2097 |
// |
2098 |
// Get the object from the webservice and cache it. |
2099 |
// |
2100 |
$duration_fetch_start = microtime(TRUE); |
2101 |
// Request data from webservice JSON or XML. |
2102 |
$response = cdm_http_request($uri, $method, $data); |
2103 |
$response_body = NULL; |
2104 |
if (isset($response->data)) { |
2105 |
$response_body = $response->data; |
2106 |
} |
2107 |
$duration_fetch = microtime(TRUE) - $duration_fetch_start; |
2108 |
$duration_parse_start = microtime(TRUE); |
2109 |
|
2110 |
// Parse data and create object. |
2111 |
$obj = cdm_load_obj($response_body); |
2112 |
|
2113 |
if(isset($obj->servlet) && isset($obj->status) && is_numeric($obj->status)){ |
2114 |
// this is json error message returned by jetty #8914 |
2115 |
// wee need to replace it by null to avoid breaking existing assumptions in the code here |
2116 |
// this is also related to #2711 |
2117 |
$obj = null; |
2118 |
} |
2119 |
|
2120 |
$duration_parse = microtime(TRUE) - $duration_parse_start; |
2121 |
|
2122 |
if (cdm_debug_block_visible()) { |
2123 |
if ($obj || $response_body == "[]") { |
2124 |
$status = 'valid'; |
2125 |
} |
2126 |
else { |
2127 |
$status = 'invalid'; |
2128 |
} |
2129 |
cdm_ws_debug_add($uri, $method, $data, $duration_fetch, $duration_parse, strlen($response_body), $status); |
2130 |
} |
2131 |
if ($set_cacheL2) { |
2132 |
// Store the object in cache L2. |
2133 |
// Comment @WA perhaps better if Drupal serializedatas here? Then the |
2134 |
// flag serialized is set properly in the cache table. |
2135 |
cache_set($cache_key, serialize($obj), 'cache_cdm_ws', CACHE_TEMPORARY); |
2136 |
} |
2137 |
} |
2138 |
if ($obj) { |
2139 |
// Store the object in cache L1. |
2140 |
if ($set_cacheL1) { |
2141 |
$cacheL1[$cache_key] = $obj; |
2142 |
} |
2143 |
} |
2144 |
return $obj; |
2145 |
} |
2146 |
|
2147 |
function cdm_ws_apply_classification_subtree_filter(&$uri){ |
2148 |
|
2149 |
$classification_subtree_filter_patterns = &drupal_static('classification_subtree_filter_patterns', array( |
2150 |
"#/classification/[0-9a-f\-]{36}/childNodes#", |
2151 |
/* covered by above pattern: |
2152 |
"#/classification/[0-9a-f\-]{36}/childNodesAt/[0-9a-f\-]{36}#", |
2153 |
'#/classification/[0-9a-f\-]{36}/childNodesOf/[0-9a-f\-]{36}#', |
2154 |
*/ |
2155 |
"#/portal/classification/[0-9a-f\-]{36}/childNodes#", |
2156 |
/* covered by above pattern: |
2157 |
"#/portal/classification/[0-9a-f\-]{36}/childNodesAt/[0-9a-f\-]{36}#", |
2158 |
'#/portal/classification/[0-9a-f\-]{36}/childNodesOf/[0-9a-f\-]{36}#', |
2159 |
*/ |
2160 |
'#/portal/classification/[0-9a-f\-]{36}/pathFrom/[0-9a-f\-]{36}#', |
2161 |
"#/portal/taxon/search#", |
2162 |
"#/portal/taxon/find#", |
2163 |
/* covered by above pattern: |
2164 |
"#/portal/taxon/findByDescriptionElementFullText#", |
2165 |
"#/portal/taxon/findByFullText#", |
2166 |
"#/portal/taxon/findByEverythingFullText#", |
2167 |
"#/portal/taxon/findByIdentifier#", |
2168 |
"#/portal/taxon/findByMarker#", |
2169 |
"#/portal/taxon/findByMarker#", |
2170 |
"#/portal/taxon/findByMarker#", |
2171 |
*/ |
2172 |
"#/portal/taxon/[0-9a-f\-]{36}#" |
2173 |
/* covered by above pattern: |
2174 |
"#/portal/taxon/[0-9a-f\-]{36}/taxonNodes#", |
2175 |
*/ |
2176 |
)); |
2177 |
|
2178 |
$sub_tree_filter_uuid_value = variable_get(CDM_SUB_TREE_FILTER_UUID, FALSE); |
2179 |
if(is_uuid($sub_tree_filter_uuid_value)){ |
2180 |
foreach($classification_subtree_filter_patterns as $preg_pattern){ |
2181 |
if(preg_match($preg_pattern, $uri)){ |
2182 |
// no need to take care for uri fragments with ws uris! |
2183 |
if(strpos( $uri, '?')){ |
2184 |
$uri .= '&subtree=' . $sub_tree_filter_uuid_value; |
2185 |
} else { |
2186 |
$uri .= '?subtree='. $sub_tree_filter_uuid_value; |
2187 |
} |
2188 |
break; |
2189 |
} |
2190 |
} |
2191 |
} |
2192 |
|
2193 |
} |
2194 |
/** |
2195 |
* Processes and stores the given information in $_SESSION['cdm']['ws_debug'] as table row. |
2196 |
* |
2197 |
* The cdm_ws_debug block will display the debug information. |
2198 |
* |
2199 |
* @param $uri |
2200 |
* The CDM REST URI to which the request has been send |
2201 |
* @param string $method |
2202 |
* The HTTP request method, either 'GET' or 'POST' |
2203 |
* @param string $post_data |
2204 |
* The datastring send with a post request |
2205 |
* @param $duration_fetch |
2206 |
* The time in seconds it took to fetch the data from the web service |
2207 |
* @param $duration_parse |
2208 |
* Time in seconds which was needed to parse the json response |
2209 |
* @param $datasize |
2210 |
* Size of the data received from the server |
2211 |
* @param $status |
2212 |
* A status string, possible values are: 'valid', 'invalid', 'cacheL1', 'cacheL2' |
2213 |
* @return bool |
2214 |
* TRUE if adding the debug information was successful |
2215 |
*/ |
2216 |
function cdm_ws_debug_add($uri, $method, $post_data, $duration_fetch, $duration_parse, $datasize, $status) { |
2217 |
|
2218 |
static $initial_time = NULL; |
2219 |
if(!$initial_time) { |
2220 |
$initial_time = microtime(TRUE); |
2221 |
} |
2222 |
$time = microtime(TRUE) - $initial_time; |
2223 |
|
2224 |
// Decompose uri into path and query element. |
2225 |
$uri_parts = explode("?", $uri); |
2226 |
$query = array(); |
2227 |
if (count($uri_parts) == 2) { |
2228 |
$path = $uri_parts[0]; |
2229 |
} |
2230 |
else { |
2231 |
$path = $uri; |
2232 |
} |
2233 |
|
2234 |
if(strpos($uri, '?') > 0){ |
2235 |
$json_uri = str_replace('?', '.json?', $uri); |
2236 |
$xml_uri = str_replace('?', '.xml?', $uri); |
2237 |
} else { |
2238 |
$json_uri = $uri . '.json'; |
2239 |
$xml_uri = $json_uri . '.xml'; |
2240 |
} |
2241 |
|
2242 |
// data links to make data accecsible as json and xml |
2243 |
$data_links = ''; |
2244 |
if (_is_cdm_ws_uri($path)) { |
2245 |
|
2246 |
// see ./js/http-method-link.js |
2247 |
|
2248 |
if($method == 'GET'){ |
2249 |
$data_links .= '<a href="' . $xml_uri . '" target="data">xml</a>-'; |
2250 |
$data_links .= '<a href="' . url('cdm_api/proxy/' . urlencode($xml_uri)) . '" target="data">proxied</a>'; |
2251 |
$data_links .= '<br/>'; |
2252 |
$data_links .= '<a href="' . $json_uri . '" target="data">json</a>-'; |
2253 |
$data_links .= '<a href="' . url('cdm_api/proxy/' . urlencode($json_uri)) . '" target="data">proxied</a>'; |
2254 |
} else { |
2255 |
$js_link_activation = 'class="http-' . $method . '-link" data-cdm-http-post="' . $post_data . '" type="application/x-www-form-urlencoded"'; |
2256 |
$data_links .= '<a ' . $js_link_activation . ' href="' . url('cdm_api/proxy/' . urlencode($xml_uri)) . '" target="data">xml-proxied</a>'; |
2257 |
$data_links .= '<br/>'; |
2258 |
$data_links .= '<a ' . $js_link_activation . ' href="' . url('cdm_api/proxy/' . urlencode($json_uri)) . '" target="data">json-proxied</a>'; |
2259 |
} |
2260 |
} |
2261 |
else { |
2262 |
$data_links .= '<a href="' . $uri . '" target="data">open</a>'; |
2263 |
} |
2264 |
|
2265 |
// |
2266 |
$data = array( |
2267 |
'ws_uri' => $uri, |
2268 |
'method' => $method, |
2269 |
'post_data' => $post_data, |
2270 |
'time' => sprintf('%3.3f', $time), |
2271 |
'fetch_seconds' => sprintf('%3.3f', $duration_fetch), |
2272 |
'parse_seconds' => sprintf('%3.3f', $duration_parse), |
2273 |
'size_kb' => sprintf('%3.1f', ($datasize / 1024)) , |
2274 |
'status' => $status, |
2275 |
'data_links' => $data_links |
2276 |
); |
2277 |
if (!isset($_SESSION['cdm']['ws_debug'])) { |
2278 |
$_SESSION['cdm']['ws_debug'] = array(); |
2279 |
} |
2280 |
$_SESSION['cdm']['ws_debug'][] = serialize($data); |
2281 |
|
2282 |
// Mark this page as being uncacheable. |
2283 |
// taken over from drupal_get_messages() but it is unsure if we really need this here |
2284 |
drupal_page_is_cacheable(FALSE); |
2285 |
|
2286 |
// Messages not set when DB connection fails. |
2287 |
return isset($_SESSION['cdm']['ws_debug']) ? $_SESSION['cdm']['ws_debug'] : NULL; |
2288 |
} |
2289 |
|
2290 |
/** |
2291 |
* helper function to dtermine if the cdm_debug_block should be displayed or not |
2292 |
* the visibility depends on whether |
2293 |
* - the block is enabled |
2294 |
* - the visibility restrictions in the block settings are satisfied |
2295 |
*/ |
2296 |
function cdm_debug_block_visible() { |
2297 |
static $is_visible = null; |
2298 |
|
2299 |
if($is_visible === null){ |
2300 |
$block = block_load('cdm_api', 'cdm_ws_debug'); |
2301 |
$is_visible = isset($block->status) && $block->status == 1; |
2302 |
if($is_visible){ |
2303 |
$blocks = array($block); |
2304 |
// Checks the page, user role, and user-specific visibilty settings. |
2305 |
block_block_list_alter($blocks); |
2306 |
$is_visible = count($blocks) > 0; |
2307 |
} |
2308 |
} |
2309 |
return $is_visible; |
2310 |
} |
2311 |
|
2312 |
/** |
2313 |
* @todo Please document this function. |
2314 |
* @see http://drupal.org/node/1354 |
2315 |
*/ |
2316 |
function cdm_load_obj($response_body) { |
2317 |
$obj = json_decode($response_body); |
2318 |
|
2319 |
if (!(is_object($obj) || is_array($obj))) { |
2320 |
ob_start(); |
2321 |
$obj_dump = ob_get_contents(); |
2322 |
ob_clean(); |
2323 |
return FALSE; |
2324 |
} |
2325 |
|
2326 |
return $obj; |
2327 |
} |
2328 |
|
2329 |
/** |
2330 |
* Do a http request to a CDM RESTful web service. |
2331 |
* |
2332 |
* @param string $uri |
2333 |
* The webservice url. |
2334 |
* @param string $method |
2335 |
* The HTTP method to use, valid values are "GET" or "POST"; defaults to |
2336 |
* "GET" even if NULL, FALSE or any invalid value is supplied. |
2337 |
* @param $data: A string containing the request body, formatted as |
2338 |
* 'param=value¶m=value&...'. Defaults to NULL. |
2339 |
* |
2340 |
* @return object |
2341 |
* The object as returned by drupal_http_request(): |
2342 |
* An object that can have one or more of the following components: |
2343 |
* - request: A string containing the request body that was sent. |
2344 |
* - code: An integer containing the response status code, or the error code |
2345 |
* if an error occurred. |
2346 |
* - protocol: The response protocol (e.g. HTTP/1.1 or HTTP/1.0). |
2347 |
* - status_message: The status message from the response, if a response was |
2348 |
* received. |
2349 |
* - redirect_code: If redirected, an integer containing the initial response |
2350 |
* status code. |
2351 |
* - redirect_url: If redirected, a string containing the URL of the redirect |
2352 |
* target. |
2353 |
* - error: If an error occurred, the error message. Otherwise not set. |
2354 |
* - headers: An array containing the response headers as name/value pairs. |
2355 |
* HTTP header names are case-insensitive (RFC 2616, section 4.2), so for |
2356 |
* easy access the array keys are returned in lower case. |
2357 |
* - data: A string containing the response body that was received. |
2358 |
*/ |
2359 |
function cdm_http_request($uri, $method = "GET", $data = NULL) { |
2360 |
static $acceptLanguage = NULL; |
2361 |
$header = array(); |
2362 |
|
2363 |
if(!$acceptLanguage && module_exists('i18n')){ |
2364 |
$acceptLanguage = i18n_language_content()->language; |
2365 |
} |
2366 |
|
2367 |
if (!$acceptLanguage) { |
2368 |
if (function_exists('apache_request_headers')) { |
2369 |
$headers = apache_request_headers(); |
2370 |
if (isset($headers['Accept-Language'])) { |
2371 |
$acceptLanguage = $headers['Accept-Language']; |
2372 |
} |
2373 |
} |
2374 |
} |
2375 |
|
2376 |
if ($method != "GET" && $method != "POST") { |
2377 |
drupal_set_message('cdm_api.module#cdm_http_request() : unsupported HTTP request method ', 'error'); |
2378 |
} |
2379 |
|
2380 |
if (_is_cdm_ws_uri($uri)) { |
2381 |
$header['Accept'] = 'application/json'; |
2382 |
$header['Accept-Language'] = $acceptLanguage; |
2383 |
$header['Accept-Charset'] = 'UTF-8'; |
2384 |
} |
2385 |
|
2386 |
if($method == "POST") { |
2387 |
// content type is application/x-www-form-urlencoded, so the request body uses the same format as the query string |
2388 |
$header['Content-Type'] = 'application/x-www-form-urlencoded'; |
2389 |
} |
2390 |
|
2391 |
|
2392 |
cdm_dd($uri); |
2393 |
return drupal_http_request($uri, array( |
2394 |
'headers' => $header, |
2395 |
'method' => $method, |
2396 |
'data' => $data, |
2397 |
'timeout' => CDM_HTTP_REQUEST_TIMEOUT |
2398 |
) |
2399 |
); |
2400 |
} |
2401 |
|
2402 |
/** |
2403 |
* Concatenates recursively the fields of all features contained in the given |
2404 |
* CDM FeatureTree root node. |
2405 |
* |
2406 |
* @param $rootNode |
2407 |
* A CDM FeatureTree node |
2408 |
* @param |
2409 |
* The character to be used as glue for concatenation, default is ', ' |
2410 |
* @param $field_name |
2411 |
* The field name of the CDM Features |
2412 |
* @param $excludes |
2413 |
* Allows defining a set of values to be excluded. This refers to the values |
2414 |
* in the field denoted by the $field_name parameter |
2415 |
* |
2416 |
*/ |
2417 |
function cdm_featureTree_elements_toString($root_node, $separator = ', ', $field_name = 'representation_L10n', $excludes = array()) { |
2418 |
$out = ''; |
2419 |
|
2420 |
$pre_child_separator = $separator; |
2421 |
$post_child_separator = ''; |
2422 |
|
2423 |
foreach ($root_node->childNodes as $feature_node) { |
2424 |
$out .= ($out ? $separator : ''); |
2425 |
if(!in_array($feature_node->term->$field_name, $excludes)) { |
2426 |
$out .= $feature_node->term->$field_name; |
2427 |
if (is_array($feature_node->childNodes) && count($feature_node->childNodes) > 0) { |
2428 |
$childlabels = cdm_featureTree_elements_toString($feature_node, $separator, $field_name); |
2429 |
if (strlen($childlabels)) { |
2430 |
$out .= $pre_child_separator . $childlabels . $post_child_separator; |
2431 |
} |
2432 |
} |
2433 |
} |
2434 |
} |
2435 |
return $out; |
2436 |
} |
2437 |
|
2438 |
/** |
2439 |
* Create a one-dimensional form options array. |
2440 |
* |
2441 |
* Creates an array of all features in the feature tree of feature nodes, |
2442 |
* the node labels are indented by $node_char and $childIndent depending on the |
2443 |
* hierachy level. |
2444 |
* |
2445 |
* @param - $rootNode |
2446 |
* @param - $node_char |
2447 |
* @param - $childIndentStr |
2448 |
* @param - $childIndent |
2449 |
* ONLY USED INTERNALLY! |
2450 |
* |
2451 |
* @return array |
2452 |
* A one dimensional Drupal form options array. |
2453 |
*/ |
2454 |
function _featureTree_nodes_as_feature_options($rootNode, $node_char = "├─ ", $childIndentStr = ' ', $childIndent = '') { |
2455 |
$options = array(); |
2456 |
foreach ($rootNode->childNodes as $featureNode) { |
2457 |
$indent_prefix = ''; |
2458 |
if ($childIndent) { |
2459 |
$indent_prefix = $childIndent . $node_char . " "; |
2460 |
} |
2461 |
$options[$featureNode->term->uuid] = $indent_prefix . $featureNode->term->representation_L10n; |
2462 |
if (isset($featureNode->childNodes) && is_array($featureNode->childNodes)) { |
2463 |
// Foreach ($featureNode->childNodes as $childNode){ |
2464 |
$childList = _featureTree_nodes_as_feature_options($featureNode, $node_char, $childIndentStr, $childIndent . $childIndentStr); |
2465 |
$options = array_merge_recursive($options, $childList); |
2466 |
// } |
2467 |
} |
2468 |
} |
2469 |
return $options; |
2470 |
} |
2471 |
|
2472 |
/** |
2473 |
* Returns an array with all available FeatureTrees and the representations of the selected |
2474 |
* FeatureTree as a detail view. |
2475 |
* |
2476 |
* @param boolean $add_default_feature_free |
2477 |
* @param boolean $show_weight |
2478 |
* Show the weight which will be applied to the according feature block |
2479 |
* @return array |
2480 |
* associative array with following keys: |
2481 |
* -options: Returns an array with all available Feature Trees |
2482 |
* -treeRepresentations: Returns representations of the selected Feature Tree as a detail view |
2483 |
* |
2484 |
*/ |
2485 |
function cdm_get_featureTrees_as_options($add_default_feature_free = FALSE, $show_weight = FALSE) { |
2486 |
|
2487 |
$options = array(); |
2488 |
$tree_representations = array(); |
2489 |
$feature_trees = array(); |
2490 |
|
2491 |
// Set tree that contains all features. |
2492 |
if ($add_default_feature_free) { |
2493 |
$options[UUID_DEFAULT_FEATURETREE] = t('Default Featuretree (contains all features)'); |
2494 |
$feature_trees[] = cdm_ws_get(CDM_WS_TERMTREE, UUID_DEFAULT_FEATURETREE); |
2495 |
} |
2496 |
|
2497 |
// Get feature trees from database. |
2498 |
$persited_trees = cdm_ws_fetch_all(CDM_WS_TERMTREES, array("termType" => "Feature")); |
2499 |
if (is_array($persited_trees)) { |
2500 |
$feature_trees = array_merge($feature_trees, $persited_trees); |
2501 |
} |
2502 |
|
2503 |
foreach ($feature_trees as $featureTree) { |
2504 |
|
2505 |
if(!is_object($featureTree)){ |
2506 |
continue; |
2507 |
} |
2508 |
// Do not add the DEFAULT_FEATURETREE again, |
2509 |
if ($featureTree->uuid != UUID_DEFAULT_FEATURETREE) { |
2510 |
$options[$featureTree->uuid] = $featureTree->titleCache; |
2511 |
} |
2512 |
|
2513 |
// Render the hierarchic tree structure |
2514 |
if (is_array( $featureTree->root->childNodes) && count( $featureTree->root->childNodes) > 0) { |
2515 |
|
2516 |
// Render the hierarchic tree structure. |
2517 |
$treeDetails = '<div class="featuretree_structure">' |
2518 |
. render_feature_tree_hierarchy($featureTree->uuid, $show_weight) |
2519 |
. '</div>'; |
2520 |
|
2521 |
$form = array(); |
2522 |
$form['featureTree-' . $featureTree->uuid] = array( |
2523 |
'#type' => 'fieldset', |
2524 |
'#title' => 'Show details', |
2525 |
'#attributes' => array('class' => array('collapsible collapsed')), |
2526 |
// '#collapsible' => TRUE, |
2527 |
// '#collapsed' => TRUE, |
2528 |
); |
2529 |
$form['featureTree-' . $featureTree->uuid]['details'] = array( |
2530 |
'#markup' => $treeDetails, |
2531 |
); |
2532 |
|
2533 |
$tree_representations[$featureTree->uuid] = drupal_render($form); |
2534 |
} |
2535 |
|
2536 |
} // END loop over feature trees |
2537 |
|
2538 |
// return $options; |
2539 |
return array('options' => $options, 'treeRepresentations' => $tree_representations); |
2540 |
} |
2541 |
|
2542 |
/** |
2543 |
* Provides the list of available classifications in form of an options array. |
2544 |
* |
2545 |
* The options array is suitable for drupal form API elements that allow multiple choices. |
2546 |
* @see http://api.drupal.org/api/drupal/developer!topics!forms_api_reference.html/7#options |
2547 |
* |
2548 |
* The classifications are ordered alphabetically whereas the classification |
2549 |
* chosen as default will always appear on top of the array, followed by a |
2550 |
* blank line below. |
2551 |
* |
2552 |
* @param bool $add_none_option |
2553 |
* is true an addtional 'none' option will be added, optional parameter, defaults to FALSE |
2554 |
* |
2555 |
* @return array |
2556 |
* classifications in an array as options for a form element that allows multiple choices. |
2557 |
*/ |
2558 |
function cdm_get_taxontrees_as_options($add_none_option = FALSE) { |
2559 |
|
2560 |
$taxonTrees = cdm_ws_fetch_all(CDM_WS_PORTAL_TAXONOMY); |
2561 |
|
2562 |
$default_classification_uuid = variable_get(CDM_TAXONOMICTREE_UUID, FALSE); |
2563 |
$default_classification_label = ''; |
2564 |
|
2565 |
// add all classifications |
2566 |
$taxonomic_tree_options = array(); |
2567 |
if ($add_none_option) { |
2568 |
$taxonomic_tree_options['NONE'] = ' '; // one Space character at beginning to force on top; |
2569 |
} |
2570 |
if ($taxonTrees) { |
2571 |
foreach ($taxonTrees as $tree) { |
2572 |
if (!$default_classification_uuid || $default_classification_uuid != $tree->uuid) { |
2573 |
$taxonomic_tree_options[$tree->uuid] = $tree->titleCache; |
2574 |
} else { |
2575 |
$taxonomic_tree_options[$tree->uuid] = ' '; // two Space characters to force on top but below 'none' option , will be replaced below by titleCache |
2576 |
$default_classification_label = $tree->titleCache; |
2577 |
} |
2578 |
} |
2579 |
} |
2580 |
// oder alphabetically the space |
2581 |
asort($taxonomic_tree_options); |
2582 |
|
2583 |
// now set the labels |
2584 |
// for none |
2585 |
if ($add_none_option) { |
2586 |
$taxonomic_tree_options['NONE'] =t('--- ALL ---'); |
2587 |
} |
2588 |
|
2589 |
// for default_classification |
2590 |
if (is_uuid($default_classification_uuid)) { |
2591 |
$taxonomic_tree_options[$default_classification_uuid] = |
2592 |
$default_classification_label ? $default_classification_label : '--- INVALID CHOICE ---' |
2593 |
. (count($taxonTrees) > 1 ? ' [' . t('DEFAULT CLASSIFICATION') . ']': ''); |
2594 |
} |
2595 |
|
2596 |
return $taxonomic_tree_options; |
2597 |
} |
2598 |
|
2599 |
/** |
2600 |
* @todo Please document this function. |
2601 |
* @see http://drupal.org/node/1354 |
2602 |
*/ |
2603 |
function cdm_api_secref_cache_prefetch(&$secUuids) { |
2604 |
// Comment @WA: global variables should start with a single underscore |
2605 |
// followed by the module and another underscore. |
2606 |
global $_cdm_api_secref_cache; |
2607 |
if (!is_array($_cdm_api_secref_cache)) { |
2608 |
$_cdm_api_secref_cache = array(); |
2609 |
} |
2610 |
$uniqueUuids = array_unique($secUuids); |
2611 |
$i = 0; |
2612 |
$param = ''; |
2613 |
while ($i++ < count($uniqueUuids)) { |
2614 |
$param .= $secUuids[$i] . ','; |
2615 |
if (strlen($param) + 37 > 2000) { |
2616 |
_cdm_api_secref_cache_add($param); |
2617 |
$param = ''; |
2618 |
} |
2619 |
} |
2620 |
if ($param) { |
2621 |
_cdm_api_secref_cache_add($param); |
2622 |
} |
2623 |
} |
2624 |
|
2625 |
/** |
2626 |
* @todo Please document this function. |
2627 |
* @see http://drupal.org/node/1354 |
2628 |
*/ |
2629 |
function cdm_api_secref_cache_get($secUuid) { |
2630 |
global $_cdm_api_secref_cache; |
2631 |
if (!is_array($_cdm_api_secref_cache)) { |
2632 |
$_cdm_api_secref_cache = array(); |
2633 |
} |
2634 |
if (!array_key_exists($secUuid, $_cdm_api_secref_cache)) { |
2635 |
_cdm_api_secref_cache_add($secUuid); |
2636 |
} |
2637 |
return $_cdm_api_secref_cache[$secUuid]; |
2638 |
} |
2639 |
|
2640 |
/** |
2641 |
* @todo Please document this function. |
2642 |
* @see http://drupal.org/node/1354 |
2643 |
*/ |
2644 |
function cdm_api_secref_cache_clear() { |
2645 |
global $_cdm_api_secref_cache; |
2646 |
$_cdm_api_secref_cache = array(); |
2647 |
} |
2648 |
|
2649 |
|
2650 |
/** |
2651 |
* @todo Please document this function. |
2652 |
* @see http://drupal.org/node/1354 |
2653 |
*/ |
2654 |
function _cdm_api_secref_cache_add($secUuidsStr) { |
2655 |
global $_cdm_api_secref_cache; |
2656 |
$ref = cdm_ws_get(CDM_WS_REFERENCE, $secUuidsStr); |
2657 |
// Batch fetching not jet reimplemented thus: |
2658 |
/* |
2659 |
$assocRefSTOs = array(); if($refSTOs) { foreach($refSTOs as $ref){ |
2660 |
$assocRefSTOs[$ref->uuid] = $ref; } $_cdm_api_secref_cache = |
2661 |
array_merge($_cdm_api_secref_cache, $assocRefSTOs); } |
2662 |
*/ |
2663 |
$_cdm_api_secref_cache[$ref->uuid] = $ref; |
2664 |
} |
2665 |
|
2666 |
/** |
2667 |
* Checks if the given uri starts with a cdm webservice url. |
2668 |
* |
2669 |
* Checks if the uri starts with the cdm webservice url stored in the |
2670 |
* Drupal variable 'cdm_webservice_url'. |
2671 |
* The 'cdm_webservice_url' can be set in the admins section of the portal. |
2672 |
* |
2673 |
* @param string $uri |
2674 |
* The URI to test. |
2675 |
* |
2676 |
* @return bool |
2677 |
* True if the uri starts with a cdm webservice url. |
2678 |
*/ |
2679 |
function _is_cdm_ws_uri($uri) { |
2680 |
return str_beginsWith($uri, variable_get('cdm_webservice_url', '#EMPTY#')); |
2681 |
} |
2682 |
|
2683 |
/** |
2684 |
* @todo Please document this function. |
2685 |
* @see http://drupal.org/node/1354 |
2686 |
*/ |
2687 |
function queryString($elements) { |
2688 |
$query = ''; |
2689 |
foreach ($elements as $key => $value) { |
2690 |
if (is_array($value)) { |
2691 |
foreach ($value as $v) { |
2692 |
$query .= (strlen($query) > 0 ? '&' : '') . $key . '=' . urlencode($v); |
2693 |
} |
2694 |
} |
2695 |
else { |
2696 |
$query .= (strlen($query) > 0 ? '&' : '') . $key . '=' . urlencode($value); |
2697 |
} |
2698 |
} |
2699 |
return $query; |
2700 |
} |
2701 |
|
2702 |
/** |
2703 |
* Implementation of the magic method __clone to allow deep cloning of objects |
2704 |
* and arrays. |
2705 |
*/ |
2706 |
function __clone() { |
2707 |
foreach ($this as $name => $value) { |
2708 |
if (gettype($value) == 'object' || gettype($value) == 'array') { |
2709 |
$this->$name = clone($this->$name); |
2710 |
} |
2711 |
} |
2712 |
} |
2713 |
|
2714 |
/** |
2715 |
* Compares the given CDM Term instances by the representationL10n. |
2716 |
* |
2717 |
* Can also be used with TermDTOs. To be used in usort() |
2718 |
* |
2719 |
* @see http://php.net/manual/en/function.usort.php |
2720 |
* |
2721 |
* @param $term1 |
2722 |
* The first CDM Term instance |
2723 |
* @param $term2 |
2724 |
* The second CDM Term instance |
2725 |
* @return int |
2726 |
* The result of the comparison |
2727 |
*/ |
2728 |
function compare_terms_by_representationL10n($term1, $term2) { |
2729 |
|
2730 |
if (!isset($term1->representation_L10n)) { |
2731 |
$term1->representationL10n = ''; |
2732 |
} |
2733 |
if (!isset($term2->representation_L10n)) { |
2734 |
$term2->representationL10n = ''; |
2735 |
} |
2736 |
|
2737 |
return strcmp($term1->representation_L10n, $term2->representation_L10n); |
2738 |
} |
2739 |
|
2740 |
function compare_terms_by_order_index($term1, $term2) { |
2741 |
|
2742 |
|
2743 |
if (!isset($term1->orderIndex)) { |
2744 |
$a = 0; |
2745 |
} else { |
2746 |
$a = $term1->orderIndex; |
2747 |
} |
2748 |
if (!isset($term2->orderIndex)) { |
2749 |
$b = 0; |
2750 |
} else { |
2751 |
$b = $term2->orderIndex; |
2752 |
} |
2753 |
|
2754 |
if ($a == $b) { |
2755 |
return 0; |
2756 |
} |
2757 |
return ($a < $b) ? -1 : 1; |
2758 |
|
2759 |
} |
2760 |
|
2761 |
|
2762 |
/** |
2763 |
* Make a 'deep copy' of an array. |
2764 |
* |
2765 |
* Make a complete deep copy of an array replacing |
2766 |
* references with deep copies until a certain depth is reached |
2767 |
* ($maxdepth) whereupon references are copied as-is... |
2768 |
* |
2769 |
* @see http://us3.php.net/manual/en/ref.array.php |
2770 |
* |
2771 |
* @param array $array |
2772 |
* @param array $copy passed by reference |
2773 |
* @param int $maxdepth |
2774 |
* @param int $depth |
2775 |
*/ |
2776 |
function array_deep_copy(&$array, &$copy, $maxdepth = 50, $depth = 0) { |
2777 |
if ($depth > $maxdepth) { |
2778 |
$copy = $array; |
2779 |
return; |
2780 |
} |
2781 |
if (!is_array($copy)) { |
2782 |
$copy = array(); |
2783 |
} |
2784 |
foreach ($array as $k => &$v) { |
2785 |
if (is_array($v)) { |
2786 |
array_deep_copy($v, $copy[$k], $maxdepth, ++$depth); |
2787 |
} |
2788 |
else { |
2789 |
$copy[$k] = $v; |
2790 |
} |
2791 |
} |
2792 |
} |
2793 |
|
2794 |
/** |
2795 |
* Concatenated the uuids of the passed cdm entity with `,` as glue. |
2796 |
* The returned string is suitable for cdm webservices consuming UUIDList as |
2797 |
* parameter |
2798 |
* |
2799 |
* @param array $cdm_entities |
2800 |
* |
2801 |
* @return string |
2802 |
*/ |
2803 |
function cdm_uuid_list_parameter_value(array $cdm_entities){ |
2804 |
$uuids = []; |
2805 |
foreach ($cdm_entities as $entity){ |
2806 |
if(isset($entity) && is_uuid($entity->uuid) ){ |
2807 |
$uuids[] = $entity->uuid; |
2808 |
} |
2809 |
} |
2810 |
return join(',', $uuids); |
2811 |
} |
2812 |
|
2813 |
/** |
2814 |
* Adds java script to create and enable a toggler for the cdm webservice debug block content. |
2815 |
* |
2816 |
*/ |
2817 |
function _add_js_ws_debug() { |
2818 |
|
2819 |
$data_tables_js = '/js/DataTables-1.9.4/media/js/jquery.dataTables.min.js'; |
2820 |
$colorbox_js = '/js/colorbox/jquery.colorbox-min.js'; |
2821 |
if (variable_get('cdm_js_devel_mode', FALSE)) { |
2822 |
// use the developer versions of js libs |
2823 |
$data_tables_js = '/js/DataTables-1.9.4/media/js/jquery.dataTables.js'; |
2824 |
$colorbox_js = '/js/colorbox/jquery.colorbox.js'; |
2825 |
} |
2826 |
drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . $data_tables_js, |
2827 |
array( |
2828 |
'type' => 'file', |
2829 |
'weight' => JS_LIBRARY, |
2830 |
'cache' => TRUE) |
2831 |
); |
2832 |
|
2833 |
drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . $colorbox_js, |
2834 |
array( |
2835 |
'type' => 'file', |
2836 |
'weight' => JS_LIBRARY, |
2837 |
'cache' => TRUE) |
2838 |
); |
2839 |
drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/js/colorbox/colorbox.css'); |
2840 |
drupal_add_css(drupal_get_path('module', 'cdm_dataportal') . '/js/DataTables-1.9.4/media/css/cdm_debug_table.css'); |
2841 |
|
2842 |
drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/ws_debug_block.js', |
2843 |
array( |
2844 |
'type' => 'file', |
2845 |
'weight' => JS_LIBRARY, |
2846 |
'cache' => TRUE) |
2847 |
); |
2848 |
drupal_add_js(drupal_get_path('module', 'cdm_dataportal') . '/js/http-method-link.js', |
2849 |
array( |
2850 |
'type' => 'file', |
2851 |
'weight' => JS_LIBRARY, |
2852 |
'cache' => TRUE) |
2853 |
); |
2854 |
|
2855 |
} |
2856 |
|
2857 |
/** |
2858 |
* @todo Please document this function. |
2859 |
* @see http://drupal.org/node/1354 |
2860 |
*/ |
2861 |
function _no_classfication_uuid_message() { |
2862 |
if (!cdm_ws_get(CDM_WS_PORTAL_TAXONOMY)) { |
2863 |
return t('This DataPortal is not configured properly or the CDM-Server may be absent.') . ' Please check the ' . l(t('CDM web service URL'), 'admin/config/cdm_dataportal/settings/general') . t(', or contact the maintainer of this DataPortal.'); |
2864 |
} |
2865 |
return t('This DataPortal is not configured properly.') . l(t('Please choose a valid classification'), 'admin/config/cdm_dataportal/settings/general') . t(', or contact the maintainer of this DataPortal.'); |
2866 |
} |
2867 |
|
2868 |
/** |
2869 |
* Implementation of hook flush_caches |
2870 |
* |
2871 |
* Add custom cache tables to the list of cache tables that |
2872 |
* will be cleared by the Clear button on the Performance page or whenever |
2873 |
* drupal_flush_all_caches is invoked. |
2874 |
* |
2875 |
* @author W.Addink <waddink@eti.uva.nl> |
2876 |
* |
2877 |
* @return array |
2878 |
* An array with custom cache tables to include. |
2879 |
*/ |
2880 |
function cdm_api_flush_caches() { |
2881 |
return array('cache_cdm_ws'); |
2882 |
} |
2883 |
|
2884 |
/** |
2885 |
* Logs if the drupal variable 'cdm_debug_mode' ist set true to drupal_debug.txt in the site's temp directory. |
2886 |
* |
2887 |
* @param $data |
2888 |
* The variable to log to the drupal_debug.txt log file. |
2889 |
* @param $label |
2890 |
* (optional) If set, a label to output before $data in the log file. |
2891 |
* |
2892 |
* @return |
2893 |
* No return value if successful, FALSE if the log file could not be written |
2894 |
* to. |
2895 |
* |
2896 |
* @see cdm_dataportal_init() where the log file is reset on each requests |
2897 |
* @see dd() |
2898 |
* @see http://drupal.org/node/314112 |
2899 |
* |
2900 |
*/ |
2901 |
function cdm_dd($data, $label = NULL) { |
2902 |
if(module_exists('devel') && variable_get('cdm_debug_mode', FALSE) && file_stream_wrapper_get_class('temporary') ){ |
2903 |
return dd($data, $label); |
2904 |
} |
2905 |
} |
2906 |
|