cdm-dataportal / modules / cdm_dataportal / includes / common.inc @ 7212f0bc
History | View | Annotate | Download (17.1 KB)
1 |
<?php |
---|---|
2 |
/** |
3 |
* @file |
4 |
* Functions for dealing with CDM entities from the package model.common |
5 |
* |
6 |
* @copyright |
7 |
* (C) 2007-2012 EDIT |
8 |
* European Distributed Institute of Taxonomy |
9 |
* http://www.e-taxonomy.eu |
10 |
* |
11 |
* The contents of this module are subject to the Mozilla |
12 |
* Public License Version 1.1. |
13 |
* @see http://www.mozilla.org/MPL/MPL-1.1.html |
14 |
* |
15 |
* @author |
16 |
* - Andreas Kohlbecker <a.kohlbecker@BGBM.org> |
17 |
*/ |
18 |
|
19 |
/** |
20 |
* @defgroup compose Compose functions |
21 |
* @{ |
22 |
* Functions which are composing Drupal render arays |
23 |
* |
24 |
* The cdm_dataportal module needs to compose rather complex render arrays from |
25 |
* the data returned by the CDM REST service. The compose functions are |
26 |
* responsible for creating the render arrays. |
27 |
* |
28 |
* All these functions are also implementations of the compose_hook() |
29 |
* which is used in the proxy_content() function. |
30 |
* @} |
31 |
*/ |
32 |
|
33 |
/** |
34 |
* Compose an render array from a CDM Marker object. |
35 |
* |
36 |
* compose_hook() implementation |
37 |
* |
38 |
* @param object $marker |
39 |
* CDM instance of type Marker |
40 |
* @return array |
41 |
* A drupal render array |
42 |
* |
43 |
* @ingroup compose |
44 |
*/ |
45 |
function compose_cdm_marker($marker) { |
46 |
|
47 |
$render_array = array( |
48 |
// ---- generic |
49 |
// these entries should be common to all cdm enitiy render arrays |
50 |
'#theme' => 'cdm_marker', // TODO add alternative theme funcitons: 'cdm_marker_' . marker.type.label |
51 |
'#attributes' => array('class' => html_class_attribute_ref($marker)), |
52 |
|
53 |
// ---- individual |
54 |
'#label' => $marker->markerType->representation_L10n . ': ' . (($marker->flag !== TRUE ? t('yes') : t('no'))), |
55 |
); |
56 |
|
57 |
return $render_array; |
58 |
} |
59 |
|
60 |
/** |
61 |
* Checks if the given $cdm_entitiy has a marker the type references by the |
62 |
* $marker_type_uuid and returns TRUE if a matching marker has been found. |
63 |
* |
64 |
* @param object $cdm_entitiy A CDM Entity |
65 |
* @param string $marker_type_uuid |
66 |
*/ |
67 |
function cdm_entity_has_marker($cdm_entitiy, $marker_type_uuid) { |
68 |
if(isset($cdm_entitiy->markers[0]) && !is_uuid($marker_type_uuid)){ |
69 |
foreach ($cdm_entitiy->markers as $marker) { |
70 |
if(isset($marker->markerType) && $marker->markerType->uuid == $marker_type_uuid){ |
71 |
return TRUE; |
72 |
} |
73 |
} |
74 |
} |
75 |
return FALSE; |
76 |
} |
77 |
|
78 |
/** |
79 |
* Sorts an array of CDM IdentifiableSource instances by 1. by the |
80 |
* author teams family names and 2. by the publication date. |
81 |
* |
82 |
* @param array $sources |
83 |
* The array of CDM IdentifiableSource instances |
84 |
* @param bool $do_theme if set TRUE the sources will be themed |
85 |
* by theme_cdm_OriginalSource |
86 |
* @return multitype: |
87 |
*/ |
88 |
function oder_sources($sources, $do_theme = false){ |
89 |
$sort_array = array(); |
90 |
foreach ($sources as $source) { |
91 |
|
92 |
$order_key = ''; |
93 |
|
94 |
// find the familynames |
95 |
if(isset($source->citation->uuid) && !isset($source->citation->authorship)){ |
96 |
$authorteam = cdm_ws_get(CDM_WS_REFERENCE_AUTHORTEAM, $source->citation->uuid); |
97 |
|
98 |
$persons = array(); |
99 |
if($authorteam->class == 'Team'){ |
100 |
if(isset($authorteam->teamMembers)){ |
101 |
$persons = $authorteam->teamMembers; |
102 |
} |
103 |
} else { |
104 |
$persons[] = $authorteam; |
105 |
} |
106 |
|
107 |
foreach($persons as $person){ |
108 |
if(!empty($person->lastname)){ |
109 |
$order_key .= $person->lastname; |
110 |
} else { |
111 |
$order_key .= $person->titleCache; |
112 |
} |
113 |
} |
114 |
if(empty($order_key)){ |
115 |
$order_key = $authorteam->titleCache; |
116 |
} |
117 |
|
118 |
} |
119 |
$order_key = str_pad($order_key, 50); |
120 |
|
121 |
// add publication date to the key |
122 |
if(isset($source->citation->datePublished)){ |
123 |
$order_key .= '_' . timePeriodAsOrderKey($source->citation->datePublished); |
124 |
} else { |
125 |
$order_key .= '_' . "0000"; |
126 |
} |
127 |
|
128 |
// padd key until unique |
129 |
while(array_key_exists($order_key, $sort_array)){ |
130 |
$order_key .= "_"; |
131 |
} |
132 |
|
133 |
|
134 |
if($do_theme) { |
135 |
$sort_array[$order_key] = theme('cdm_OriginalSource', array('source' => $source)); |
136 |
} else { |
137 |
$sort_array[$order_key] = $source; |
138 |
} |
139 |
} |
140 |
ksort($sort_array); |
141 |
return array_values ($sort_array); |
142 |
} |
143 |
|
144 |
/** |
145 |
* Compare callback to be used in usort to sort image sources of CDM OriginalSource instances. |
146 |
* |
147 |
* TODO the compare strategy implemented in oder_sources() is probably better but is not taking the |
148 |
* originalName into account. |
149 |
* |
150 |
* @param $a |
151 |
* @param $b |
152 |
*/ |
153 |
function compare_original_sources($a, $b){ |
154 |
|
155 |
$a_string = ''; |
156 |
if(isset($a->citation->titleCache)) { |
157 |
$a_string = $a->citation->titleCache; |
158 |
} |
159 |
if((isset($a->nameUsedInSource))){ |
160 |
$a_string .= $a->nameUsedInSource->titleCache; |
161 |
} elseif (isset($a->originalNameString)){ |
162 |
$a_string .= $a->originalNameString; |
163 |
} |
164 |
|
165 |
$b_string = ''; |
166 |
if(isset($b->citation->titleCache)) { |
167 |
$b_string = $b->citation->titleCache; |
168 |
}; |
169 |
if((isset($b->nameUsedInSource))){ |
170 |
$b_string .= $b->nameUsedInSource->titleCache; |
171 |
} elseif (isset($b->originalNameString)){ |
172 |
$b_string .= $b->originalNameString; |
173 |
} |
174 |
|
175 |
if ($a_string == $b_string) { |
176 |
return 0; |
177 |
} |
178 |
return ($a_string < $b_string) ? -1 : 1; |
179 |
} |
180 |
|
181 |
/** |
182 |
* Compare callback to be used in usort to sort image sources of CDM Media instances. |
183 |
* |
184 |
* @param $a |
185 |
* @param $b |
186 |
*/ |
187 |
function compare_text_data($a, $b) { |
188 |
|
189 |
if ($a->multilanguageText_L10n->text == $b->multilanguageText_L10n->text) { |
190 |
return 0; |
191 |
} |
192 |
return ($a->multilanguageText_L10n->text < $b->multilanguageText_L10n->text) ? -1 : 1; |
193 |
} |
194 |
|
195 |
/** |
196 |
* Compare two different footnotes objects. |
197 |
* |
198 |
* The comparison is based on the footnote key. The one which is |
199 |
* displayed as footnote number. |
200 |
* |
201 |
* @param mixed $a |
202 |
* Footnote object $a. |
203 |
* @param mixed $b |
204 |
* Footnote object $b. |
205 |
*/ |
206 |
function footnotes_key_compare($a, $b) { |
207 |
$res = 0; |
208 |
if (empty($a) || empty($b)) { |
209 |
return $res; |
210 |
} |
211 |
if ($a->keyStr < $b->keyStr) { |
212 |
$res = -1; |
213 |
} |
214 |
elseif ($a->keyStr > $b->keyStr) { |
215 |
$res = 1; |
216 |
} |
217 |
return $res; |
218 |
} |
219 |
|
220 |
|
221 |
/** |
222 |
* Creates an array suitable to be used in min_max_markup() |
223 |
* |
224 |
* @return array |
225 |
*/ |
226 |
function min_max_array() |
227 |
{ |
228 |
// FIXME use UUIDs instead? how about idInVocab? |
229 |
$min_max = array( |
230 |
'Extreme Min' => NULL, |
231 |
'Min' => NULL, |
232 |
'Average' => NULL, |
233 |
'Max' => NULL, |
234 |
'Extreme Max' => NULL, |
235 |
); |
236 |
return $min_max; |
237 |
} |
238 |
|
239 |
/** |
240 |
* Creates markup from a min max array. |
241 |
* |
242 |
* NOTE: use min_max_array() to create an appropriate array |
243 |
* |
244 |
* @param $min_max |
245 |
* the min-max array |
246 |
* @param $unit |
247 |
* Defaults to no unit |
248 |
* @return string |
249 |
*/ |
250 |
function min_max_markup($min_max, $unit = '') { |
251 |
|
252 |
$min_max_markup = ''; |
253 |
// create min-max string |
254 |
if ($min_max['Min'] !== NULL && $min_max['Max'] !== NULL && $min_max['Min']->_value == $min_max['Max']->_value) { |
255 |
// min and max are identical |
256 |
$min_max['Average'] = $min_max['Min']; |
257 |
$min_max['Min'] = NULL; |
258 |
$min_max['Max'] = NULL; |
259 |
} |
260 |
|
261 |
// check for inconsistent cases, eg. only Max and average given |
262 |
if ($min_max['Min'] === NULL && $min_max['Max'] !== NULL) { |
263 |
// min missing |
264 |
$min_max['Min'] = '?'; |
265 |
} |
266 |
if ($min_max['Min'] !== NULL && $min_max['Max'] === NULL) { |
267 |
// max missing |
268 |
$min_max['Max'] = '?'; |
269 |
} |
270 |
|
271 |
|
272 |
foreach ($min_max as $key => $statistical_val) { |
273 |
if ($statistical_val !== NULL) { |
274 |
|
275 |
if ($statistical_val == '?') { |
276 |
$val_markup = $statistical_val; |
277 |
} else { |
278 |
$val_markup = '<span class="' |
279 |
. html_class_attribute_ref($statistical_val) . ' ' |
280 |
. (isset($statistical_val->type) ? $statistical_val->type->termType : '') . ' ">' |
281 |
. $statistical_val->_value . '</span>'; |
282 |
} |
283 |
|
284 |
if (strlen($min_max_markup)) { |
285 |
$min_max_markup .= '–'; |
286 |
} |
287 |
if (str_beginsWith($key, 'Extreme')) { |
288 |
$val_markup = "($val_markup)"; |
289 |
} |
290 |
$min_max_markup .= $val_markup; |
291 |
} |
292 |
} |
293 |
return $min_max_markup . ' ' . $unit; |
294 |
} |
295 |
|
296 |
/** |
297 |
* Creates min max markup to represent a min-average-max measure optionally with an error value. |
298 |
* |
299 |
* The fields that are taken into account are: |
300 |
* - field_base_name = min |
301 |
* - field_base_nameMax = max |
302 |
* - field_base_nameText = free text |
303 |
* - field_base_nameError = error value |
304 |
* |
305 |
* @param $object |
306 |
* The object having min max measurement fields |
307 |
* @param string $field_base_name |
308 |
* The base name for all measurement fields. This name is at the same time the full name of the |
309 |
* min value. |
310 |
* @return string |
311 |
* The markup for the min max |
312 |
*/ |
313 |
function min_max_measure($object, $field_base_name) |
314 |
{ |
315 |
static $default_unit = 'm'; |
316 |
|
317 |
$field_name = $field_base_name . 'Text'; |
318 |
if (@is_string($object->$field_name)) { |
319 |
// Freetext overrides all other data |
320 |
$min_max_markup = ' ' . $object->$field_name; |
321 |
} else { |
322 |
// create markup for the atomized min max data |
323 |
$min_max_array = min_max_array(); |
324 |
if (@is_numeric($object->$field_base_name)) { |
325 |
$min_max_array['Min'] = new stdClass(); |
326 |
$min_max_array['Min']->_value = $object->$field_base_name; |
327 |
} |
328 |
$field_name = $field_base_name . 'Max'; |
329 |
if (@is_numeric($object->$field_name)) { |
330 |
$min_max_array['Max'] = new stdClass(); |
331 |
$min_max_array['Max']->_value = $object->$field_name; |
332 |
} |
333 |
$min_max_markup = min_max_markup($min_max_array, $default_unit); |
334 |
} |
335 |
|
336 |
return $min_max_markup; |
337 |
} |
338 |
|
339 |
// TODO move below code into new file: agent.inc |
340 |
|
341 |
/* |
342 |
* Compose an render array from a CDM TaxonNodeAgentRelation object as Taxon Expert. |
343 |
* |
344 |
* compose_hook() implementation |
345 |
* |
346 |
* @param object $taxon_node_agent_relation |
347 |
* CDM instance of type TaxonNodeAgentRelation |
348 |
* @return array |
349 |
* A drupal render array |
350 |
* |
351 |
* @ingroup compose |
352 |
*/ |
353 |
function compose_cdm_taxon_expert($taxon_node_agent_relation) { |
354 |
|
355 |
$label_suffix = ':'; |
356 |
|
357 |
if($taxon_node_agent_relation->class == 'DefaultPagerImpl'){ |
358 |
// oops this is a pager |
359 |
// this situation will occur when this compose is executed |
360 |
// through the proxy_content() method |
361 |
$taxon_node_agent_relation = $taxon_node_agent_relation->records[0]; |
362 |
|
363 |
} |
364 |
|
365 |
if(is_object($taxon_node_agent_relation->agent)) { |
366 |
$agent_details = compose_cdm_team_or_person_base($taxon_node_agent_relation->agent); |
367 |
// all data will be added to the groups of the agent_details render array |
368 |
$groups = &$agent_details[0]['#groups']; |
369 |
|
370 |
@_description_list_group_add($groups, t('Role'). $label_suffix, $taxon_node_agent_relation->type->representation_L10n); |
371 |
|
372 |
$family_tnars = cdm_ws_fetch_all(CDM_WS_PORTAL_AGENT . '/' . $taxon_node_agent_relation->agent->uuid . '/taxonNodeAgentRelations', array("rank"=>"Familia")); |
373 |
|
374 |
$taxa_markup = array( |
375 |
'#theme_wrappers' => array('container'), |
376 |
'#attributes' => array('class' => array('managed_taxa')), |
377 |
'#wrapper_attributes' => array('class' => 'sublist-container') |
378 |
); |
379 |
foreach($family_tnars as $tnar){ |
380 |
if(is_object($tnar->taxonNode->taxon)){ |
381 |
$taxa_markup[$tnar->taxonNode->taxon->titleCache] = markup_to_render_array(render_taxon_or_name($tnar->taxonNode->taxon, url(path_to_taxon($tnar->taxonNode->taxon->uuid)))); |
382 |
} |
383 |
} |
384 |
ksort($taxa_markup); |
385 |
|
386 |
@_description_list_group_add($groups, t('Families'). $label_suffix, array($taxa_markup)); |
387 |
|
388 |
} |
389 |
|
390 |
return $agent_details; |
391 |
} |
392 |
|
393 |
|
394 |
/* |
395 |
* Compose an render array from a CDM TeamOrPersonBase object. |
396 |
* |
397 |
* compose_hook() implementation |
398 |
* |
399 |
* TODO: currently mainly implemented for Agent, add Team details |
400 |
* |
401 |
* @param object $team_or_person |
402 |
* CDM instance of type TeamOrPersonBase |
403 |
* @return array |
404 |
* A drupal render array |
405 |
* |
406 |
* @ingroup compose |
407 |
*/ |
408 |
function compose_cdm_team_or_person_base($team_or_person, $data = array()) { |
409 |
|
410 |
$groups = array(); |
411 |
|
412 |
$label_suffix = ':'; |
413 |
|
414 |
// $weight = 0; |
415 |
if($team_or_person){ |
416 |
|
417 |
if(is_object($team_or_person->lifespan)){ |
418 |
// ToDo render as date* - date† ? |
419 |
@_description_list_group_add($groups, t('Lifespan'). $label_suffix, timePeriodToString($team_or_person->lifespan) /*, '' , $weight++ */); |
420 |
} |
421 |
|
422 |
// nomenclaturalTitle |
423 |
@_description_list_group_add($groups, "Nomenclatural Title". $label_suffix, $team_or_person->nomenclaturalTitle); |
424 |
// collectorTitle |
425 |
@_description_list_group_add($groups, "Collector Title". $label_suffix, $team_or_person->collectorTitle); |
426 |
|
427 |
// institutionalMemberships |
428 |
if(is_array($team_or_person->institutionalMemberships)){ |
429 |
|
430 |
$institutes_ra = array(); |
431 |
foreach($team_or_person->institutionalMemberships as $membership) { |
432 |
$membership_groups = array(); |
433 |
@_description_list_group_add($membership_groups, t('Department'). $label_suffix, $membership->department); |
434 |
@_description_list_group_add($membership_groups, t('Role'). $label_suffix, $membership->role); |
435 |
if(is_object($membership->period)){ |
436 |
@_description_list_group_add($membership_groups, t('Period'). $label_suffix, timePeriodToString($membership->period)); |
437 |
} |
438 |
if(is_object($membership->institute->contact)){ |
439 |
$institute_contact_details = compose_cdm_contact($membership->institute->contact, $membership->institute->titleCache); |
440 |
if(is_array($institute_contact_details[0]['#groups'])){ |
441 |
$membership_groups = array_merge($membership_groups, $institute_contact_details[0]['#groups']); |
442 |
} |
443 |
} |
444 |
if(count($membership_groups) > 0){ |
445 |
$institutes_ra[] = array( |
446 |
'#title' => $membership->institute->titleCache, |
447 |
'#theme' => 'description_list', |
448 |
'#groups' => $membership_groups, |
449 |
'#attributes' => array('class' => html_class_attribute_ref($membership)), |
450 |
'#wrapper_attributes' => array('class' => 'sublist-container') |
451 |
); |
452 |
} else { |
453 |
// no further details for the membership, display the title |
454 |
$institutes_ra[] = markup_to_render_array('<h3>' . $membership->institute->titleCache . '</h3>'); |
455 |
} |
456 |
|
457 |
} |
458 |
|
459 |
$label = count($institutes_ra) > 1 ? t('Institutes'): t('Institute'); |
460 |
@_description_list_group_add($groups, $label. $label_suffix, $institutes_ra /*, '' , $weight++ */); |
461 |
} |
462 |
|
463 |
|
464 |
// Contact |
465 |
$agent_contact_details = compose_cdm_contact($team_or_person->contact, $team_or_person->titleCache); |
466 |
if(is_array($agent_contact_details[0]['#groups'])){ |
467 |
$groups = array_merge($groups, $agent_contact_details[0]['#groups']); |
468 |
} |
469 |
|
470 |
// additional data |
471 |
foreach($data as $key=>$value){ |
472 |
@_description_list_group_add($sub_dl_groups, t('@key', array('@key' => $key)), $value /*, '' , $weight++ */); |
473 |
} |
474 |
|
475 |
} |
476 |
|
477 |
$team_or_person_details = array( |
478 |
'#title' => $team_or_person->titleCache, |
479 |
'#theme' => 'description_list', |
480 |
'#groups' => $groups, |
481 |
'#attributes' => array('class' => html_class_attribute_ref($team_or_person)), |
482 |
); |
483 |
return array($team_or_person_details); |
484 |
} |
485 |
|
486 |
|
487 |
/* |
488 |
* Compose an render array from a CDM Contact object. |
489 |
* |
490 |
* compose_hook() implementation |
491 |
* |
492 |
* TODO: currently mainly implemented for Agent, add Team details |
493 |
* |
494 |
* @param object $contact |
495 |
* CDM instance of type Contact |
496 |
* @param $title |
497 |
* The title for the description list header |
498 |
* @param $weight |
499 |
* Optional weight for the description list entries |
500 |
* @return array |
501 |
* A drupal render array |
502 |
* |
503 |
* @ingroup compose |
504 |
*/ |
505 |
function compose_cdm_contact($contact, $title, $weight = 0) |
506 |
{ |
507 |
|
508 |
$groups = array(); |
509 |
|
510 |
$contact_details = null; |
511 |
|
512 |
$label_suffix = ':'; |
513 |
|
514 |
$contact_field_names_map = array( |
515 |
'emailAddresses' => t('Email'), |
516 |
'urls' => t('Urls'), |
517 |
'phoneNumbers' => t('Phone'), |
518 |
'faxNumbers' => t('Fax'), |
519 |
); |
520 |
|
521 |
// Contact |
522 |
if(is_object($contact)){ |
523 |
if(isset($contact->addresses)){ |
524 |
// TODO .... |
525 |
// $sub_groups = array(); |
526 |
// foreach($contact->addresses as $address){ |
527 |
// @_description_list_group_add($sub_groups, $label, $contact->$fieldName, '', $weight++); |
528 |
// } |
529 |
} |
530 |
foreach($contact_field_names_map as $fieldName => $label){ |
531 |
if(is_array($contact->$fieldName)){ |
532 |
@_description_list_group_add($groups, $label . $label_suffix, $contact->$fieldName, '', $weight++); |
533 |
} |
534 |
} |
535 |
$contact_details = array( |
536 |
'#title' => $title, |
537 |
'#theme' => 'description_list', |
538 |
'#groups' => $groups |
539 |
); |
540 |
|
541 |
|
542 |
} else if(is_string($title)) { |
543 |
// if the contact entity is empty but the title is given anyway |
544 |
// we are only adding the title, using the description_list |
545 |
// structure is not possible since it would be empty due to |
546 |
// missing group data |
547 |
$contact_details = array('#markup' => '<h3>' . $title . '</h3>'); |
548 |
} |
549 |
|
550 |
return array($contact_details); |
551 |
|
552 |
} |
553 |
|
554 |
/** |
555 |
* Compose an render array from a CDM Extension objects. |
556 |
* |
557 |
* @param $extensions |
558 |
* An array of CDM Extension objects |
559 |
* @return array |
560 |
* A render array containing the fields of the supplied $sequence |
561 |
* |
562 |
* @ingroup compose |
563 |
*/ |
564 |
function compose_extensions($extensions) |
565 |
{ |
566 |
$extensions_render_array= null; |
567 |
$extensions_by_type = array(); |
568 |
foreach ($extensions as $extension) { |
569 |
if (@is_string($extension->value)) { |
570 |
if (!isset($extensions_by_type[$extension->type->representation_L10n])) { |
571 |
$extensions_by_type[$extension->type->representation_L10n] = array(); |
572 |
} |
573 |
$extensions_by_type[$extension->type->representation_L10n][] = markup_to_render_array($extension->value); |
574 |
} |
575 |
} |
576 |
|
577 |
if (count($extensions_by_type)) { |
578 |
$sub_dl_groups = array(); |
579 |
foreach ($extensions_by_type as $type_label => $text_list) { |
580 |
@_description_list_group_add($sub_dl_groups, $type_label . ':', $text_list); |
581 |
} |
582 |
$extensions_render_array = array( |
583 |
array('#theme' => 'description_list', '#groups' => $sub_dl_groups) |
584 |
); |
585 |
return $extensions_render_array; |
586 |
} |
587 |
return $extensions_render_array; |
588 |
} |
589 |
|
590 |
|