Project

General

Profile

Download (63.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/**
3
 * @file
4
 * Functions for dealing with CDM entities from the package model.name
5
 *
6
 * @copyright
7
 *   (C) 2007-2015 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
/**
35
 * Provides the name render template to be used within the page elements identified the the $renderPath.
36
 *
37
 * The render templates arrays contains one or more name render templates to be used within the page elements identified the the
38
 * renderPath. The renderPath is the key of the subelements whereas the value is the name render template.
39
 *
40
 * The render paths used for a cdm_dataportal page can be visualized by supplying the HTTP query parameter RENDER_PATH=1.
41
 *
42
 * It will be tried to find  the best matching default RenderTemplate by stripping the dot separated render path
43
 * element by element. If no matching template is found the DEFAULT will be used:
44
 *
45
 * - related_taxon.heterotypicSynonymyGroup.taxon_page_synonymy
46
 * - related_taxon.heterotypicSynonymyGroup.taxon_page_synonymy
47
 * - related_taxon.heterotypicSynonymyGroup.taxon_page_synonymy
48
 *
49
 * A single render template can be used for multiple render paths. In this case the according key of the render templates
50
 * array element should be the list of these render paths concatenated by ONLY a comma character without any whitespace.
51
 *
52
 * A render template is an associative array. The keys of this array are referring to the keys as defined in the part
53
 * definitions array.
54
 * @see get_partDefinition($taxonNameType) for more information
55
 *
56
 * The value of the render template element must be set to TRUE in order to let this part being rendered.
57
 * The namePart, nameAuthorPart and referencePart can also hold an associative array with a single
58
 * element: array('#uri' => TRUE). The value of the #uri element will be replaced by the according
59
 * links if the parameters $nameLink or $refenceLink are set.
60
 *
61
 * @param string $render_path
62
 *   The render path can consist of multiple dot separated elements
63
 *   @see RenderHints::getRenderPath()
64
 * @param string $nameLink
65
 *   The link path ot URL to be used for name parts if a link is forseen in the template
66
 *   matching the given $renderPath.
67
 * @param string $referenceLink
68
 *   The link path ot URL to be used for nomenclatural reference parts if a link is forseen
69
 *   in the template matching the given $renderPath.
70
 * @return array
71
 *   An associative array, the render template
72
 */
73
function get_nameRenderTemplate($render_path, $nameLink = NULL, $referenceLink = NULL) {
74

    
75
  static $default_render_templates = NULL;
76
  static $split_render_templates = NULL;
77

    
78

    
79
  if (!isset($default_render_templates)) {
80
    $default_render_templates = unserialize(CDM_NAME_RENDER_TEMPLATES_DEFAULT);
81
  }
82
  if($split_render_templates == NULL) {
83
    $render_templates = variable_get(CDM_NAME_RENDER_TEMPLATES, $default_render_templates);
84
    // needs to be converted to an array
85
    $render_templates = (object_to_array($render_templates));
86

    
87
    // separate render templates which are combined with a comma
88
    $split_render_templates = array();
89
    foreach($render_templates as $key => $template){
90
      if(strpos($key, ',')){
91
        foreach(explode(',', $key) as $path){
92
          $split_render_templates[$path] = $template;
93
        }
94
      } else {
95
        $split_render_templates[$key] = $template;
96
      }
97
    }
98
  }
99

    
100
  // get the base element of the renderPath
101
  if (($separatorPos = strpos($render_path, '.')) > 0) {
102
    $renderPath_base = substr($render_path, 0, $separatorPos);
103
  } else {
104
    $renderPath_base = $render_path;
105
  }
106

    
107
  $template = NULL;
108
  // 1. try to find a template using the render path base element
109
  if(array_key_exists($renderPath_base, $split_render_templates)){
110
    $template = (array)$split_render_templates[$renderPath_base];
111
  }
112

    
113
  // 2. Find best matching default RenderTemplate
114
  // by stripping the dot separated render path element by element
115
  // if no matching template is found the DEFAULT will be used.
116
  while (!is_array($template) && strlen($render_path) > 0) {
117
    foreach ($split_render_templates as $path => $t) {
118
      if ($path == $render_path) {
119
        $template = $t;
120
        break;
121
      }
122
    }
123
    // shorten by one element
124
    $render_path = substr($render_path, strrpos($render_path, '.') + 1, strlen($render_path));
125
  }
126

    
127

    
128
  // 3. Otherwise get default RenderTemplate from theme.
129
  if (!is_array($template)) {
130
    $template = $split_render_templates['#DEFAULT'];
131
  }
132

    
133
  // --- set the link uris to the according template fields if they exist
134
  if(isset($template['nameAuthorPart']) && isset($template['nameAuthorPart']['#uri'])) {
135
    if ($nameLink) {
136
      $template['nameAuthorPart']['#uri'] = $nameLink;
137
    }
138
    else {
139
      unset($template['nameAuthorPart']['#uri']);
140
    }
141
  }
142

    
143
  if ($nameLink && isset($template['namePart']['#uri'])) {
144
    $template['namePart']['#uri'] = $nameLink;
145
  }
146
  else {
147
    unset($template['namePart']['#uri']);
148
  }
149

    
150
  if ($referenceLink && isset($template['referencePart']['#uri'])) {
151
    $template['referencePart']['#uri'] = $referenceLink;
152
  }
153
  else {
154
    unset($template['referencePart']['#uri']);
155
  }
156

    
157
  return $template;
158
}
159

    
160
/**
161
 * The part definitions define the specific parts of which a rendered taxon name plus additional information will consist.
162
 *
163
 * A full taxon name plus additional information can consist of the following elements:
164
 *
165
 *   - name: the taxon name inclugin rank nbut without author
166
 *   - authorTeam:  The authors of a reference, also used in taxon names
167
 *   - authors:  The authors of a reference, also used in taxon names
168
 *   - reference: the nomenclatural reference,
169
 *   - microreference:  Volume, page number etc.
170
 *   - status:  The nomenclatural status of a name
171
 *   - description: name descriptions like protologues etc ...
172
 *
173
 * These elements are combined in the part definitions array to from the specific parts to be rendered.
174
 * Usually the following parts are formed:
175
 *
176
 * The name "Lapsana communis L., Sp. Pl.: 811. 1753" shall be an example here:
177
 *  - namePart: the name and rank (in example: "Lapsana communis")
178
 *  - authorshipPart: the author (in example: "L.")
179
 *  - nameAuthorPart: the combination of name and author part (in example: "Lapsana communis L.").
180
 *     This is useful for zoological names where the authorshipPart belongs to the name and both should
181
 *     be combined when a link to the taxon is rendered.
182
 *  - referencePart: the nomencaltural reference (in example: "Sp. Pl. 1753")
183
 *  - microreferencePart: usually the page number (in example ": 811.")
184
 *  - statusPart: the nomenclatorical status
185
 *  - descriptionPart:
186
 *
187
 * Each set of parts is dedicated to render a specific TaxonName type, the type names are used as keys for the
188
 * specific parts part definitions:
189
 *
190
 *  - BotanicalName
191
 *  - ZoologicalName
192
 *  - #DEFAULT:  covers ViralNames and general NonViralNames
193
 *
194
 * An example:
195
 * @code
196
 * array(
197
 *    'ZoologicalName' => array(
198
 *        'namePart' => array('name' => TRUE),
199
 *        'referencePart' => array('authorTeam' => TRUE),
200
 *        'microreferencePart' => array('microreference' => TRUE),
201
 *        'statusPart' => array('status' => TRUE),
202
 *        'descriptionPart' => array('description' => TRUE),
203
 *    ),
204
 *    'BotanicalName' => array(
205
 *        'namePart' => array(
206
 *            'name' => TRUE,
207
 *            'authors' => TRUE,
208
 *        ),
209
 *        'referencePart' => array(
210
 *            'reference' => TRUE,
211
 *            'microreference' => TRUE,
212
 *        ),
213
 *        'statusPart' => array('status' => TRUE),
214
 *        'descriptionPart' => array('description' => TRUE),
215
 *    ),
216
 *  );
217
 * @endcode
218
 *
219
 * @param object $taxonNameType
220
 *    A cdm TaxonNameType entity
221
 *
222
 */
223
function get_partDefinition($taxonNameType) {
224

    
225
  static $default_part_definitions = null;
226
  if (!isset($default_part_definitions)) {
227
    $default_part_definitions= unserialize(CDM_PART_DEFINITIONS_DEFAULT);
228
  }
229

    
230
  static $part_definitions = null;
231
  if (!isset($part_definitions)) {
232
    $part_definitions = object_to_array(variable_get(CDM_PART_DEFINITIONS, $default_part_definitions));
233
  }
234

    
235
  $dtype = nameTypeToDTYPE($taxonNameType);
236
  if (array_key_exists($taxonNameType, $part_definitions)) {
237
    return $part_definitions[$taxonNameType];
238
  } else if (array_key_exists($dtype, $part_definitions)) {
239
    return $part_definitions[$dtype];
240
  } else {
241
    return $part_definitions['#DEFAULT']; // covers ViralNames and general NonViralNames
242
  }
243

    
244
}
245

    
246

    
247
/**
248
 * Renders the markup for a CDM TaxonName instance.
249
 *
250
 * The layout of the name representation is configured by the
251
 * part_definitions and render_templates (see get_partDefinition() and
252
 * get_nameRenderTemplate())
253
 *
254
 * @param $taxonName
255
 *    cdm TaxonName instance
256
 * @param $nameLink
257
 *    URI to the taxon, @see path_to_taxon(), must be processed by url() before passing to this method
258
 * @param $refenceLink
259
 *    URI to the reference, @see path_to_reference(), must be processed by url() before passing to this method
260
 * @param $show_annotations
261
 *    turns the display of annotations on
262
 * @param $is_type_designation
263
 *    To indicate that the supplied taxon name is a name type designation.
264
 * @param $skiptags
265
 *    an array of name elements tags like 'name', 'rank' to skip. The name part
266
 *          'authors' will not ber affected by this filter. This part is managed though the render template
267
 *          mechanism.
268
 * @param $is_invalid
269
 *   Indicates that this taxon is invalid. In this case the name part will be shown in double quotes.
270
 *   This is useful when rendering taxon relation ships.
271
 *
272
 * @return string
273
 *  The markup for a taxon name.
274
 *
275
 */
276
function render_taxon_or_name($taxon_name_or_taxon_base, $nameLink = NULL, $refenceLink = NULL,
277
  $show_annotations = true, $is_type_designation = false, $skiptags = array(), $is_invalid = false) {
278

    
279
  $is_doubtful = false;
280

    
281
  if($taxon_name_or_taxon_base->class == 'Taxon' || $taxon_name_or_taxon_base->class == 'Synonym'){
282
    $taxonName = $taxon_name_or_taxon_base->name;
283
    $is_doubtful = $taxon_name_or_taxon_base->doubtful;
284
    // use the TaxonBase.tagged_title so we have the secRef
285
    $tagged_title = $taxon_name_or_taxon_base->taggedTitle;
286
  } else {
287
    // assuming this is a TaxonName
288
    $taxonName = $taxon_name_or_taxon_base;
289
    if(isset($taxonName->taggedFullTitle)){
290
      $tagged_title = $taxon_name_or_taxon_base->taggedFullTitle;
291
    } else {
292
      $tagged_title = $taxon_name_or_taxon_base->taggedName;
293
    }
294
  }
295

    
296

    
297
  $renderTemplate = get_nameRenderTemplate(RenderHints::getRenderPath(), $nameLink, $refenceLink);
298
  $partDefinition = get_partDefinition($taxonName->nameType);
299

    
300
  // Apply definitions to template.
301
  foreach ($renderTemplate as $part => $uri) {
302

    
303
    if (isset($partDefinition[$part])) {
304
      $renderTemplate[$part] = $partDefinition[$part];
305
    }
306
    if (is_array($uri) && isset($uri['#uri'])) {
307
      $renderTemplate[$part]['#uri'] = $uri['#uri'];
308
    }
309
  }
310

    
311
  $secref_tagged_text = tagged_text_extract_reference_and_detail($tagged_title);
312
  // taxon names will have the nomenclatural reference in the tagged full title:
313
  $nomref_tagged_text = tagged_text_extract_reference($tagged_title);
314
  $nom_status_tagged_text = tagged_text_extract_nomstatus($tagged_title);
315
  $appended_phrase_tagged_text = array(); // this is filled later
316

    
317
  normalize_tagged_text($tagged_title);
318

    
319
  $is_valid_tagged_title =
320
    isset($tagged_title)
321
    && is_array($tagged_title)
322
    && isset($tagged_title[0]->text)
323
    && is_string($tagged_title[0]->text)
324
    && $tagged_title[0]->text != ''
325
    && isset($tagged_title[0]->type);
326
  $lastAuthorElementString = FALSE;
327

    
328
  $name_encasement = $is_invalid ? '"' : '';
329
  $doubtful_marker = $is_doubtful ? '?&#8239;' : ''; // 	&#8239; =  NARROW NO-BREAK SPACE
330
  $doubtful_marker_markup = '';
331

    
332
  if($doubtful_marker){
333
    $doubtful_marker_markup = '<span class="doubtful">' . $doubtful_marker . '</span>';
334
    if($tagged_title[0]->text == '?' ){
335
      // remove the first tagged text element
336
      unset($tagged_title[0]);
337
    }
338
  }
339

    
340
  // split off all appendedPhrase item  from the end of the array (usually there only should  be one)
341
  while($tagged_title[count($tagged_title)-1]->type == "appendedPhrase"){
342
    $appended_phrase_tagged_text[] = array_pop($tagged_title);
343
  }
344

    
345
  // Got to use second entry as first one, see ToDo comment below ...
346
  if ($is_valid_tagged_title) {
347

    
348
    $taggedName = $tagged_title;
349
    $hasNamePart_with_Authors = isset($renderTemplate['namePart']) && isset($renderTemplate['namePart']['authors']);
350
    $hasNameAuthorPart_with_Authors = isset($renderTemplate['nameAuthorPart']) && isset($renderTemplate['nameAuthorPart']['authors']);
351

    
352

    
353
    if (!(($hasNamePart_with_Authors) || ($hasNameAuthorPart_with_Authors))) {
354
      // Find author and split off from name.
355
      // TODO expecting to find the author as the last element.
356
      /*
357
      if($taggedName[count($taggedName)- 1]->type == 'authors'){
358
        $authorTeam = $taggedName[count($taggedName)- 1]->text;
359
        unset($taggedName[count($taggedName)- 1]);
360
      }
361
      */
362

    
363
      // Remove all authors.
364
      $taggedNameNew = array();
365
      foreach ($taggedName as $element) {
366
        if ($element->type != 'authors') {
367
          $taggedNameNew[] = $element;
368
        }
369
        else {
370
          $lastAuthorElementString = $element->text;
371
        }
372
      }
373
      $taggedName = $taggedNameNew;
374
      unset($taggedNameNew);
375
    }
376
    $name = '<span class="' . $taxonName->class . '">' . $doubtful_marker_markup . $name_encasement . cdm_tagged_text_to_markup($taggedName, $skiptags) . $name_encasement . '</span>';
377
  }
378
  else {
379
    // use titleCache instead
380
    $name = '<span class="' . $taxonName->class . '_titleCache">' . $doubtful_marker_markup . $name_encasement . $taxonName->titleCache . $name_encasement . '</span>';
381
  }
382

    
383

    
384
  if(isset($appended_phrase_tagged_text[0])){
385
    $name .= ' <span class="appended-phrase">'. cdm_tagged_text_to_markup($appended_phrase_tagged_text) . '</span>';
386
  }
387

    
388
  // Fill name into $renderTemplate.
389
  array_setr('name', $name , $renderTemplate);
390

    
391
  // Fill with authorTeam.
392
  /*
393
  if($authorTeam){
394
    $authorTeamHtml = ' <span class="authorTeam">'.$authorTeam.'</span>';
395
    array_setr('authorTeam', $authorTeamHtml, $renderTemplate);
396
  }
397
  */
398

    
399
  // Fill with reference.
400
  if (isset($renderTemplate['referencePart']) && !$is_type_designation) {
401

    
402
    $registrations = cdm_ws_get(CDM_WS_NAME, array($taxonName->uuid, "registrations"));
403
    $registration_markup = render_registrations($registrations);
404

    
405
    // default separator
406
    $separator = '';
407

    
408
    // [Eckhard]:"Komma nach dem Taxonnamen ist grunsätzlich falsch,
409
    // Komma nach dem Autornamen ist überall dort falsch, wo ein "in" folgt."
410
    if (isset($renderTemplate['referencePart']['reference']) && isset($taxonName->nomenclaturalReference)) {
411
      $microreference = NULL;
412
      if (isset($renderTemplate['referencePart']['microreference'])&& isset($taxonName->nomenclaturalMicroReference)) {
413
        $microreference = $taxonName->nomenclaturalMicroReference;
414
      }
415
      if(count($nomref_tagged_text) == 0){
416
        $citation = cdm_ws_getNomenclaturalReference($taxonName->nomenclaturalReference->uuid, $microreference);
417
        // Find preceding element of the reference.
418
        $precedingKey = get_preceding_contentElementKey('reference', $renderTemplate);
419
        if (str_beginsWith($citation, ", in")) {
420
          $citation = substr($citation, 2);
421
          $separator = ' ';
422
        }
423
        elseif (!str_beginsWith($citation, "in") && $precedingKey == 'authors') {
424
          $separator = ', ';
425
        } else {
426
          $separator = ' ';
427
        }
428
        $referenceArray['#separator'] = $separator;
429
        $referenceArray['#html'] = '<span class="reference">' . $citation . '</span>' . $registration_markup;
430
      } else {
431
        // this ist the case for taxon names
432
        $referenceArray['#html'] = cdm_tagged_text_to_markup($nomref_tagged_text);
433
      }
434

    
435

    
436
      array_setr('reference', $referenceArray, $renderTemplate);
437
    }
438

    
439
    // If authors have been removed from the name part the last named authorteam
440
    // should be added to the reference citation, otherwise, keep the separator
441
    // out of the reference.
442
    if (isset($renderTemplate['referencePart']['authors']) && $lastAuthorElementString) {
443
      // If the nomenclaturalReference citation is not included in the
444
      // reference part but display of the microreference
445
      // is wanted, append the microreference to the authorTeam.
446
      $citation = '';
447
      if (!isset($renderTemplate['referencePart']['reference']) && isset($renderTemplate['referencePart']['microreference'])) {
448
        $separator = ": ";
449
        $citation = $taxonName->nomenclaturalMicroReference;
450
      }
451
      $referenceArray['#html'] = ' <span class="reference">' . $lastAuthorElementString . $separator . $citation . '</span>';
452
      array_setr('authors', $referenceArray, $renderTemplate);
453
    }
454
  }
455

    
456
  $is_reference_year = false;
457
  if (isset($renderTemplate['referenceYearPart']['reference.year'])) {
458
    if(isset($taxonName->nomenclaturalReference->datePublished)){
459
      $referenceArray['#html'] = ' <span class="reference">' . timePeriodToString($taxonName->nomenclaturalReference->datePublished) . '</span>';
460
      array_setr('reference.year', $referenceArray, $renderTemplate);
461
      $is_reference_year = true;
462
    }
463
  }
464

    
465
  // Fill with status.
466
  if(isset($renderTemplate['statusPart']['status'])){
467
    if (isset($nom_status_tagged_text[0])) {
468
        $tt_to_markup_options = array('html' => false);
469
        foreach ($nom_status_tagged_text as &$tt){
470
         if($tt->type == 'nomStatus'&& isset($tt->entityReference)) {
471
           $nom_status = cdm_ws_get(CDM_WS_NOMENCLATURALSTATUS, array($tt->entityReference->uuid));
472
           $nom_status_fkey = nomenclatural_status_footnote_markup($nom_status);
473
           $tt->text .= $nom_status_fkey;
474
           $tt_to_markup_options['html'] = true;
475
         }
476
        }
477
        array_setr(
478
          'status',
479
          '<span class="nomenclatural_status">' . cdm_tagged_text_to_markup($nom_status_tagged_text, array('postSeparator'), 'span', $tt_to_markup_options) . '</span>', $renderTemplate);
480
    }
481
  }
482

    
483
  if (isset($renderTemplate['secReferencePart'])){
484
    if(isset($secref_tagged_text[1])){
485
      $post_separator_markup = $is_reference_year ? '.': '';
486
      if(isset($nom_status_tagged_text[count($nom_status_tagged_text) - 1]) && ($nom_status_tagged_text[count($nom_status_tagged_text) - 1]->type ==  'postSeparator')){
487
        $post_separator_markup = cdm_tagged_text_to_markup(array($nom_status_tagged_text[count($nom_status_tagged_text) - 1 ]));
488
      };
489
      array_setr('secReference',
490
        $post_separator_markup
491
          . ' <span class="sec_reference">'
492
          . join('', cdm_tagged_text_values($secref_tagged_text))
493
          . '</span>', $renderTemplate);
494
    }
495
  }
496

    
497
  // Fill with protologues etc...
498
  $descriptionHtml = '';
499
  if (array_setr('description', TRUE, $renderTemplate)) {
500
    $descriptions = cdm_ws_get(CDM_WS_PORTAL_NAME_DESCRIPTIONS, $taxonName->uuid);
501
    foreach ($descriptions as $description) {
502
      if (!empty($description)) {
503
        foreach ($description->elements as $description_element) {
504
          $second_citation = '';
505
          if (isset($description_element->multilanguageText_L10n) && $description_element->multilanguageText_L10n->text) {
506
            $second_citation = '[& ' . $description_element->multilanguageText_L10n->text . '].';
507
          }
508
          $descriptionHtml .= $second_citation;
509
          $descriptionHtml .= cdm_description_element_media(
510
              $description_element,
511
              array(
512
                'application/pdf',
513
                'image/png',
514
                'image/jpeg',
515
                'image/gif',
516
                'text/html',
517
              )
518
          );
519

    
520
        }
521
      }
522
    }
523
    array_setr('description', $descriptionHtml, $renderTemplate);
524
  }
525

    
526
  // Render.
527
  $out = '';
528
  if(isset($_REQUEST['RENDER_PATH'])){
529
    // developer option to show the render path with each taxon name
530
    $out .= '<span class="render-path">' . RenderHints::getRenderPath() . '</span>';
531
  }
532
  $out .= '<span class="' . html_class_attribute_ref($taxon_name_or_taxon_base)
533
    . '" data-cdm-ref="/name/' . $taxonName->uuid . '" data-cdm-render-path="' . RenderHints::getRenderPath() .'">';
534

    
535
  foreach ($renderTemplate as $partName => $part) {
536
    $separator = '';
537
    $partHtml = '';
538
    $uri = FALSE;
539
    if (!is_array($part)) {
540
      continue;
541
    }
542
    if (isset($part['#uri']) && is_string($part['#uri'])) {
543
      $uri = $part['#uri'];
544
      unset($part['#uri']);
545
    }
546
    foreach ($part as $key => $content) {
547
      $html = '';
548
      if (is_array($content)) {
549
        $html = $content['#html'];
550
        if(isset($content['#separator'])) {
551
          $separator = $content['#separator'];
552
        }
553
      }
554
      elseif (is_string($content)) {
555
        $html = $content;
556
      }
557
      $partHtml .= '<span class="' . $key . '">' . $html . '</span>';
558
    }
559
    if ($uri) {
560
      // cannot use l() here since the #uri aleady should have been processed through uri() at this point
561
      $out .= $separator . '<a href="' . $uri . '" class="' . $partName . '">' . $partHtml . '</a>';
562

    
563
    }
564
    else {
565
      $out .= $separator . $partHtml;
566
    }
567
  }
568
  $out .= '</span>';
569
  if ($show_annotations) {
570
    // $out .= theme('cdm_annotations_as_footnotekeys', $taxonName);
571
  }
572
  return $out;
573
}
574

    
575

    
576

    
577
/**
578
 * Composes information for a registration from a dto object.
579
 *
580
 * Registrations which are not yet published are suppressed.
581
 *
582
 * @param $registration_dto
583
 * @param $with_citation
584
 *   Whether to show the citation.
585
 *
586
 * @return array
587
 *    A drupal render array with the elements:
588
 *    - 'name'
589
 *    - 'name-relations'
590
 *    - 'specimen_type_designations'
591
 *    - 'name_type_designations'
592
 *    - 'citation'
593
 *    - 'registration_date_and_institute'
594
 * @ingroup compose
595
 */
596
function compose_registration_dto_full($registration_dto, $with_citation = true)
597
{
598
  $render_array = array(
599
    '#prefix' => '<div class="registration">',
600
    '#suffix' => '</div>'
601
  );
602

    
603
  if(!(isset($registration_dto->identifier) && $registration_dto->status == 'PUBLISHED')){
604
    return $render_array;
605
  }
606

    
607
  $render_array['sub_headline'] = markup_to_render_array(join(", ", registration_types($registration_dto)),-10, '<h3 class="registration_type">' . t('Event: '), '</h3>' );
608
  $render_array['nomenclatural_act'] = array(
609
    '#weight' => 0,
610
    '#prefix' => '<div class="nomenclatural_act">',
611

    
612
    '#suffix' => '</div>'
613
  );
614

    
615
  // name
616
  if($registration_dto->nameRef){
617
    $name = cdm_ws_get(CDM_WS_PORTAL_NAME, $registration_dto->nameRef->uuid);
618
    cdm_load_tagged_full_title($name);
619
    $render_array['nomenclatural_act']['published_name'] = markup_to_render_array('<div class="published-name">' . render_taxon_or_name($name, url(path_to_name($name->uuid))) . '</div>', 0);
620
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $registration_dto->nameRef->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
621
    $render_array['nomenclatural_act']['name_relations'] = compose_name_relationships_list($name_relations, $registration_dto->nameRef->uuid, null);
622
    $render_array['nomenclatural_act']['name_relations']['#weight'] = 10;
623
  } else {
624
    // in this case the registration must have a
625
    $name = cdm_ws_get(CDM_WS_PORTAL_NAME, $registration_dto->typifiedNameRef->uuid);
626
    $render_array['typified_name'] = markup_to_render_array('<p class="typified-name">for ' . render_taxon_or_name($name, url(path_to_name($name->uuid))) . '</p>', 40);
627
  }
628
  // typedesignation in detail
629
  if(is_object($registration_dto->orderdTypeDesignationWorkingSets)) {
630
    $field_unit_uuids = array();
631
    $specimen_type_designation_refs = array();
632
    $name_type_designation_refs = array();
633
    foreach ((array)$registration_dto->orderdTypeDesignationWorkingSets as $workingset_ref => $obj) {
634
      $tokens = explode("#", $workingset_ref);
635
      $types_in_fieldunit = get_object_vars($obj); // convert into associative array
636

    
637
      if ($tokens[0] == 'NameTypeDesignation') {
638
        foreach ($types_in_fieldunit as $type_status => $entity_reference_list) {
639
          if(!isset($name_type_designation_refs[$type_status])){
640
            $name_type_designation_refs[$type_status]  = $entity_reference_list;
641
          } else {
642
            array_push($name_type_designation_refs[$type_status] ,$entity_reference_list);
643
          }
644
        }
645
      } else if ($tokens[0] == 'FieldUnit'){
646
        $field_unit_uuids[] = $tokens[1];
647
        foreach ($types_in_fieldunit as $type_status => $entity_reference_list) {
648
          if(!isset($specimen_type_designation_refs[$type_status])){
649
            $specimen_type_designation_refs[$type_status] =  $entity_reference_list;
650
          } else {
651
            array_push($specimen_type_designation_refs[$type_status], $entity_reference_list);
652
          }
653
        }
654
      } else {
655
        drupal_set_message("Unimplemented type: " . $tokens[0], 'error');
656
      }
657
    }
658
    // type designations wich are in this nomenclatural act.
659
    if (count($name_type_designation_refs) > 0) {
660
      $render_array['nomenclatural_act']['name_type_designations'] = compose_name_type_designations($name_type_designation_refs);
661
      $render_array['nomenclatural_act']['name_type_designations']['#prefix'] = '<p class="name_type_designations">';
662
      $render_array['nomenclatural_act']['name_type_designations']['#suffix'] = '</p>';
663
      $render_array['nomenclatural_act']['name_type_designations']['#weight'] = 20;
664
    }
665
    if (count($field_unit_uuids) > 0) {
666
      $specimen_type_designations_array = compose_specimen_type_designations($specimen_type_designation_refs, true);
667
      $render_array['nomenclatural_act']['specimen_type_designations'] = $specimen_type_designations_array['type_designations'];
668
      $render_array['map'] = $specimen_type_designations_array['map'];
669
      $render_array['map']['#weight'] = $render_array['nomenclatural_act']['#weight'] + 20;
670
    }
671
  }
672

    
673
  // citation
674
  if ($with_citation) {
675
    $render_array['citation'] = markup_to_render_array(
676
      "<div class=\"citation nomenclatural_act_citation" . html_class_attribute_ref(new TypedEntityReference("Reference", $registration_dto->citationUuid)) . "\">"
677
      . "<span class=\"label\">published in: </span>"
678
      . $registration_dto->bibliographicInRefCitationString
679
      . l(custom_icon_font_markup('icon-interal-link-alt-solid', array('class' => array('superscript'))), path_to_reference($registration_dto->citationUuid), array('html' => true))
680
      . "</div>",
681
      $render_array['nomenclatural_act']['#weight'] + 10 );
682
  }
683

    
684
  // registration date and office
685
  $registration_date_insitute_markup = render_registration_date_and_institute($registration_dto);
686
  if($registration_date_insitute_markup){
687
    $render_array['registration_date_and_institute'] = markup_to_render_array(
688
      $registration_date_insitute_markup . '</p>',
689
      100);
690
  }
691

    
692
  return $render_array;
693
}
694

    
695

    
696
/**
697
 * Composes a compact representation for a registrationDTO object
698
 *
699
 * Registrations which are not yet published are suppressed.
700
 *
701
 * @param $registration_dto
702
 * @param $style string
703
 *   The style of how to compose the 'identifier' and 'registration_date_and_institute' part with the summary
704
 *   - 'citation': Similar to the arrearance of nomenclatural acts in print media
705
 *   - 'list-item' : style suitable for result lists etc
706
 *
707
 * @return array
708
 *    A drupal render array with the elements:
709
 *    - 'registration-metadata' when $style == 'list-item'
710
 *    - 'summary'
711
 * @ingroup compose
712
 */
713
function compose_registration_dto_compact($registration_dto, $style = 'citation', $tag_enclosing_summary = 'p')
714
{
715
  $render_array = array();
716
  $media_link_map = array();
717

    
718
  if(!(isset($registration_dto->identifier) && $registration_dto->status == 'PUBLISHED')){
719
    return $render_array;
720
  }
721

    
722
  $registration_date_insitute_markup = render_registration_date_and_institute($registration_dto, 'span');
723
  $itentifier_markup = l($registration_dto->identifier, path_to_registration($registration_dto->identifier), array('attributes' => array('class' => array('identifier'))));
724

    
725
  $tagged_text_options = array();
726
  if(isset($registration_dto->nameRef)){
727
    $tagged_text_options[] = array(
728
      'filter-type' => 'name',
729
      'prefix' => '<span class="registered_name">',
730
      'suffix' => '</span>',
731
    );
732
  } else {
733
    $tagged_text_options[] = array(
734
      'filter-type' => 'name',
735
      'prefix' => '<span class="referenced_typified_name">',
736
      'suffix' => '</span>',
737
    );
738
  }
739
  cdm_tagged_text_add_options($registration_dto->summaryTaggedText, $tagged_text_options);
740
  $taggged_text_expanded = cdm_tagged_text_expand_entity_references($registration_dto->summaryTaggedText);
741
  foreach ($taggged_text_expanded  as $tagged_text){
742
    if(isset($tagged_text->entityReference->type) && $tagged_text->entityReference->type == 'SpecimenTypeDesignation') {
743
      $mediaDTOs = cdm_ws_get('typedesignation/$0/media', array($tagged_text->entityReference->uuid));
744
      if(isset($mediaDTOs[0]->uri)){
745
        $media_url_key = '{link-' . $mediaDTOs[0]->uuid . '}';
746
        $tagged_text->text = str_replace('[icon]', '[icon]' . $media_url_key, $tagged_text->text);
747
        $media_link_map[$media_url_key] =  cdm_external_uri($mediaDTOs[0]->uri, true);
748
      }
749
    }
750
  }
751
  $registation_markup = cdm_tagged_text_to_markup($taggged_text_expanded);
752
  foreach($media_link_map as $media_url_key => $link){
753
    $registation_markup = str_replace($media_url_key, $link, $registation_markup);
754
  }
755
  if($style == 'citation') {
756
    $registation_markup = $registation_markup . ' ' . $itentifier_markup . ' ' . $registration_date_insitute_markup;
757
  } else {
758
    $render_array['registration-metadata'] = markup_to_render_array('<div class="registration-metadata">' . $itentifier_markup . ' ' . $registration_date_insitute_markup. "</div>", -10);
759
  }
760
  $render_array['summary'] = markup_to_render_array('<' . $tag_enclosing_summary . ' class="registration-summary">' . $registation_markup . '</' . $tag_enclosing_summary . '>', 0);
761

    
762
  return $render_array;
763
}
764

    
765

    
766
/**
767
 * Renders the registrationDate and institutionTitleCache of the $registration_dto as markup.
768
 *
769
 * @param $registration_dto
770
 * @return string
771
 *    The markup or an empty string
772
 */
773
function render_registration_date_and_institute($registration_dto, $enclosing_tag = 'p') {
774
  $registration_date_institute_markup = '';
775
  if ($registration_dto->registrationDate) {
776
    $date_string = format_datetime($registration_dto->registrationDate);
777
    if (isset($registration_dto->institutionTitleCache) && $registration_dto->institutionTitleCache) {
778
      $registration_date_institute_markup =
779
        t("Registration on @date in @institution", array(
780
          '@date' => $date_string,
781
          '@institution' => $registration_dto->institutionTitleCache,
782
        ));
783
    } else {
784
      $registration_date_institute_markup =
785
        t("Registration on @date", array(
786
          '@date' => $date_string
787
        ));
788
    }
789
    $registration_date_institute_markup = '<' .$enclosing_tag . ' class="registration-date-and-institute">'. $registration_date_institute_markup . '</' .$enclosing_tag . '>';
790
  }
791
  return $registration_date_institute_markup;
792
}
793

    
794

    
795
/**
796
 * @param $registrations
797
 * @return string
798
 */
799
function render_registrations($registrations)
800
{
801
  $registration_markup = '';
802
  $registration_markup_array = array();
803
  if ($registrations) {
804
    foreach ($registrations as $reg) {
805
      $registration_markup_array[] = render_registration($reg);
806
    }
807
    $registration_markup = " Registration" . (count($registration_markup_array) > 1 ? 's: ' : ': ')
808
      . join(', ', $registration_markup_array);
809
  }
810
  return $registration_markup;
811
}
812

    
813

    
814
/**
815
 * Renders a registration
816
 *
817
 * TODO replace by compose_registration_dto_compact
818
 * @param $registration
819
 */
820
function render_registration($registration){
821
  $markup = '';
822

    
823
  if(isset($registration->identifier) && $registration->status == 'PUBLISHED'){
824
    $office_class_attribute = '';
825
    if(isset($registration->institution->titleCache)){
826
      $office_class_attribute = registration_intitute_class_attribute($registration);
827
    }
828
    $markup = "<span class=\"registration $office_class_attribute\">" . l($registration->identifier, path_to_registration($registration->identifier)) . ', '
829
      .  preg_replace('/^([^T]*)(.*)$/', '${1}', $registration->registrationDate)
830
      . '</span>';
831
  }
832
  return $markup;
833
}
834

    
835
/**
836
 * @param $registration
837
 * @return string
838
 */
839
function registration_intitute_class_attribute($registration_dto)
840
{
841
  if(isset($registration_dto->institutionTitleCache)){
842
    $institutionTitleCache = $registration_dto->institutionTitleCache;
843
  } else {
844
    // fall back option to also support cdm entities
845
    $institutionTitleCache = @$registration_dto->institution->titleCache;
846
  }
847
  return $institutionTitleCache ? 'registration-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '-', $institutionTitleCache)) : '';
848
}
849

    
850

    
851
/**
852
 * Composes the textual representation for the type designation of taxon name identified by the uuid in with a map for the location data.
853
 *
854
 * @param $taxon_name_uuid
855
 * @param $show_specimen_details
856
 * @return array
857
 *    A drupal render array with the following elements:
858
 *    - 'type_designations'
859
 *    - 'map'
860
 *    - 'specimens'
861
 *
862
 * @ingroup compose
863
 */
864
function compose_type_designations($taxon_name_uuid, $show_specimen_details = false)
865
{
866
  $render_array = array(
867
    'type_designations' => array(),
868
    'map' => array(),
869
    );
870
  $type_designations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $taxon_name_uuid);
871
  if ($type_designations) {
872
    usort($type_designations, 'compare_specimen_type_designation');
873
    $render_array['type_designations'] = markup_to_render_array(
874
      theme('cdm_typedesignations', array('typeDesignations' => $type_designations, 'enclosing_tag' => 'div', 'element_tag' => 'div'))
875
    );
876

    
877
    $render_array['map'] = compose_type_designations_map($type_designations);
878
  }
879
  return $render_array;
880
}
881

    
882
/**
883
 * Composes a map with the location points of the passed $type_designations.
884
 *
885
 * @param $type_designations
886
 *
887
 * @return array
888
 *     A drupal render array or an empty array in case there are no point to show.
889
 *
890
 * @ingroup compose
891
 */
892
function compose_type_designations_map($type_designations)
893
{
894
  $points = array();
895
  $map_render_array = array();
896
  foreach ($type_designations as $td) {
897
    if ($td->class == "SpecimenTypeDesignation") {
898
      $derived_unit_facade = cdm_ws_get(CDM_WS_PORTAL_DERIVEDUNIT_FACADE, array($td->typeSpecimen->uuid));
899
      if (isset($derived_unit_facade->exactLocation)) {
900
        $points[] = $derived_unit_facade->exactLocation->latitude . ',' . $derived_unit_facade->exactLocation->longitude;
901
      }
902
    }
903
  }
904

    
905
  if (count($points) > 0) {
906
    // os=1:c/ff0000/10/noLabel&od=1:52.52079,13.57781|-43.46333333333333,172.60355&legend=0
907
    $occurrence_query = 'os=1:c/ff0000/10/noLabel&od=1:' . join('|', $points) . '&legend=0';
908
    // $occurrence_query = 'os=1:c/ff0000/10/noLabel&od=1:52.52079,13.57781|-43.46333333333333,172.60355&legend=0';
909
    $legend_format_query = null;
910
    $distribution_query = NULL;
911
    $map_render_array = compose_map('specimens', $occurrence_query, $distribution_query, $legend_format_query, array());
912
  }
913
  return $map_render_array;
914
}
915

    
916
/**
917
 * Composes the TypedEntityReference to name type designations passed as associatve array.
918
 *
919
 * @param $$type_entity_refs array
920
 *   an associative array of name type type => TypedEntityReference for name type designations as
921
 *   produced by the eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager
922
 *
923
 * @ingroup compose
924
 */
925
function compose_name_type_designations($type_entity_refs){
926
  $render_array = array();
927
  $preferredStableUri = '';
928
  foreach($type_entity_refs as $type_status => $name_types){
929
    foreach ($name_types as $name_type){
930
      $type_designation = cdm_ws_get(CDM_WS_TYPEDESIGNATION, array($name_type->uuid, 'preferredUri'));
931
      if(isset($type_designation->typeSpecimen->preferredStableUri) && $type_designation->typeSpecimen->preferredStableUri){
932
        $preferredStableUri = $type_designation->typeSpecimen->preferredStableUri;
933
      }
934
      $render_array[] = markup_to_render_array('<div class="name_type_designation ' . html_class_attribute_ref($name_type)  . '"><span class="type-status">'. ucfirst($type_status) . "</span>: "
935
        . $name_type->label
936
        . ($preferredStableUri ? " ". l($preferredStableUri,  $preferredStableUri) : '')
937
        . '</div>');
938
      }
939
  }
940
  return $render_array;
941
}
942

    
943
/**
944
 * Composes the specimen type designations with map from the the $type_entity_refs
945
 *
946
 * @param $type_entity_refs array
947
 *   an associative array of specimen type type => TypedEntityReference for specimen type designations as
948
 *   produced by the eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager
949
 *
950
 * @param $show_media_specimen
951
 * @return array
952
 *    A drupal render array with the following elements:
953
 *    - 'type_designations'
954
 *    - 'map'
955
 *
956
 * @ingroup compose
957
 *
958
 */
959
function compose_specimen_type_designations($type_entity_refs, $show_media_specimen){
960

    
961
  $render_array = array();
962

    
963
  $type_designation_list = array();
964
  uksort($type_entity_refs, "compare_type_designation_status_labels");
965
  foreach($type_entity_refs as $type_status => $specimen_types){
966
    foreach($specimen_types as $specimen_type){
967

    
968
      $type_designation = cdm_ws_get(CDM_WS_PORTAL_TYPEDESIGNATION, array($specimen_type->uuid));
969
      $type_designation_list[] = $type_designation; // collect for the map
970

    
971
      $derivedUnitFacadeInstance = cdm_ws_get(CDM_WS_PORTAL_DERIVEDUNIT_FACADE, $type_designation->typeSpecimen->uuid);
972
      // the media specimen is not contained in the $type_designation returned by CDM_PORTAL_TYPEDESIGNATION, so we need to fetch it separately
973
      $mediaSpecimen = cdm_ws_get(CDM_WS_PORTAL_OCCURRENCE, array($type_designation->typeSpecimen->uuid, 'mediaSpecimen'));
974

    
975

    
976
      $preferredStableUri = '';
977
      $citation_markup = '';
978
      $media = '';
979

    
980
      // preferredStableUri
981
      if(isset($type_designation->typeSpecimen->preferredStableUri) && $type_designation->typeSpecimen->preferredStableUri){
982
        $preferredStableUri = $type_designation->typeSpecimen->preferredStableUri;
983
      }
984

    
985
      if($show_media_specimen && $mediaSpecimen){
986
        // compose output
987
        // mediaURI
988
        if(isset($mediaSpecimen->representations[0])) {
989
          $gallery_settings = getGallerySettings(CDM_DATAPORTAL_SPECIMEN_GALLERY_NAME);
990
          $captionElements = array(
991
            '#uri' => t('open media'),
992
            'elements' => array('-none-'),
993
            'sources_as_content' => true
994
          );
995
          $media = compose_cdm_media_gallerie(array(
996
            'mediaList' => array($mediaSpecimen),
997
            'galleryName' => CDM_DATAPORTAL_TYPE_SPECIMEN_GALLERY_NAME . '_' . $specimen_type->uuid,
998
            'maxExtend' => $gallery_settings['cdm_dataportal_media_maxextend'],
999
            'cols' => $gallery_settings['cdm_dataportal_media_cols'],
1000
            'captionElements' => $captionElements,
1001
          ));
1002
        }
1003
        // citation and detail
1004
        $annotations_and_sources = handle_annotations_and_sources(
1005
            $mediaSpecimen,
1006
            array(
1007
                'sources_as_content' => true,
1008
                'link_to_name_used_in_source' => false,
1009
                'link_to_reference' => true,
1010
                'add_footnote_keys' => false,
1011
                'bibliography_aware' => false),
1012
            '',
1013
            null
1014
        );
1015
        if(is_array( $annotations_and_sources['source_references'])){
1016
          $citation_markup = join(', ', $annotations_and_sources['source_references']);
1017
        }
1018
      }
1019

    
1020
      $specimen_markup = $derivedUnitFacadeInstance->titleCache;
1021
      if(isset($derivedUnitFacadeInstance->specimenLabel) && $derivedUnitFacadeInstance->specimenLabel){
1022
        $specimen_markup = str_replace($derivedUnitFacadeInstance->specimenLabel, l($derivedUnitFacadeInstance->specimenLabel, path_to_specimen($type_designation->typeSpecimen->uuid)), $specimen_markup);
1023
      }
1024

    
1025
      $type_designation_render_array = markup_to_render_array('<div class="specimen_type_designation ' . html_class_attribute_ref($specimen_type)  . '">
1026
          <span class="type-status">' . ucfirst($type_status) . "</span>: "
1027
        . $specimen_markup
1028
        . ($citation_markup ? ' '. $citation_markup : '')
1029
        . ($preferredStableUri ? " ". l($preferredStableUri,  $preferredStableUri) : '')
1030
        . $media
1031
        . '</div>');
1032

    
1033
      $render_array['type_designations'][] = $type_designation_render_array;
1034
    }
1035
  }
1036
  if(count($type_designation_list) > 0 ){
1037
    $render_array['map'] = compose_type_designations_map($type_designation_list);
1038
  } else {
1039
    $render_array['map'] = array();
1040
  }
1041
  return $render_array;
1042
}
1043

    
1044
/**
1045
 * @param $name_rel
1046
 * @param $current_name_uuid
1047
 * @param $current_taxon_uuid
1048
 * @param $suppress_if_current_name_is_source // FIXME UNUSED !!!!
1049
 * @param $show_name_cache_only
1050
 *    The nameCache will be shown instead of the titleCache if this parameter is true.
1051
 * @return null|string
1052
 */
1053
function name_relationship_markup($name_rel, $current_name_uuid, $current_taxon_uuid, $show_name_cache_only = false){
1054

    
1055
  $relationship_markup = null;
1056

    
1057
  $current_name_is_toName = $current_name_uuid == $name_rel->toName->uuid;
1058

    
1059
  if($current_name_is_toName){
1060
    $name = $name_rel->fromName;
1061
  } else {
1062
    $name = $name_rel->toName;
1063
  }
1064

    
1065
  cdm_load_tagged_full_title($name);
1066

    
1067
  $highlited_synonym_uuid = isset ($name->taxonBases[0]->uuid) ? $name->taxonBases[0]->uuid : '';
1068
  if(!$show_name_cache_only){
1069
    $relationship_markup = render_taxon_or_name($name,
1070
      url(path_to_name($name->uuid, $current_taxon_uuid, $highlited_synonym_uuid, false))
1071
    );
1072
  } else {
1073
    $relationship_markup = l(
1074
      '<span class="' . html_class_attribute_ref($name) . '"">' . $name->nameCache . '</span>',
1075
      path_to_name($name->uuid, $current_taxon_uuid, $highlited_synonym_uuid, false),
1076
      array('html' => true)
1077
    );
1078
  }
1079

    
1080
  return $relationship_markup;
1081
}
1082

    
1083

    
1084
/**
1085
 * Composes an inline representation of selected name relationships
1086
 *
1087
 * The output of this function will be usually appended to taxon name representations.
1088
 * Only the following types are displayed: LATER_HOMONYM, TREATED_AS_LATER_HOMONYM, BLOCKING_NAME_FOR, ORTHOGRAPHIC_VARIANT
1089
 *
1090
 * LATER_HOMONYM, TREATED_AS_LATER_HOMONYM, BLOCKING_NAME_FOR are displayed as
1091
 * non {titleCache} nec {titleCache} nec {titleCache} whereas the related names
1092
 * are ordered alphabetically.
1093
 *
1094
 * ORTHOGRAPHIC_VARIANT is displayed as 'ort. var. {nameCache}'
1095
 *
1096
 * Related issues:
1097
 *   - https://dev.e-taxonomy.eu/redmine/issues/5697 "Show name conserved against as [non xxx]"
1098
 *   - https://dev.e-taxonomy.eu/redmine/issues/6678 "How to correctly show name relationship "orth. var." in dataportal"
1099
 *   - https://dev.e-taxonomy.eu/redmine/issues/5857
1100
 *   - https://dev.e-taxonomy.eu/redmine/issues/2001 "[Cichorieae Portal] Name Relationship -> blocking name are not shown"
1101
 *
1102
 * @param $name_relations
1103
 *    The list of CDM NameRelationsips
1104
 * @param $current_name_uuid
1105
 *    The Uuid of the name for which the relations are to be rendered, the current name will be hidden when
1106
 *    rendering the relation an only the other name is shown. Parameter is REQUIRED.
1107
 * @param $suppress_if_current_name_is_source
1108
 *    The display of the relation will be
1109
 *    suppressed is the current name is on the source of the relation edge.
1110
 *    That is if it is on the from side of the relation. Except for 'blocking name for' which is
1111
 *    an inverse relation. For this relation type the toName is taken in to account.
1112
 * @param $current_taxon_uuid
1113
 *    The taxon to be omitted from related taxa. This is only used to create links, see path_to_name()
1114
 * @return array
1115
 *    A drupal render array
1116
 *
1117
 * @ingroup Compose
1118
 */
1119
function compose_name_relationships_inline($name_relations, $current_name_uuid, $current_taxon_uuid, $suppress_if_current_name_is_source = true) {
1120

    
1121
  RenderHints::pushToRenderStack('homonym');
1122
  // the render stack element homonyms is being used in the default render templates !!!, see CDM_NAME_RENDER_TEMPLATES_DEFAULT
1123

    
1124
  $selected_name_rel_uuids = variable_get(CDM_NAME_RELATIONSHIP_INLINE_TYPES, unserialize(CDM_NAME_RELATIONSHIP_INLINE_TYPES_DEFAULT));
1125
  $name_rel_type_filter = array('direct' => array(), 'inverse' => array());
1126
  foreach ($selected_name_rel_uuids as $uuid){
1127
    $name_rel_type_filter['direct'][$uuid] = $uuid;
1128
    if($uuid != UUID_NAMERELATIONSHIPTYPE_MISSPELLING){
1129
      $name_rel_type_filter['inverse'][$uuid] = $uuid;
1130
    }
1131
  }
1132

    
1133
  $list_prefix = '<span class="name_relationships">[';
1134
  $list_suffix = ']</span>';
1135
  $item_prefix = '<span class="item">';
1136
  $item_suffix = '</span> ';
1137
  $render_array = compose_name_relationships($name_relations, $name_rel_type_filter, $current_name_uuid, $current_taxon_uuid, $list_prefix, $list_suffix, $item_prefix, $item_suffix);
1138

    
1139
  // remove the glue space from the last item element which has been added by the $item_suffix = '</span> '
1140
  $items_ctn = count($render_array['list']['items']);
1141
  if($items_ctn){
1142
    $render_array['list']['items'][$items_ctn - 1]['#suffix'] = '</span>';
1143
  }
1144

    
1145
  RenderHints::popFromRenderStack();
1146
  return $render_array;
1147
}
1148

    
1149
/**
1150
 * Composes an list representation of the name relationships.
1151
 *
1152
 * The output of this function will be usually appended to taxon name representations.
1153
 *
1154
 * Related issues:
1155
 *   - https://dev.e-taxonomy.eu/redmine/issues/5697 "Show name conserved against as [non xxx]"
1156
 *   - https://dev.e-taxonomy.eu/redmine/issues/6678 "How to correctly show name relationship "orth. var." in dataportal"
1157
 *   - https://dev.e-taxonomy.eu/redmine/issues/5857
1158
 *
1159
 * @param $name_relations
1160
 *    The list of CDM NameRelationsips
1161
 * @param $current_name_uuid
1162
 *    The Uuid of the name for which the relations are to be rendered, the current name will be hidden when
1163
 *    rendering the relation an only the other name is shown. Parameter is REQUIRED.
1164
 * @param $current_taxon_uuid
1165
 *    The taxon to be omitted from related taxa. This is only used to create links, see path_to_name()
1166
 * @return array
1167
 *    A drupal render array
1168
 *
1169
 * @ingroup Compose
1170
 */
1171
function compose_name_relationships_list($name_relations, $current_name_uuid, $current_taxon_uuid) {
1172

    
1173
  // $ordered_name_relation_type_uuids = array_keys(cdm_terms_by_type_as_option('NameRelationshipType', CDM_ORDER_BY_ORDER_INDEX_ASC));
1174

    
1175
  $key = 'name_relationships';
1176
  RenderHints::pushToRenderStack($key);
1177
  if(!RenderHints::getFootnoteListKey()){
1178
    RenderHints::setFootnoteListKey($key);
1179
  }
1180
  // the render stack element homonyms is being used in the default render templates !!!, see CDM_NAME_RENDER_TEMPLATES_DEFAULT
1181

    
1182
  $selected_name_rel_uuids = variable_get(CDM_NAME_RELATIONSHIP_LIST_TYPES, cdm_vocabulary_as_defaults(UUID_NAME_RELATIONSHIP_TYPE));
1183
  $name_rel_type_filter = array('direct' => array(), 'inverse' => array());
1184
  foreach ($selected_name_rel_uuids as $uuid){
1185
    $name_rel_type_filter['direct'][$uuid] = $uuid;
1186
    $name_rel_type_filter['inverse'][$uuid] = $uuid;
1187
  }
1188

    
1189
  $list_prefix = '<div class="relationships_list name_relationships">';
1190
  $list_suffix = '</div>';
1191
  $item_prefix = '<div class="item">';
1192
  $item_suffix = '</div>';
1193

    
1194
  $render_array = compose_name_relationships($name_relations, $name_rel_type_filter, $current_name_uuid, $current_taxon_uuid, $list_prefix, $list_suffix, $item_prefix, $item_suffix);
1195

    
1196
  RenderHints::popFromRenderStack();
1197
  $render_array['footnotes'] = markup_to_render_array(theme('cdm_footnotes', array('footnoteListKey' => RenderHints::getFootnoteListKey())));
1198
  if(RenderHints::getFootnoteListKey() == $key) {
1199
    RenderHints::clearFootnoteListKey();
1200
  }
1201
  return $render_array;
1202
}
1203

    
1204
/**
1205
 * @param $name_relations
1206
 * @param $name_rel_type_filter
1207
 *   Associative array with two keys:
1208
 *   - 'direct': the relationship type uuids for the direct direction of the relation edge to be included
1209
 *   - 'inverse': the relationship type uuids for the direct direction of the relation edge to be included
1210
 * @param $current_name_uuid
1211
 * @param $current_taxon_uuid
1212
 * @param $list_prefix
1213
 * @param $list_suffix
1214
 * @param $item_prefix
1215
 * @param $item_suffix
1216
 * @return array
1217
 *
1218
 * @ingroup Compose
1219
 */
1220
function compose_name_relationships($name_relations, $name_rel_type_filter, $current_name_uuid, $current_taxon_uuid,
1221
                                    $list_prefix, $list_suffix, $item_prefix, $item_suffix)
1222
{
1223
  $non_nec_name_reltype_uuids = array(UUID_NAMERELATIONSHIPTYPE_LATER_HOMONYM,
1224
    UUID_NAMERELATIONSHIPTYPE_TREATED_AS_LATER_HOMONYM,
1225
    UUID_NAMERELATIONSHIPTYPE_CONSERVED_AGAINST,
1226
    UUID_NAMERELATIONSHIPTYPE_MISSPELLING,
1227
    UUID_NAMERELATIONSHIPTYPE_BLOCKING_NAME_FOR);
1228

    
1229
  $render_array = array(
1230
    'list' => array(
1231
      '#prefix' => $list_prefix,
1232
      '#suffix' => $list_suffix,
1233
      'items' => array()
1234
    ),
1235
    'footnotes' => array()
1236
  );
1237

    
1238
  if ($name_relations) {
1239

    
1240
    // remove all relations which are not selected in the settings and
1241
    // separate all LATER_HOMONYM, TREATED_AS_LATER_HOMONYM, BLOCKING_NAME_FOR relations and ORTHOGRAPHIC_VARIANTs
1242
    // for special handling
1243
    $filtered_name_rels = array();
1244
    $non_nec_name_rels = array();
1245
    $orthographic_variants = array();
1246
    foreach ($name_relations as $name_rel) {
1247
      $rel_type_uuid = $name_rel->type->uuid;
1248
      $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1249
      if ((!$is_inverse_relation && isset($name_rel_type_filter['direct'][$rel_type_uuid]) && $name_rel_type_filter['direct'][$rel_type_uuid])
1250
        ||($is_inverse_relation && isset($name_rel_type_filter['inverse'][$rel_type_uuid]) && $name_rel_type_filter['inverse'][$rel_type_uuid])) {
1251

    
1252
        if (array_search($rel_type_uuid, $non_nec_name_reltype_uuids) !== false && (
1253
            $current_name_uuid == $name_rel->fromName->uuid && $rel_type_uuid != UUID_NAMERELATIONSHIPTYPE_BLOCKING_NAME_FOR
1254
            || $current_name_uuid == $name_rel->toName->uuid && $rel_type_uuid == UUID_NAMERELATIONSHIPTYPE_BLOCKING_NAME_FOR
1255
          )
1256
        ){
1257
          $non_nec_name_rels[] = $name_rel;
1258
        } else if (UUID_NAMERELATIONSHIPTYPE_ORTHOGRAPHIC_VARIANT == $rel_type_uuid) {
1259
          $orthographic_variants[] = $name_rel;
1260
        } else {
1261

    
1262
          $filtered_name_rels[] = $name_rel;
1263
        }
1264
      }
1265
    }
1266
    $name_relations = $filtered_name_rels;
1267

    
1268
    usort($name_relations, 'compare_name_relations_by_term_order_index');
1269

    
1270
    // compose
1271
    foreach ($name_relations as $name_rel) {
1272

    
1273
      $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1274

    
1275
      $rel_footnote_key_markup = name_relationship_footnote_markup($name_rel);
1276
      $relationship_markup = name_relationship_markup($name_rel, $current_name_uuid, $current_taxon_uuid);
1277

    
1278
      $label = cdm_relationship_type_term_abbreviated_label($name_rel->type, $is_inverse_relation);
1279
      $symbol = cdm_relationship_type_term_symbol($name_rel->type, $is_inverse_relation);
1280
      $symbol_markup = '<span class="symbol" title="' . $label . '">' . $symbol . '</span>' . $rel_footnote_key_markup . ' ';
1281
      $relationship_markup = $symbol_markup . $relationship_markup;
1282
      if ($relationship_markup) {
1283
        $render_array['list']['items'][] = markup_to_render_array($relationship_markup,
1284
          null,
1285
          $item_prefix,
1286
          $item_suffix);
1287
      }
1288
    }
1289

    
1290
    // name relationships to be displayed as non nec
1291
    if (count($non_nec_name_rels) > 0) {
1292
      $non_nec_markup = '';
1293
      foreach ($non_nec_name_rels as $name_rel) {
1294
        $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1295
        $rel_footnote_key_markup = name_relationship_footnote_markup($name_rel);
1296
        $relationship_markup = name_relationship_markup($name_rel, $current_name_uuid, $current_taxon_uuid);
1297
        $label = cdm_relationship_type_term_abbreviated_label($name_rel->type, $is_inverse_relation);
1298
        $symbol = $non_nec_markup ? ' nec ' : 'non';
1299
        $symbol_markup = '<span class="symbol" title="' . $label . '">' . $symbol . '</span>' . $rel_footnote_key_markup .  ' ';
1300
        $non_nec_markup .= $symbol_markup . $relationship_markup;
1301
      }
1302
      if ($non_nec_markup) {
1303
        $render_array['list']['items'][] = markup_to_render_array($non_nec_markup,
1304
          null,
1305
          $item_prefix,
1306
          $item_suffix);
1307
      }
1308
    }
1309

    
1310
    // orthographic variants
1311
    if (count($orthographic_variants) > 0) {
1312
      foreach ($orthographic_variants as $name_rel) {
1313

    
1314
        $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1315
        $rel_footnote_key_markup = name_relationship_footnote_markup($name_rel);
1316
        $relationship_markup = name_relationship_markup($name_rel, $current_name_uuid, $current_taxon_uuid, TRUE);
1317
        $nomref_footnote_key_markup = nomenclatural_reference_footnote_key_markup($name_rel->toName);
1318
        $label = cdm_relationship_type_term_abbreviated_label($name_rel->type, $is_inverse_relation);
1319
        $symbol = cdm_relationship_type_term_symbol($name_rel->type, $is_inverse_relation);
1320
        $symbol_markup = '<span class="symbol" title="' . $label . '">' . $symbol . '</span>' . $rel_footnote_key_markup .  ' ';
1321
        $relationship_markup = $symbol_markup . $relationship_markup . $nomref_footnote_key_markup;
1322
      }
1323
      if ($relationship_markup) {
1324
        $render_array['list']['items'][] = markup_to_render_array($relationship_markup,
1325
          null,
1326
          $item_prefix,
1327
          $item_suffix);
1328
      }
1329
    }
1330
  }
1331
  return $render_array;
1332
}
1333

    
1334
/**
1335
 * @param $name_rel
1336
 * @return string
1337
 */
1338
function name_relationship_footnote_markup($name_rel)
1339
{
1340
  $footnote_markup = '';
1341
  $footnote_key_markup = '';
1342
  if (isset($name_rel->ruleConsidered) && $name_rel->ruleConsidered) {
1343
    $footnote_markup = '<span class="rule_considered">' . $name_rel->ruleConsidered . '</span> ';
1344
  }
1345
  if (isset($name_rel->citation)) {
1346
    $footnote_markup .= '<span class="reference">' . $name_rel->citation->titleCache . '</span>';
1347
  }
1348
  if (isset($name_rel->citationMicroReference) && $name_rel->citationMicroReference) {
1349
    $footnote_markup .= (isset($name_rel->citation) ? ':' : '') . '<span class="reference_detail">' . $name_rel->citationMicroReference . '</span>';
1350
  }
1351
  if ($footnote_markup) {
1352
    $fnkey = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $footnote_markup);
1353
    $footnote_key_markup = theme('cdm_footnote_key', array(
1354
      'footnoteKey' => $fnkey,
1355
      'separator' => ',',
1356
      'highlightable' => TRUE,
1357
      'separator_off' => TRUE,
1358
    ));
1359
  }
1360
  return $footnote_key_markup;
1361
}
1362

    
1363
/**
1364
 * @param $nom_status
1365
 * @return string
1366
 */
1367
function nomenclatural_status_footnote_markup($nom_status)
1368
{
1369
  // NomenclaturalStatus is a subclass of ReferencedEntityBase
1370
  // and has the same structure as TaxonNameRelationship
1371
  return name_relationship_footnote_markup($nom_status);
1372
}
1373

    
1374
/**
1375
 * @param $name
1376
 * @return string
1377
 */
1378
function nomenclatural_reference_footnote_key_markup($name)
1379
{
1380
  $footnote_markup = '';
1381
  $footnote_key_markup = '';
1382
  if (isset($name->nomenclaturalReference) && $name->nomenclaturalReference) {
1383
    $footnote_markup .= '<span class="reference">' . $name->nomenclaturalReference->titleCache . '</span>';
1384
  }
1385
  if (isset($name->nomenclaturalMicroReference)) {
1386
    $footnote_markup .= ($footnote_key_markup ? ':' : '') . '<span class="reference_detail">' . $name->nomenclaturalMicroReference . '</span>';
1387
  }
1388
  if ($footnote_markup) {
1389
    $fnkey = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $footnote_markup);
1390
    $footnote_key_markup = theme('cdm_footnote_key', array(
1391
      'footnoteKey' => $fnkey,
1392
      'separator' => ',',
1393
      'highlightable' => TRUE,
1394
      'separator_off' => TRUE,
1395
    ));
1396
  }
1397
  return $footnote_key_markup;
1398
}
1399

    
1400

    
1401
/**
1402
 * @param $taxon
1403
 * @return array
1404
 */
1405
function cdm_name_relationships_for_taxon($taxon)
1406
{
1407
  $from_name_relations = cdm_ws_get(CDM_WS_PORTAL_TAXON_FROM_NAMERELATIONS, $taxon->uuid);
1408
  $to_name_relations = cdm_ws_get(CDM_WS_PORTAL_TAXON_TO_NAMERELATIONS, $taxon->uuid);
1409
  $name_relations = array_merge($from_name_relations, $to_name_relations);
1410
  return $name_relations;
1411
}
1412

    
1413

    
1414
/**
1415
 * Recursively searches the array for the $key and sets the given value.
1416
 *
1417
 * @param mixed $key
1418
 *   Key to search for.
1419
 * @param mixed $value
1420
 *   Value to set.'
1421
 * @param array $array
1422
 *   Array to search in.
1423
 *
1424
 * @return bool
1425
 *   True if the key has been found.
1426
 */
1427
function &array_setr($key, $value, array &$array) {
1428
  $res = NULL;
1429
  foreach ($array as $k => &$v) {
1430
    if ($key == $k) {
1431
      $v = $value;
1432
      return $array;
1433
    }
1434
    elseif (is_array($v)) {
1435
      $innerArray = array_setr($key, $value, $v);
1436
      if ($innerArray) {
1437
        return $array;
1438
      }
1439
    }
1440
  }
1441
  return $res;
1442
}
1443

    
1444
/**
1445
 * @todo Please document this function.
1446
 * @see http://drupal.org/node/1354
1447
 */
1448
function &get_preceding_contentElement($contentElementKey, array &$renderTemplate) {
1449
  $res = NULL;
1450
  $precedingElement = NULL;
1451
  foreach ($renderTemplate as &$part) {
1452
    foreach ($part as $key => &$element) {
1453
      if ($key == $contentElementKey) {
1454
        return $precedingElement;
1455
      }
1456
      $precedingElement = $element;
1457
    }
1458
  }
1459
  return $res;
1460
}
1461

    
1462
/**
1463
 * @todo Please document this function.
1464
 * @see http://drupal.org/node/1354
1465
 */
1466
function &get_preceding_contentElementKey($contentElementKey, array &$renderTemplate) {
1467
  $res = NULL;
1468
  $precedingKey = NULL;
1469
  foreach ($renderTemplate as &$part) {
1470
    if (is_array($part)) {
1471
      foreach ($part as $key => &$element) {
1472
        if ($key == $contentElementKey) {
1473
          return $precedingKey;
1474
        }
1475
        if (!str_beginsWith($key, '#')) {
1476
          $precedingKey = $key;
1477
        }
1478
      }
1479
    }
1480
  }
1481
  return $res;
1482
}
1483

    
1484
function nameTypeToDTYPE($dtype){
1485
  static $nameTypeLabelMap = array(
1486
    "ICNB" => "BacterialName",
1487
    "ICNAFP" => "BotanicalName",
1488
    "ICNCP" => "CultivarPlantName",
1489
    "ICZN" => "ZoologicalName",
1490
    "ICVCN" => "ViralName",
1491
    "Any taxon name" => "TaxonName",
1492
    "NonViral" => "TaxonName",
1493
    "Fungus" => "BotanicalName",
1494
    "Plant" => "BotanicalName",
1495
    "Algae" => "BotanicalName",
1496
  );
1497
  return $nameTypeLabelMap[$dtype];
1498

    
1499
}
1500

    
1501

    
1502
function compare_name_relations_by_term_order_index($name_rel1, $name_rel2){
1503
  return compare_terms_by_order_index($name_rel1->type, $name_rel2->type);
1504
}
1505

    
1506
/**
1507
 * Provides an array with the different registration types covered by the passed registration.
1508
 *
1509
 * The labels in the returned array are translatable.
1510
 *
1511
 * See also https://dev.e-taxonomy.eu/redmine/issues/8016
1512
 *
1513
 * @param $registration_dto
1514
 * @return array
1515
 *    An array of the labels describing the different registration types covered by the passed registration.
1516
 */
1517
function registration_types($registration_dto){
1518
  $reg_type_labels = array();
1519
  if(isset($registration_dto->nameRef)){
1520
    $reg_type_labels["name"] = t("new name");
1521
    $reg_type_labels["taxon"] = t("new taxon");
1522
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $registration_dto->nameRef->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
1523
    $is_new_combination = true;
1524
    foreach($name_relations as $name_rel){
1525
      if(isset($name_rel->type->uuid)){
1526
        $name_is_from_name = $registration_dto->nameRef->uuid == $name_rel->fromName->uuid;
1527
        switch($name_rel->type->uuid) {
1528
          case UUID_NAMERELATIONSHIPTYPE_BASIONYM:
1529
            if(!$name_is_from_name){
1530
              $reg_type_labels["basionym"] = t("new combination");
1531
              $is_new_combination = true;
1532
            }
1533
            break;
1534
          case UUID_NAMERELATIONSHIPTYPE_REPLACED_SYNONYM:
1535
            if(!$name_is_from_name) {
1536
              $is_new_combination = true;
1537
            }
1538
            break;
1539
          case UUID_NAMERELATIONSHIPTYPE_VALIDATED_BY_NAME:
1540
            if(!$name_is_from_name) {
1541
              $reg_type_labels["validation"] = t("validation");
1542
            }
1543
            break;
1544
          case UUID_NAMERELATIONSHIPTYPE_ORTHOGRAPHIC_VARIANT:
1545
            if(!$name_is_from_name) {
1546
              $reg_type_labels["orth_var"] = t("orthographical correction");
1547
            }break;
1548
          default:
1549
            // NOTHING
1550
        }
1551
      }
1552
    }
1553
    if($is_new_combination){
1554
      unset($reg_type_labels["taxon"]);
1555
    }
1556
  }
1557
  if(isset($registration_dto->orderdTypeDesignationWorkingSets)){
1558
    $reg_type_labels[] = t("new nomenclatural type");
1559
  }
1560
  return $reg_type_labels;
1561
}
1562

    
1563
/**
1564
 * Collects and deduplicates the type designations associated with the passes synonyms.
1565
 *
1566
 * @param $synonymy_group
1567
 *    An array containing a homotypic or heterotypic group of names.
1568
 * @param $accepted_taxon_name_uuid
1569
 *    The uuid of the accepted taxon name. Optional parameter which is required when composing
1570
 *    the information for the homotypic group. In this case the accepted taxon is not included
1571
 *    in the $synonymy_group and must therefor passed in this second parameter.
1572
 *
1573
 * @return array
1574
 *    The type designations
1575
 */
1576
function type_designations_for_synonymy_group($synonymy_group, $accepted_taxon_name_uuid = null)
1577
{
1578
  if (count($synonymy_group) > 0) {
1579
    $name_uuid = array_pop($synonymy_group)->name->uuid;
1580
  } else {
1581
    $name_uuid = $accepted_taxon_name_uuid;
1582
  }
1583
  if ($name_uuid) {
1584
   $type_designations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS_IN_HOMOTYPICAL_GROUP, $name_uuid);
1585
    if ($type_designations) {
1586
      return $type_designations;
1587
    }
1588
  }
1589

    
1590
  return array();
1591
}
1592

    
1593

    
1594
/**
1595
 * Compares the status of two SpecimenTypeDesignations
1596
 *
1597
 * @param object $a
1598
 *   A SpecimenTypeDesignation.
1599
 * @param object $b
1600
 *   SpecimenTypeDesignation.
1601
 */
1602
function compare_specimen_type_designation($a, $b) {
1603

    
1604
  $type_status_order = type_status_order();
1605

    
1606

    
1607
  $aQuantifier = FALSE;
1608
  $bQuantifier = FALSE;
1609
  if (isset($a->typeStatus->titleCache) && isset($b->typeStatus->titleCache)) {
1610
    $aQuantifier = array_search($a->typeStatus->titleCache, $type_status_order);
1611
    $bQuantifier = array_search($b->typeStatus->titleCache, $type_status_order);
1612
  }
1613
  if ($aQuantifier == $bQuantifier) {
1614
    // Sort alphabetically.
1615
    $a_text =  isset($a->typeSpecimen->titleCache) ? preg_replace('/[\[\]\"]/', '', $a->typeSpecimen->titleCache) : '';
1616
    $b_text =  isset($b->typeSpecimen->titleCache) ? preg_replace('/[\[\]\"]/', '', $b->typeSpecimen->titleCache) : '';
1617
    return strcasecmp($a_text, $b_text);
1618
  }
1619
  return ($aQuantifier < $bQuantifier) ? -1 : 1;
1620
}
1621

    
1622
/**
1623
 * Compares the status of two SpecimenTypeDesignations
1624
 *
1625
 * @param object $a
1626
 *   A TypeDesignationStatusBase.
1627
 * @param object $b
1628
 *   TypeDesignationStatusBase.
1629
 */
1630
function compare_type_designation_status($a, $b) {
1631

    
1632
  $type_status_order = type_status_order();
1633

    
1634

    
1635
  $aQuantifier = FALSE;
1636
  $bQuantifier = FALSE;
1637
  if (isset($a->label) && isset($b->label)) {
1638
    $aQuantifier = array_search($a->label, $type_status_order);
1639
    $bQuantifier = array_search($b->label, $type_status_order);
1640
  }
1641
  return ($aQuantifier < $bQuantifier) ? -1 : 1;
1642
}
1643

    
1644

    
1645
/**
1646
 * Compares two SpecimenTypeDesignation status labels
1647
 *
1648
 * @param string $a
1649
 *   A TypeDesignationStatus label.
1650
 * @param string $b
1651
 *   A TypeDesignationStatus label.
1652
 */
1653
function compare_type_designation_status_labels($a, $b) {
1654

    
1655
  $type_status_order = type_status_order();
1656

    
1657

    
1658
  $aQuantifier = FALSE;
1659
  $bQuantifier = FALSE;
1660
  if (isset($a) && isset($b)) {
1661
    $aQuantifier = array_search($a, $type_status_order);
1662
    $bQuantifier = array_search($b, $type_status_order);
1663
  }
1664
  return ($aQuantifier < $bQuantifier) ? -1 : 1;
1665
}
1666

    
1667
/**
1668
 * @return array
1669
 */
1670
function type_status_order()
1671
{
1672
  /*
1673
    This is the desired sort order as of now: Holotype Isotype Lectotype
1674
    Isolectotype Syntype.
1675
    TODO Basically, what we are trying to do is, we define
1676
    an ordered array of TypeDesignation-states and use the index of this array
1677
    for comparison. This array has to be filled with the cdm- TypeDesignation
1678
    states and the order should be parameterisable inside the dataportal.
1679
    */
1680
  // Make that static for now.
1681
  $type_status_order = array(
1682
    'Epitype',
1683
    'Holotype',
1684
    'Isotype',
1685
    'Lectotype',
1686
    'Isolectotype',
1687
    'Syntype',
1688
    'Paratype'
1689
  );
1690
  return $type_status_order;
1691
}
(5-5/10)