Project

General

Profile

Download (63.5 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 $name_link
257
 *    URI to the taxon, @see path_to_taxon(), must be processed by url() before passing to this method
258
 * @param $reference_link
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, $name_link = NULL, $reference_link = 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(), $name_link, $reference_link);
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>',
480
          $renderTemplate);
481
    }
482
  }
483

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

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

    
522
          }
523
        }
524
      }
525
    }
526
    array_setr('description', $descriptionHtml, $renderTemplate);
527
  }
528

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

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

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

    
578

    
579

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

    
606
  if(!(isset($registration_dto->identifier) && $registration_dto->status == 'PUBLISHED')){
607
    return $render_array;
608
  }
609

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

    
615
    '#suffix' => '</div>'
616
  );
617

    
618
  // name
619
  if($registration_dto->nameRef){
620
    $name = cdm_ws_get(CDM_WS_PORTAL_NAME, $registration_dto->nameRef->uuid);
621
    cdm_load_tagged_full_title($name);
622
    $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);
623
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $registration_dto->nameRef->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
624
    $render_array['nomenclatural_act']['name_relations'] = compose_name_relationships_list($name_relations, $registration_dto->nameRef->uuid, null);
625
    $render_array['nomenclatural_act']['name_relations']['#weight'] = 10;
626
  } else {
627
    // in this case the registration must have a
628
    $name = cdm_ws_get(CDM_WS_PORTAL_NAME, $registration_dto->typifiedNameRef->uuid);
629
    $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);
630
  }
631
  // typedesignation in detail
632
  if(is_object($registration_dto->orderdTypeDesignationWorkingSets)) {
633
    $field_unit_uuids = array();
634
    $specimen_type_designation_refs = array();
635
    $name_type_designation_refs = array();
636
    foreach ((array)$registration_dto->orderdTypeDesignationWorkingSets as $workingset_ref => $obj) {
637
      $tokens = explode("#", $workingset_ref);
638
      $types_in_fieldunit = get_object_vars($obj); // convert into associative array
639

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

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

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

    
695
  return $render_array;
696
}
697

    
698

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

    
721
  if(!(isset($registration_dto->identifier) && $registration_dto->status == 'PUBLISHED')){
722
    return $render_array;
723
  }
724

    
725
  $registration_date_insitute_markup = render_registration_date_and_institute($registration_dto, 'span');
726
  $itentifier_markup = l($registration_dto->identifier, path_to_registration($registration_dto->identifier), array('attributes' => array('class' => array('identifier'))));
727

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

    
765
  return $render_array;
766
}
767

    
768

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

    
797

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

    
816

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

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

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

    
853

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

    
880
    $render_array['map'] = compose_type_designations_map($type_designations);
881
  }
882
  return $render_array;
883
}
884

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

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

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

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

    
964
  $render_array = array();
965

    
966
  $type_designation_list = array();
967
  uksort($type_entity_refs, "compare_type_designation_status_labels");
968
  foreach($type_entity_refs as $type_status => $specimen_types){
969
    foreach($specimen_types as $specimen_type){
970

    
971
      $type_designation = cdm_ws_get(CDM_WS_PORTAL_TYPEDESIGNATION, array($specimen_type->uuid));
972
      $type_designation_list[] = $type_designation; // collect for the map
973

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

    
978

    
979
      $preferredStableUri = '';
980
      $citation_markup = '';
981
      $media = '';
982

    
983
      // preferredStableUri
984
      if(isset($type_designation->typeSpecimen->preferredStableUri) && $type_designation->typeSpecimen->preferredStableUri){
985
        $preferredStableUri = $type_designation->typeSpecimen->preferredStableUri;
986
      }
987

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

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

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

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

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

    
1058
  $relationship_markup = null;
1059

    
1060
  $current_name_is_toName = $current_name_uuid == $name_rel->toName->uuid;
1061

    
1062
  if($current_name_is_toName){
1063
    $name = $name_rel->fromName;
1064
  } else {
1065
    $name = $name_rel->toName;
1066
  }
1067

    
1068
  cdm_load_tagged_full_title($name);
1069

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

    
1083
  return $relationship_markup;
1084
}
1085

    
1086

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

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

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

    
1136
  $list_prefix = '<span class="name_relationships">[';
1137
  $list_suffix = ']</span>';
1138
  $item_prefix = '<span class="item">';
1139
  $item_suffix = '</span> ';
1140
  $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);
1141

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

    
1148
  RenderHints::popFromRenderStack();
1149
  return $render_array;
1150
}
1151

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

    
1176
  // $ordered_name_relation_type_uuids = array_keys(cdm_terms_by_type_as_option('NameRelationshipType', CDM_ORDER_BY_ORDER_INDEX_ASC));
1177

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

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

    
1192
  $list_prefix = '<div class="relationships_list name_relationships">';
1193
  $list_suffix = '</div>';
1194
  $item_prefix = '<div class="item">';
1195
  $item_suffix = '</div>';
1196

    
1197
  $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);
1198

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

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

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

    
1241
  if ($name_relations) {
1242

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

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

    
1265
          $filtered_name_rels[] = $name_rel;
1266
        }
1267
      }
1268
    }
1269
    $name_relations = $filtered_name_rels;
1270

    
1271
    usort($name_relations, 'compare_name_relations_by_term_order_index');
1272

    
1273
    // compose
1274
    foreach ($name_relations as $name_rel) {
1275

    
1276
      $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1277

    
1278
      $rel_footnote_key_markup = name_relationship_footnote_markup($name_rel);
1279
      $relationship_markup = name_relationship_markup($name_rel, $current_name_uuid, $current_taxon_uuid);
1280

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

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

    
1313
    // orthographic variants
1314
    if (count($orthographic_variants) > 0) {
1315
      foreach ($orthographic_variants as $name_rel) {
1316

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

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

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

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

    
1403

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

    
1416

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

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

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

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

    
1502
}
1503

    
1504

    
1505
function compare_name_relations_by_term_order_index($name_rel1, $name_rel2){
1506
  return compare_terms_by_order_index($name_rel1->type, $name_rel2->type);
1507
}
1508

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

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

    
1593
  return array();
1594
}
1595

    
1596

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

    
1607
  $type_status_order = type_status_order();
1608

    
1609

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

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

    
1635
  $type_status_order = type_status_order();
1636

    
1637

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

    
1647

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

    
1658
  $type_status_order = type_status_order();
1659

    
1660

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

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