Project

General

Profile

Download (85.9 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 or 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 $split_render_templates = NULL;
76

    
77
  if($split_render_templates == NULL) {
78
    $render_templates = variable_get(NameRenderConfiguration::CDM_NAME_RENDER_TEMPLATES, NameRenderConfiguration::CDM_NAME_RENDER_TEMPLATES_DEFAULT);
79
    // needs to be converted to an array
80
    $render_templates = (object_to_array($render_templates));
81

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

    
95
  // get the base element of the renderPath
96
  if (($separatorPos = strpos($render_path, '.')) > 0) {
97
    $renderPath_base = substr($render_path, 0, $separatorPos);
98
  } else {
99
    $renderPath_base = $render_path;
100
  }
101

    
102
  $template = NULL;
103
  // 1. try to find a template using the render path base element
104
  if(array_key_exists($renderPath_base, $split_render_templates)){
105
    $template = (array)$split_render_templates[$renderPath_base];
106
  }
107

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

    
122

    
123
  // 3. Otherwise get default RenderTemplate from theme.
124
  if (!is_array($template)) {
125
    $template = $split_render_templates['#DEFAULT'];
126
  }
127

    
128
  // --- set the link uris to the according template fields if they exist
129
  if(isset($template['nameAuthorPart']) && isset($template['nameAuthorPart']['#uri'])) {
130
    if ($nameLink) {
131
      $template['nameAuthorPart']['#uri'] = $nameLink;
132
    }
133
    else {
134
      unset($template['nameAuthorPart']['#uri']);
135
    }
136
  }
137

    
138
  if ($nameLink && isset($template['namePart']['#uri'])) {
139
    $template['namePart']['#uri'] = $nameLink;
140
  }
141
  else {
142
    unset($template['namePart']['#uri']);
143
  }
144

    
145
  if ($referenceLink && isset($template['referencePart']['#uri'])) {
146
    $template['referencePart']['#uri'] = $referenceLink;
147
  }
148
  else {
149
    unset($template['referencePart']['#uri']);
150
  }
151

    
152
  return $template;
153
}
154

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

    
220
  static $part_definitions = null;
221
  if (!isset($part_definitions)) {
222
    $part_definitions = object_to_array(variable_get(NameRenderConfiguration::CDM_PART_DEFINITIONS, NameRenderConfiguration::CDM_PART_DEFINITIONS_DEFAULT));
223
  }
224

    
225
  $dtype = nameTypeToDTYPE($taxonNameType);
226
  if (array_key_exists($taxonNameType, $part_definitions)) {
227
    return $part_definitions[$taxonNameType];
228
  } else if (array_key_exists($dtype, $part_definitions)) {
229
    return $part_definitions[$dtype];
230
  } else {
231
    return $part_definitions['#DEFAULT']; // covers ViralNames and general NonViralNames
232
  }
233

    
234
}
235

    
236

    
237
/**
238
 * Renders the markup for a CDM TaxonName instance.
239
 *
240
 * The layout of the name representation is configured by the
241
 * part_definitions and render_templates (see get_partDefinition() and
242
 * get_nameRenderTemplate())
243
 *
244
 * @param $taxon_name_or_taxon_base
245
 *    A cdm TaxonBase or TaxonName entity
246
 * @param $name_link
247
 *    URI to the taxon, the path provided by path_to_taxon() must be processed
248
 *    by url() before passing to this method
249
 * @param $reference_link
250
 *    URI to the reference, the path provided by path_to_reference() must be
251
 *    processed by url() before passing to this method
252
 * @param bool $show_taxon_name_annotations
253
 *    Enable the display of footnotes for annotations on the taxon and name
254
 *    (default: true)
255
 * @param bool $is_type_designation
256
 *    To indicate that the supplied taxon name is a name type designation.
257
 *    (default: false)
258
 * @param array $skip_render_template_parts
259
 *    The render template elements matching these part names will bes skipped.
260
 *    This parameter should only be used in rare cases like for suppressing
261
 *    the sec reference of synonyms. Normally the configuration of the
262
 *    name appearance should only be done via the render templates themselves. (default: [])
263
 * @param bool $is_invalid
264
 *   Indicates that this taxon is invalid. In this case the name part will be shown in double quotes.
265
 *   This is useful when rendering taxon relation ships. (default: false)
266
 *
267
 * @return string
268
 *  The markup for a taxon name.
269
 */
270
function render_taxon_or_name($taxon_name_or_taxon_base, $name_link = NULL, $reference_link = NULL,
271
  $show_taxon_name_annotations = true, $is_type_designation = false, $skip_render_template_parts = [], $is_invalid = false) {
272

    
273
  $is_doubtful = false;
274
  $taxon_base = null;
275
  $nom_status_fkey = null; // FootNoteKey
276
  if($taxon_name_or_taxon_base->class == 'Taxon' || $taxon_name_or_taxon_base->class == 'Synonym'){
277
    $taxon_base = $taxon_name_or_taxon_base;
278
    if(isset($taxon_name_or_taxon_base->name)){
279
      $taxon_name = $taxon_name_or_taxon_base->name;
280
    } else {
281
      $taxon_name = cdm_ws_get(CDM_WS_TAXON . '/$0/name', array($taxon_name_or_taxon_base->uuid));
282
    }
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
    $taxon_name = $taxon_name_or_taxon_base;
289
    if(isset($taxon_name->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($taxon_name->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
  foreach($skip_render_template_parts as $part){
312
    unset($renderTemplate[$part]);
313
  }
314

    
315
  $secref_tagged_text = tagged_text_extract_reference_and_detail($tagged_title);
316
  $secref_name_inSource_tagged_text = tagged_text_extract_secReference_name_in_source($tagged_title);
317
  // taxon names will have the nomenclatural reference in the tagged full title:
318
  $nomref_tagged_text = tagged_text_extract_reference($tagged_title);
319
  $nom_status_tagged_text = tagged_text_extract_nomstatus($tagged_title);
320
  $appended_phrase_tagged_text = array(); // this is filled later
321

    
322
  normalize_tagged_text($tagged_title);
323

    
324
  $is_valid_tagged_title =
325
    isset($tagged_title)
326
    && is_array($tagged_title)
327
    && isset($tagged_title[0]->text)
328
    && is_string($tagged_title[0]->text)
329
    && $tagged_title[0]->text != ''
330
    && isset($tagged_title[0]->type);
331
  $lastAuthorElementString = FALSE;
332

    
333
  $name_encasement = $is_invalid ? '"' : '';
334
  $doubtful_marker = $is_doubtful ? '?&#8239;' : ''; // 	&#8239; =  NARROW NO-BREAK SPACE
335
  $doubtful_marker_markup = '';
336

    
337
  if($doubtful_marker){
338
    $doubtful_marker_markup = '<span class="doubtful">' . $doubtful_marker . '</span>';
339
    if($tagged_title[0]->text == '?' ){
340
      // remove the first tagged text element
341
      unset($tagged_title[0]);
342
    }
343
  }
344

    
345
  // split off all appendedPhrase item  from the end of the array (usually there only should  be one)
346
  while($tagged_title[count($tagged_title)-1]->type == "appendedPhrase"){
347
    $appended_phrase_tagged_text[] = array_pop($tagged_title);
348
  }
349

    
350
  // Got to use second entry as first one, see ToDo comment below ...
351
  if ($is_valid_tagged_title) {
352

    
353
    $taggedName = $tagged_title;
354
    $hasNamePart_with_Authors = isset($renderTemplate['namePart']) && isset($renderTemplate['namePart']['authors']);
355
    $hasNameAuthorPart_with_Authors = isset($renderTemplate['nameAuthorPart']) && isset($renderTemplate['nameAuthorPart']['authors']);
356

    
357

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

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

    
388

    
389
  if(isset($appended_phrase_tagged_text[0])){
390
    $name .= ' <span class="appended-phrase">'. cdm_tagged_text_to_markup($appended_phrase_tagged_text) . '</span>';
391
  }
392

    
393
  // Fill name into $renderTemplate.
394
  array_setr('name', $name , $renderTemplate);
395

    
396
  // Fill with authorTeam.
397
  /*
398
  if($authorTeam){
399
    $authorTeamHtml = ' <span class="authorTeam">'.$authorTeam.'</span>';
400
    array_setr('authorTeam', $authorTeamHtml, $renderTemplate);
401
  }
402
  */
403

    
404
  // Fill with reference.
405
  if (isset($renderTemplate['referencePart']) && !$is_type_designation) {
406

    
407
    $registrations = cdm_ws_get(CDM_WS_NAME, array($taxon_name->uuid, "registrations"));
408
    $registration_markup = render_registrations($registrations);
409

    
410
    // default separator
411
    $separator = '';
412

    
413
    // [Eckhard]:"Komma nach dem Taxonnamen ist grundsätzlich falsch,
414
    // Komma nach dem Autornamen ist überall dort falsch, wo ein "in" folgt."
415
    if (isset($renderTemplate['referencePart']['reference']) && isset($taxon_name->nomenclaturalSource)) {
416
      $microreference = $taxon_name->nomenclaturalSource->citationMicroReference;
417
      if(count($nomref_tagged_text) == 0 && isset($taxon_name->nomenclaturalSource->citation)){
418
        // drupal message for debugging of #9599
419
        // drupal_set_message("reference/$0/nomenclaturalCitation' must no longer be used (type: "
420
        //  . $taxon_name_or_taxon_base->class . (isset($taxon_name_or_taxon_base->type) ? " - " +$taxon_name_or_taxon_base->type : ""  . ")"), "error");
421
        $citation = cdm_ws_getNomenclaturalReference($taxon_name->nomenclaturalSource->citation->uuid, $microreference);
422
        // Find preceding element of the reference.
423
        $precedingKey = get_preceding_contentElementKey('reference', $renderTemplate);
424
        if (str_beginsWith($citation, ", in")) {
425
          $citation = substr($citation, 2);
426
          $separator = ' ';
427
        }
428
        elseif (!str_beginsWith($citation, "in") && $precedingKey == 'authors') {
429
          $separator = ', ';
430
        } else {
431
          $separator = ' ';
432
        }
433
        $referenceArray['#separator'] = $separator;
434
        $referenceArray['#html'] = '<span class="reference">' . $citation . '</span>' . $registration_markup;
435
      } else {
436
        // this is the case for taxon names
437
        $referenceArray['#html'] = cdm_tagged_text_to_markup($nomref_tagged_text);
438
      }
439

    
440
      array_setr('reference', $referenceArray, $renderTemplate);
441
    }
442

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

    
460
  $is_reference_year = false;
461
  if (isset($renderTemplate['referenceYearPart']['reference.year'])) {
462
    if(isset($taxon_name->nomenclaturalSource->citation->datePublished)){
463
      $referenceArray['#html'] = ' <span class="reference">' . timePeriodToString($taxon_name->nomenclaturalSource->citation->datePublished) . '</span>';
464
      array_setr('reference.year', $referenceArray, $renderTemplate);
465
      $is_reference_year = true;
466
    }
467
  }
468

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

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

    
502
  // Fill with protologues etc...
503
  $protologue_links = [];
504
  if (array_setr('description', TRUE, $renderTemplate)) {
505
    $external_links = cdm_ws_get(CDM_WS_NAME_PROTOLOGUE_LINKS, $taxon_name->uuid);
506
    if($external_links){
507
      foreach ($external_links as $link) {
508
        if (!empty($link->uri)) {
509
          // for the link see also cdm_external_uri()
510
          $protologue_links[] = l(font_awesome_icon_markup('fa-book'), $link->uri, ['html' => true]);
511
          }
512
        }
513
      }
514

    
515
    // ---------------
516

    
517
    $additional_pub_markup = '';
518
      $descriptions = cdm_ws_get(CDM_WS_PORTAL_NAME_DESCRIPTIONS, $taxon_name->uuid);
519
      if($descriptions) {
520
        foreach ($descriptions as $description) {
521
          if (!empty($description)) {
522
            $additional_citations = [];
523
            $additional_data = [];
524
            foreach ($description->elements as $description_element) {
525
              if (isset($description_element->multilanguageText_L10n) && $description_element->multilanguageText_L10n->text) {
526
                RenderHints::setAnnotationsAndSourceConfig(synonymy_annotations_and_source_config());
527
                $annotations_and_sources = handle_annotations_and_sources($description_element);
528
                // synonymy_annotations_and_source_config() has 'sources_as_content' => FALSE, so no need to handle inline sources here
529
                $element_media = cdm_description_element_media(
530
                  $description_element,
531
                  [
532
                    'application/pdf',
533
                    'image/png',
534
                    'image/jpeg',
535
                    'image/gif',
536
                    'text/html',
537
                  ]
538
                );
539
                if (isset($description_element->feature) && $description_element->feature->uuid == UUID_ADDITIONAL_PUBLICATION) {
540
                   $additional_citations[] = ' [& ' . trim($description_element->multilanguageText_L10n->text) . $element_media . $annotations_and_sources->footNoteKeysMarkup() .']';
541
                } else {
542
                  $additional_data[] = ' [' . trim($description_element->multilanguageText_L10n->text) . $element_media . $annotations_and_sources->footNoteKeysMarkup(). ']';
543
                }
544
              }
545
            }
546
            // merge
547
            $additional_citations = array_merge($additional_citations, $additional_data);
548
            $additional_pub_markup .= join(',', $additional_citations);
549
          }
550
        }
551
      }
552
      if($additional_pub_markup){
553
        $additional_pub_markup = ' ' . $additional_pub_markup . '. '; // surround with space etc.
554
      }
555
      array_setr('description', $additional_pub_markup . join(', ', $protologue_links), $renderTemplate);
556
      array_replace_keyr('description', 'protologue', $renderTemplate); // in preparation for #9319
557
  }
558

    
559
  // Render.
560
  $out = '';
561
  if(isset($_REQUEST['RENDER_PATH'])){
562
    // developer option to show the render path with each taxon name
563
    $out .= '<span class="render-path">' . RenderHints::getRenderPath() . '</span>';
564
  }
565
  $out .= '<span class="' . html_class_attribute_ref($taxon_name_or_taxon_base)
566
    . '" data-cdm-ref="/name/' . $taxon_name->uuid . '" data-cdm-render-path="' . RenderHints::getRenderPath() .'">';
567
   // . '" data-cdm-ref="/name/' . $taxon_name->uuid . '">';
568
  foreach ($renderTemplate as $partName => $part) {
569
    $separator = '';
570
    $partHtml = '';
571
    $uri = FALSE;
572
    if (!is_array($part)) {
573
      continue;
574
    }
575
    if (isset($part['#uri']) && is_string($part['#uri'])) {
576
      $uri = $part['#uri'];
577
      unset($part['#uri']);
578
    }
579
    foreach ($part as $part => $content) {
580
      $html = '';
581
      if (is_array($content)) {
582
        $html = $content['#html'];
583
        if(isset($content['#separator'])) {
584
          $separator = $content['#separator'];
585
        }
586
      }
587
      elseif (is_string($content)) {
588
        $html = $content;
589
      }
590
      if($html){ // skip empty elements
591
        $partHtml .= '<span class="' . $part . '">' . $html . '</span>';
592
      }
593
    }
594
    if ($uri) {
595
      // cannot use l() here since the #uri already should have been processed through uri() at this point
596
      $out .= $separator . '<a href="' . $uri . '" class="' . $partName . '">' . $partHtml . '</a>';
597

    
598
    }
599
    else {
600
      $out .= $separator . $partHtml;
601
    }
602
  }
603
  $out .= '</span>';
604

    
605
  $annotations_and_sources = new AnnotationsAndSources();
606
  if($nom_status_fkey){
607
    // the nomenclatural status footnote key refers to the source citation
608
    $annotations_and_sources->addFootNoteKey($nom_status_fkey);
609
  }
610
  if ($show_taxon_name_annotations) {
611
    if($taxon_base){
612
      $annotations_and_sources = handle_annotations_and_sources($taxon_base,
613
        null, null, $annotations_and_sources);
614
    }
615
    $annotations_and_sources = handle_annotations_and_sources($taxon_name,
616
      null, null, $annotations_and_sources);
617
  }
618
  $out .= $annotations_and_sources->footNoteKeysMarkup();
619
  return $out;
620
}
621

    
622

    
623

    
624
/**
625
 * Composes information for a registration from a dto object.
626
 *
627
 * Registrations which are not yet published are suppressed.
628
 *
629
 * @param $registration_dto
630
 * @param $with_citation
631
 *   Whether to show the citation.
632
 *
633
 * @return array
634
 *    A drupal render array with the elements:
635
 *    - 'name'
636
 *    - 'name-relations'
637
 *    - 'specimen_type_designations'
638
 *    - 'name_type_designations'
639
 *    - 'citation'
640
 *    - 'registration_date_and_institute'
641
 * @ingroup compose
642
 */
643
function compose_registration_dto_full($registration_dto, $with_citation = true)
644
{
645
  $render_array = array(
646
    '#prefix' => '<div class="registration">',
647
    '#suffix' => '</div>'
648
  );
649

    
650
  if(!(isset($registration_dto->identifier) && $registration_dto->status == 'PUBLISHED')){
651
    return $render_array;
652
  }
653

    
654
  $render_array['sub_headline'] = markup_to_render_array(join(", ", registration_types($registration_dto)),-10, '<h3 class="registration_type">' . t('Event: '), '</h3>' );
655
  $render_array['nomenclatural_act'] = array(
656
    '#weight' => 0,
657
    '#prefix' => '<div class="nomenclatural_act">',
658

    
659
    '#suffix' => '</div>'
660
  );
661

    
662
  $typified_name = null;
663

    
664
  // Nomenclatural act block element
665
  $last_footnote_listkey = RenderHints::setFootnoteListKey("nomenclatural_act");
666
  // name
667
  $name_relations = null;
668
  if(isset($registration_dto->nameRef) && $registration_dto->nameRef){
669
    $name = cdm_ws_get(CDM_WS_PORTAL_NAME, $registration_dto->nameRef->uuid);
670
    cdm_load_tagged_full_title($name);
671
    $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);
672
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $registration_dto->nameRef->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
673
    // need to create the name relationships later, so that the foot notes are in correct order, see section // name relations
674
  } else {
675
    // in this case the registration must have a
676
    // typified name will be rendered later
677
    $typified_name = cdm_ws_get(CDM_WS_PORTAL_NAME, $registration_dto->typifiedNameRef->uuid);
678

    
679
  }
680

    
681
  // typedesignation in detail
682
  if(is_object($registration_dto->orderedTypeDesignationSets)) {
683
    $field_unit_uuids = array();
684
    $specimen_type_designation_refs = array();
685
    $name_type_designation_refs = array();
686
    foreach ((array)$registration_dto->orderedTypeDesignationSets as $workingset_ref => $obj) {
687
      $tokens = explode("#", $workingset_ref);
688
      $types_in_fieldunit = get_object_vars($obj); // convert into associative array
689

    
690
      if ($tokens[0] == 'NameTypeDesignation') {
691
        foreach ($types_in_fieldunit as $type_status => $entity_reference_list) {
692
          if(!isset($name_type_designation_refs[$type_status])){
693
            $name_type_designation_refs[$type_status]  = $entity_reference_list;
694
          } else {
695
            $specimen_type_designation_refs[$type_status] = array_merge($specimen_type_designation_refs[$type_status], $entity_reference_list);
696
          }
697
        }
698
      } else if ($tokens[0] == 'FieldUnit'){
699
        $field_unit_uuids[] = $tokens[1];
700
        foreach ($types_in_fieldunit as $type_status => $entity_reference_list) {
701
          if(!isset($specimen_type_designation_refs[$type_status])){
702
            $specimen_type_designation_refs[$type_status] =  $entity_reference_list;
703
          } else {
704
            array_push($specimen_type_designation_refs[$type_status], $entity_reference_list);
705
          }
706
        }
707
      } else {
708
        drupal_set_message("Unimplemented type: " . $tokens[0], 'error');
709
      }
710
    }
711
    // type designations which are in this nomenclatural act.
712
    if (count($name_type_designation_refs) > 0) {
713
      $render_array['nomenclatural_act']['name_type_designations'] = compose_name_type_designations($name_type_designation_refs);
714
      $render_array['nomenclatural_act']['name_type_designations']['#prefix'] = '<p class="name_type_designations">';
715
      $render_array['nomenclatural_act']['name_type_designations']['#suffix'] = '</p>';
716
      $render_array['nomenclatural_act']['name_type_designations']['#weight'] = 20;
717
    }
718
    if (count($field_unit_uuids) > 0) {
719
      $specimen_type_designations_array = compose_specimen_type_designations($specimen_type_designation_refs, true);
720
      $render_array['nomenclatural_act']['specimen_type_designations'] = $specimen_type_designations_array['type_designations'];
721
      $render_array['map'] = $specimen_type_designations_array['map'];
722
      $render_array['map']['#weight'] = $render_array['nomenclatural_act']['#weight'] + 20;
723
    }
724
  }
725

    
726
  // name relations
727
  if($name_relations){
728
    $render_array['nomenclatural_act']['name_relations'] = compose_name_relationships_list($name_relations, $registration_dto->nameRef->uuid, null);
729
    $render_array['nomenclatural_act']['name_relations']['#weight'] = 10;
730
  }
731

    
732
  // citation
733
  if ($with_citation) {
734
    $render_array['citation'] = markup_to_render_array(
735
      "<div class=\"citation nomenclatural_act_citation" . html_class_attribute_ref(new TypedEntityReference("Reference", $registration_dto->citationUuid)) . "\">"
736
      . "<span class=\"label\">published in: </span>"
737
      . $registration_dto->bibliographicInRefCitationString
738
      . l(custom_icon_font_markup('icon-interal-link-alt-solid', array('class' => array('superscript'))), path_to_reference($registration_dto->citationUuid), array('html' => true))
739
      . "</div>",
740
      $render_array['nomenclatural_act']['#weight'] + 10 );
741
  }
742

    
743
  $render_array['nomenclatural_act']['footnotes'] = markup_to_render_array(render_footnotes(),100);
744

    
745
  // END of nomenclatural act block
746
  RenderHints::setFootnoteListKey($last_footnote_listkey );
747

    
748
  if($typified_name){
749
    $render_array['typified_name'] = markup_to_render_array('<p class="typified-name">for ' . render_taxon_or_name($typified_name, url(path_to_name($typified_name->uuid))) . '</p>', 40);
750
  }
751

    
752
  // registration date and office
753
  $registration_date_insitute_markup = render_registration_date_and_institute($registration_dto);
754
  if($registration_date_insitute_markup){
755
    $render_array['registration_date_and_institute'] = markup_to_render_array(
756
      $registration_date_insitute_markup . '</p>',
757
      100);
758
  }
759

    
760
  $render_array['page_footnotes'] = markup_to_render_array(render_footnotes(), 110);
761

    
762
  return $render_array;
763
}
764

    
765

    
766
/**
767
 * Composes a compact representation for a registrationDTO object
768
 *
769
 * Registrations which are not yet published are suppressed.
770
 *
771
 * @param $registration_dto
772
 * @param $style string
773
 *   The style of how to compose the 'identifier' and 'registration_date_and_institute' part with the summary
774
 *   - 'citation': Similar to the appearance of nomenclatural acts in print media
775
 *   - 'list-item' : style suitable for result lists etc
776
 *
777
 * @return array
778
 *    A drupal render array with the elements:
779
 *    - 'registration-metadata' when $style == 'list-item'
780
 *    - 'summary'
781
 * @ingroup compose
782
 */
783
function compose_registration_dto_compact($registration_dto, $style = 'citation', $tag_enclosing_summary = 'p')
784
{
785
  $render_array = array();
786
  $media_link_map = array();
787

    
788
  if(!(isset($registration_dto->identifier) && $registration_dto->status == 'PUBLISHED')){
789
    return $render_array;
790
  }
791

    
792
  $registration_date_institute_markup = render_registration_date_and_institute($registration_dto, 'span');
793
  $identifier_markup = render_link_to_registration($registration_dto->identifier);
794

    
795
  $tagged_text_options = array();
796
  if(isset($registration_dto->nameRef)){
797
    $tagged_text_options[] = array(
798
      'filter-type' => 'name',
799
      'prefix' => '<span class="registered_name">',
800
      'suffix' => '</span>',
801
    );
802
  } else {
803
    $tagged_text_options[] = array(
804
      'filter-type' => 'name',
805
      'prefix' => '<span class="referenced_typified_name">',
806
      'suffix' => '</span>',
807
    );
808
  }
809
  cdm_tagged_text_add_options($registration_dto->summaryTaggedText, $tagged_text_options);
810
  $tagged_text_cropped = tagged_text_crop_at($registration_dto->summaryTaggedText, 'reference', '/[dD]esignated\s+[bB]y/');
811
  $tagged_text_expanded = cdm_tagged_text_expand_entity_references($tagged_text_cropped);
812
  foreach ($tagged_text_expanded  as $tagged_text){
813
    if(isset($tagged_text->entityReference->type) && $tagged_text->entityReference->type == 'SpecimenTypeDesignation') {
814
      $mediaDTOs = cdm_ws_get('typedesignation/$0/media', array($tagged_text->entityReference->uuid));
815
      if(isset($mediaDTOs[0]->uri)){
816
        $media_url_key = '{link-' . $mediaDTOs[0]->uuid . '}';
817
        $tagged_text->text = str_replace('[icon]', '[icon]' . $media_url_key, $tagged_text->text);
818
        $media_link_map[$media_url_key] =  cdm_external_uri($mediaDTOs[0]->uri, true);
819
      }
820
    }
821
  }
822
  $registation_markup = cdm_tagged_text_to_markup($tagged_text_expanded);
823
  foreach($media_link_map as $media_url_key => $link){
824
    $registation_markup = str_replace($media_url_key, $link, $registation_markup);
825
  }
826
  if($style == 'citation') {
827
    $registation_markup = $registation_markup . ' ' . $identifier_markup . ' ' . $registration_date_institute_markup;
828
  } else {
829
    $render_array['registration-metadata'] = markup_to_render_array('<div class="registration-metadata">' . $identifier_markup . ' ' . $registration_date_institute_markup. "</div>", -10);
830
  }
831
  $render_array['summary'] = markup_to_render_array('<' . $tag_enclosing_summary . ' class="registration-summary">' . $registation_markup . '</' . $tag_enclosing_summary . '>', 0);
832

    
833
  return $render_array;
834
}
835

    
836
/**
837
 * Renders the registrationDate and institutionTitleCache of the $registration_dto as markup.
838
 *
839
 * @param $registration_dto
840
 * @return string
841
 *    The markup or an empty string
842
 */
843
function render_registration_date_and_institute($registration_dto, $enclosing_tag = 'p') {
844
  $registration_date_institute_markup = '';
845
  if ($registration_dto->registrationDate) {
846
    $date_string = format_datetime($registration_dto->registrationDate);
847
    if (isset($registration_dto->institutionTitleCache) && $registration_dto->institutionTitleCache) {
848
      $registration_date_institute_markup =
849
        t("Registration on @date in @institution", array(
850
          '@date' => $date_string,
851
          '@institution' => $registration_dto->institutionTitleCache,
852
        ));
853
    } else {
854
      $registration_date_institute_markup =
855
        t("Registration on @date", array(
856
          '@date' => $date_string
857
        ));
858
    }
859
    $registration_date_institute_markup = '<' .$enclosing_tag . ' class="registration-date-and-institute">'. $registration_date_institute_markup . '</' .$enclosing_tag . '>';
860
  }
861
  return $registration_date_institute_markup;
862
}
863

    
864

    
865
/**
866
 * @param $registrations
867
 * @return string
868
 */
869
function render_registrations($registrations)
870
{
871
  $registration_markup = '';
872
  $registration_markup_array = array();
873
  if ($registrations) {
874
    foreach ($registrations as $reg) {
875
      $registration_markup_array[] = render_registration($reg);
876
    }
877
    $registration_markup = " Registration" . (count($registration_markup_array) > 1 ? 's: ' : ': ')
878
      . join(', ', $registration_markup_array);
879
  }
880
  return $registration_markup;
881
}
882

    
883

    
884
/**
885
 * Renders a registration
886
 *
887
 * TODO replace by compose_registration_dto_compact
888
 * @param $registration
889
 */
890
function render_registration($registration){
891
  $markup = '';
892

    
893
  if(isset($registration->identifier) && $registration->status == 'PUBLISHED'){
894
    $office_class_attribute = '';
895
    if(isset($registration->institution->titleCache)){
896
      $office_class_attribute = registration_institution_class_attribute($registration);
897
    }
898
    $markup = "<span class=\"registration $office_class_attribute\">" . render_link_to_registration($registration->identifier) . ', '
899
      .  preg_replace('/^([^T]*)(.*)$/', '${1}', $registration->registrationDate)
900
      . '</span>';
901
  }
902
  return $markup;
903
}
904

    
905
/**
906
 * @param $registration
907
 * @return string
908
 */
909
function registration_institution_class_attribute($registration_dto)
910
{
911
  if(isset($registration_dto->institutionTitleCache)){
912
    $institutionTitleCache = $registration_dto->institutionTitleCache;
913
  } else {
914
    // fall back option to also support cdm entities
915
    $institutionTitleCache = @$registration_dto->institution->titleCache;
916
  }
917
  return $institutionTitleCache ? 'registration-' . strtolower(preg_replace('/[^a-zA-Z0-9]/', '-', $institutionTitleCache)) : '';
918
}
919

    
920

    
921
/**
922
 * Renders and array of CDM TypeDesignations
923
 *
924
 *  - NameTypeDesignation
925
 *  - SpecimenTypeDesignation
926
 *  - TextualTypeDesignation
927
 *
928
 * @param array $type_designations an array of cdm TypeDesignation entities
929
 *  to render
930
 * @param string $enclosing_tag the tag element type to enclose the whole list
931
 *  of type designation with. By default this DOM element is <ul>
932
 * @param string $element_tag the tag element type to be used for each
933
 *  type designation item.
934
 * @param bool $link_to_specimen_page whether a specimen in type designation element
935
 *  should be a link or not.
936
 *
937
 * @return string The markup.
938
 *
939
 * @InGroup Render
940
 */
941
function render_type_designations($type_designations, $enclosing_tag = 'ul', $element_tag =  'li', $link_to_specimen_page = true) {
942

    
943
  // need to add element to render path since type designations
944
  // need other name render template
945
  RenderHints::pushToRenderStack('typedesignations');
946

    
947
  $out = '<' . $enclosing_tag .' class="typeDesignations">';
948
  $specimen_type_designations = array();
949
  $name_type_designations = array();
950
  $textual_type_designations = array();
951
  $separator = ',';
952

    
953
  foreach ($type_designations as $type_designation) {
954
    switch ($type_designation->class) {
955
      case 'SpecimenTypeDesignation':
956
        $specimen_type_designations[] = $type_designation;
957
        break;
958
      case 'NameTypeDesignation':
959
        $name_type_designations[] = $type_designation;
960
        break;
961
      case 'TextualTypeDesignation':
962
        $textual_type_designations[] = $type_designation;
963
        break;
964
      default:  throw new Exception('Unknown type designation class: ' . $type_designation->class);
965
    }
966
  }
967

    
968
  // NameTypeDesignation ..................................
969
  if(!empty($name_type_designations)){
970
    usort($name_type_designations, "compare_type_designations_by_status");
971
    foreach($name_type_designations as $name_type_designation){
972
      if ($name_type_designation->notDesignated) {
973
        $out .= '<'. $element_tag .' class="' . html_class_attribute_ref($name_type_designation) . '">' .  type_designation_status_label_markup($name_type_designation)  . ': '
974
          . t('not designated') . '</'. $element_tag .'>';
975
      }
976
      elseif (isset($name_type_designation->typeName)) {
977
        $link_to_name_page = url(path_to_name($name_type_designation->typeName->uuid));
978
        $out .= '<'. $element_tag .' class="' . html_class_attribute_ref($name_type_designation) . '">' .  type_designation_status_label_markup($name_type_designation) ;
979

    
980
        if (!empty($name_type_designation->designationSource->citation)) {
981
          $out .= type_designation_citation_layout($name_type_designation, $separator); // TODO type_designation_citation_layout() needs most probably to be replaced
982

    
983
        }
984
        $referenceUri = '';
985
        if (isset($name_type_designation->typeName->nomenclaturalSource->citation)) {
986
          $referenceUri = url(path_to_reference($name_type_designation->typeName->nomenclaturalSource->citation->uuid));
987
        }
988
        $out .= ': ' . render_taxon_or_name($name_type_designation->typeName, $link_to_name_page, $referenceUri, TRUE, TRUE);
989
      }
990
      RenderHints::setAnnotationsAndSourceConfig(annotations_and_sources_config_typedesignations());
991
      $annotations_and_sources = handle_annotations_and_sources($name_type_designation);
992
      $out .= $annotations_and_sources->footNoteKeysMarkup();
993
    }
994
  } // END NameTypeDesignation
995

    
996
  // SpecimenTypeDesignation ...................................
997
  if (!empty($specimen_type_designations)) {
998
    usort($specimen_type_designations, "compare_specimen_type_designation");
999
    foreach ($specimen_type_designations as $specimen_type_designation) {
1000
      $type_citation_markup = '';
1001
      if ($specimen_type_designation->notDesignated) {
1002
        $out .= '<' . $element_tag . ' class="' . html_class_attribute_ref($specimen_type_designation) . '">' . type_designation_status_label_markup($specimen_type_designation) . ': '
1003
          . t('not designated') . '</' . $element_tag . '>';
1004
      }
1005
      else {
1006

    
1007
        if (!empty($specimen_type_designation->designationSource->citation)) {
1008

    
1009
          $citation_footnote_str = cdm_reference_markup($specimen_type_designation->designationSource->citation, NULL, FALSE, TRUE);
1010
          $author_team = cdm_ws_get(CDM_WS_REFERENCE_AUTHORTEAM, $specimen_type_designation->designationSource->citation->uuid);
1011

    
1012
          if (!empty($author_team->titleCache)) {
1013
            $year = @timePeriodToString($specimen_type_designation->designationSource->citation->datePublished, TRUE, 'YYYY');
1014
            $authorteam_str = $author_team->titleCache . ($year ? ' ' : '') . $year;
1015
            if ($authorteam_str == $specimen_type_designation->designationSource->citation->titleCache) {
1016
              $citation_footnote_str = '';
1017
            }
1018
          }
1019
          else {
1020
            $authorteam_str = $citation_footnote_str;
1021
            // no need for a footnote in case in case it is used as replacement for missing author teams
1022
            $citation_footnote_str = '';
1023
          }
1024

    
1025
          // for being registered a typedesignation MUST HAVE a citation, so we safely can handle the
1026
          // Registration output under the checked condition that the citation is present
1027
          $registration_markup = render_registrations($specimen_type_designation->registrations);
1028
          $citation_footnote_str .= ($citation_footnote_str ? ' ' : '') . $registration_markup;
1029

    
1030
          $footnote_key_markup = '';
1031
          if ($citation_footnote_str) {
1032
            // footnotes should be rendered in the parent element so we
1033
            // are relying on the FootnoteListKey set there
1034
            $_fkey2 = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $citation_footnote_str);
1035
            $footnote_key_markup = render_footnote_key($_fkey2, $separator, TRUE);
1036
          }
1037

    
1038
          $type_citation_markup .= '&nbsp;(' . t('designated by') . '&nbsp;<span class="typeReference">' . $authorteam_str . '</span>';
1039
          if (!empty($specimen_type_designation->designationSource->citationMicroReference)) {
1040
            $type_citation_markup .= ': ' . trim($specimen_type_designation->designationSource->citationMicroReference);
1041
          }
1042
          $type_citation_markup .= $footnote_key_markup . ')';
1043
        }
1044

    
1045
        $out .= '<' . $element_tag . ' class="' . html_class_attribute_ref($specimen_type_designation) . '">';
1046
        $out .= type_designation_status_label_markup($specimen_type_designation) . $type_citation_markup;
1047

    
1048

    
1049
        $derived_unit_dto = NULL;
1050
        if (isset($specimen_type_designation->typeSpecimen)) {
1051
          $derived_unit_dto = cdm_ws_get(CDM_WS_PORTAL_OCCURRENCE_AS_DTO, $specimen_type_designation->typeSpecimen->uuid);
1052
        }
1053

    
1054
        if (!empty($derived_unit_dto->summaryLabel)) {
1055
          $specimen_markup = $derived_unit_dto->summaryLabel;
1056
          if ($link_to_specimen_page && isset($derived_unit_dto->mostSignificantIdentifier) && $derived_unit_dto->mostSignificantIdentifier) {
1057
            $specimen_markup = str_replace($derived_unit_dto->mostSignificantIdentifier, l($derived_unit_dto->mostSignificantIdentifier, path_to_specimen($specimen_type_designation->typeSpecimen->uuid)), $specimen_markup);
1058
          }
1059
          $media_sources_markup = '';
1060
          if (isset_not_empty($derived_unit_dto->listOfMedia)) {
1061
            foreach ($derived_unit_dto->listOfMedia as $media_dto) {
1062
              // adding the source citations
1063
              if (isset_not_empty($media_dto->sources)) {
1064
                foreach ($media_dto->sources as $source_dto) {
1065
                  $media_sources_markup .= source_dto_markup($source_dto);
1066
                }
1067
              }
1068
            }
1069
          }
1070
          if ($media_sources_markup) {
1071
            $specimen_markup .= ' in ' . $media_sources_markup;
1072
          }
1073
          RenderHints::setAnnotationsAndSourceConfig(annotations_and_sources_config_typedesignations());
1074
          $annotations_and_sources = handle_annotations_and_sources($derived_unit_dto);
1075
          $out .= ': <span class="' . html_class_attribute_ref($specimen_type_designation->typeSpecimen) . '">'
1076
            . $specimen_markup
1077
            . '</span>'; // . ': ' . theme('cdm_specimen', array('specimenTypeDesignation' => $derivedUnitFacadeInstance));
1078
          if (!empty($derived_unit_dto->preferredStableUri)) {
1079
            $out .= ' ' . l($derived_unit_dto->preferredStableUri, $derived_unit_dto->preferredStableUri, ['absolute' => TRUE]);
1080
          }
1081
          $out .= $annotations_and_sources->footNoteKeysMarkup();
1082
        }
1083

    
1084
        $out .= '</' . $element_tag . '>';
1085
      }
1086
    }
1087
  } // END Specimen type designations
1088

    
1089
  // TextualTypeDesignation .........................
1090
  usort($textual_type_designations, 'compare_textual_type_designation');
1091
  if(!empty($textual_type_designations)) {
1092
      RenderHints::setAnnotationsAndSourceConfig([
1093
          // these settings differ from those provided by annotations_and_sources_config_typedesignations()
1094
          // TODO is this by purpose? please document the reason for the difference
1095
          'sources_as_content' => false, // as footnotes
1096
          'link_to_name_used_in_source' => false,
1097
          'link_to_reference' => true,
1098
          'add_footnote_keys' => true,
1099
          'bibliography_aware' => false
1100
        ]
1101
      );
1102
    foreach ($textual_type_designations as $textual_type_designation) {
1103
      $annotations_and_sources = handle_annotations_and_sources($textual_type_designation);
1104
      $encasement =  $textual_type_designation->verbatim ? '"' : '';
1105
      $out .= '<' . $element_tag . ' class="' . html_class_attribute_ref($textual_type_designation) . '">' . type_designation_status_label_markup(null)
1106
        . ': ' .  $encasement . trim($textual_type_designation->text_L10n->text) . $encasement .  $annotations_and_sources->footNoteKeysMarkup() .'</' . $element_tag . '>';
1107
//      if($annotations_and_sources->hasSourceReferences())){
1108
//        $citation_markup = join(', ', getSourceReferences());
1109
//      }
1110
//      $out .= $citation_markup;
1111
    }
1112
  }
1113

    
1114
  // Footnotes for citations, collection acronyms.
1115
  // footnotes should be rendered in the parent element so we
1116
  // are relying on the FootnoteListKey set there
1117
  $_fkey = FootnoteManager::addNewFootnote(
1118
    RenderHints::getFootnoteListKey(),
1119
    (isset($derived_unit_dto->collection->titleCache) ? $derived_unit_dto->collection->titleCache : FALSE)
1120
  );
1121
  $out .= render_footnote_key($_fkey, $separator);
1122
  $out .= '</' . $enclosing_tag .'>';
1123

    
1124
  RenderHints::popFromRenderStack();
1125

    
1126
  return $out;
1127
}
1128

    
1129
/**
1130
 * @param $source_dto
1131
 *
1132
 * @return string
1133
 */
1134
function source_dto_markup($source_dto, $as_nom_ref = false) {
1135
  $source_dto_markup = '';
1136
  if (isset_not_empty($source_dto->citation->abbrevTitleCache)) {
1137
    $source_dto_markup .= $source_dto->citation->abbrevTitleCache;
1138
  }
1139
  if (isset_not_empty($source_dto->citationDetail)) {
1140
    $source_dto_markup .= ': ' . $source_dto->citationDetail;
1141
  }
1142
  return $source_dto_markup;
1143
}
1144

    
1145
/**
1146
 * Creates markup for a list of SpecimenTypedesignationDTO
1147
 *
1148
 * @param array $specimen_typedesignation_dtos
1149
 *  The SpecimenTypedesignationDTOs to be rendered
1150
 *
1151
 * @param bool $show_type_specimen
1152
 *
1153
 * @param string $enclosing_tag
1154
 * @param string $element_tag
1155
 *
1156
 * @return string
1157
 *   The markup.
1158
 */
1159
function render_specimen_typedesignation_dto($specimen_typedesignation_dtos, $show_type_specimen = FALSE, $enclosing_tag = 'ul', $element_tag = 'li'){
1160

    
1161
  // need to add element to render path since type designations
1162
  // need other name render template
1163
  RenderHints::pushToRenderStack('typedesignations');
1164

    
1165
  $out = '<' . $enclosing_tag .' class="typeDesignations">';
1166
  $separator = ',';
1167

    
1168
  if (!empty($specimen_typedesignation_dtos)) {
1169
    // usort($specimen_type_designations, "compare_specimen_type_designation"); // FIXME create compare function for SpecimenTypedesignationDTO
1170
    foreach ($specimen_typedesignation_dtos as $std_dto) {
1171
      $type_citation_markup = '';
1172

    
1173
      if (!empty($std_dto->designationSource->citation)) {
1174
        // TODO this now can be simplified since SourceDTO has the label field, see #9896
1175
        $citation_footnote_str = cdm_reference_markup($std_dto->designationSource->citation, null, false, true);
1176
        $author_team = cdm_ws_get(CDM_WS_REFERENCE_AUTHORTEAM, $std_dto->designationSource->citation->uuid);
1177

    
1178
        if (!empty($author_team->titleCache)) {
1179
          $year = @timePeriodToString($std_dto->designationSource->citation->datePublished, true, 'YYYY');
1180
          $authorteam_str = $author_team->titleCache . ($year ? ' ' : '') . $year;
1181
          if ($authorteam_str == $std_dto->designationSource->citation->label) {
1182
            $citation_footnote_str = '';
1183
          }
1184
        } else {
1185
          $authorteam_str = $citation_footnote_str;
1186
          // no need for a footnote in case it is used as replacement for missing author teams
1187
          $citation_footnote_str = '';
1188
        }
1189

    
1190
        // for being registered a typedesignation MUST HAVE a citation, so it is save to handle the
1191
        // Registration output in the conditional block which has been checked that the citation is present
1192
        $registration_markup = render_registrations($std_dto->registrations);
1193
        $citation_footnote_str .= ($citation_footnote_str ? ' ' : '') . $registration_markup;
1194

    
1195
        $footnote_key_markup = '';
1196
        if ($citation_footnote_str) {
1197
          // footnotes should be rendered in the parent element so we
1198
          // are relying on the FootnoteListKey set there
1199
          $_fkey2 = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $citation_footnote_str);
1200
          $footnote_key_markup = render_footnote_key($_fkey2, $separator, TRUE);
1201
        }
1202

    
1203
        $type_citation_markup .= '&nbsp;(' . t('designated by') . '&nbsp;<span class="typeReference">' . $authorteam_str . '</span>';
1204
        if (!empty($std_dto->designationSource->citationMicroReference)) {
1205
          $type_citation_markup .= ': ' . trim($std_dto->designationSource->citationMicroReference);
1206
        }
1207
        $type_citation_markup .= $footnote_key_markup . ')';
1208
      }
1209

    
1210
      $out .= '<'. $element_tag .' class="' . html_class_attribute_ref($std_dto) . '">';
1211
      $out .= type_designation_dto_status_label_markup($std_dto) . $type_citation_markup;
1212

    
1213
      if($show_type_specimen){
1214
        $derived_unit_dto = null;
1215
        if (isset($std_dto->typeSpecimen)) {
1216
          $derived_unit_dto = cdm_ws_get(CDM_WS_PORTAL_OCCURRENCE_AS_DTO, $std_dto->typeSpecimen->uuid);
1217
        }
1218

    
1219
        if (!empty($derived_unit_dto->summaryLabel)) {
1220
          $specimen_markup = $derived_unit_dto->summaryLabel;
1221
          if(isset($derived_unit_dto->mostSignificantIdentifier) && $derived_unit_dto->mostSignificantIdentifier){
1222
            $specimen_markup = str_replace($derived_unit_dto->mostSignificantIdentifier, l($derived_unit_dto->mostSignificantIdentifier, path_to_specimen($std_dto->typeSpecimen->uuid)), $specimen_markup);
1223
          }
1224
          RenderHints::setAnnotationsAndSourceConfig(annotations_and_sources_config_typedesignations());
1225
          $annotations_and_sources = handle_annotations_and_sources($derived_unit_dto);
1226
          $out .= ': <span class="' . html_class_attribute_ref($std_dto->typeSpecimen) . '">'
1227
            . $specimen_markup
1228
            . '</span>'; // . ': ' . theme('cdm_specimen', array('specimenTypeDesignation' => $derivedUnitFacadeInstance));
1229
          if(!empty($derived_unit_dto->preferredStableUri)){
1230
            $out .= ' ' . l($derived_unit_dto->preferredStableUri, $derived_unit_dto->preferredStableUri, array('absolute' => true));
1231
          }
1232
          $out .= $annotations_and_sources->footNoteKeysMarkup();
1233
        }
1234
      }
1235

    
1236
      $out .= '</'. $element_tag .'>';
1237
    }
1238
    RenderHints::popFromRenderStack();
1239
  }
1240
  return $out;
1241
}
1242

    
1243

    
1244
/**
1245
 * Composes the textual representation for the type designation of taxon name identified by the uuid in with a map for the location data.
1246
 *
1247
 * @param $taxon_name_uuid
1248
 * @param $show_specimen_details
1249
 * @return array
1250
 *    A drupal render array with the following elements:
1251
 *    - 'type_designations'
1252
 *    - 'map'
1253
 *    - 'specimens'
1254
 *
1255
 * @ingroup compose
1256
 */
1257
function compose_type_designations($taxon_name_uuid, $show_specimen_details = false)
1258
{
1259
  $render_array = array(
1260
    'type_designations' => array(),
1261
    'map' => array(),
1262
    );
1263
  $type_designations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS, $taxon_name_uuid);
1264
  if ($type_designations) {
1265
    usort($type_designations, 'compare_specimen_type_designation');
1266
    $render_array['type_designations'] = markup_to_render_array(
1267
      render_type_designations($type_designations, 'div', 'div')
1268
    );
1269

    
1270
    $render_array['map'] = compose_type_designations_map($type_designations);
1271
  }
1272
  return $render_array;
1273
}
1274

    
1275

    
1276
/**
1277
 * Composes the TypedEntityReference to name type designations passed as associatve array.
1278
 *
1279
 * @param $type_entity_refs_by_status array
1280
 *   an associative array of name type type => TypedEntityReference for name type designations as
1281
 *   produced by the eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager
1282
 *
1283
 * @ingroup compose
1284
 */
1285
function compose_name_type_designations($type_entity_refs_by_status){
1286
  $render_array = array();
1287
  $preferredStableUri = '';
1288
  foreach($type_entity_refs_by_status as $type_status => $name_type_entityRefs){
1289
    foreach ($name_type_entityRefs as $name_type_entity_ref){
1290
      $type_designation = cdm_ws_get(CDM_WS_TYPEDESIGNATION, array($name_type_entity_ref->uuid, 'preferredUri'));
1291
      $footnote_keys = '';
1292

    
1293
      if(isset($type_designation->typeSpecimen->preferredStableUri) && $type_designation->typeSpecimen->preferredStableUri){
1294
        $preferredStableUri = $type_designation->typeSpecimen->preferredStableUri;
1295
      }
1296
      // annotations and sources for the $derived_unit_facade_dto
1297
      RenderHints::setAnnotationsAndSourceConfig(annotations_and_sources_config_typedesignations());
1298
      $annotations_and_sources = handle_annotations_and_sources($name_type_entity_ref);
1299

    
1300
      $render_array[] = markup_to_render_array('<div class="name_type_designation ' . html_class_attribute_ref($name_type_entity_ref)  .
1301
        '"><span class="type-status">'. ucfirst($type_status) . "</span>: "
1302
        . cdm_tagged_text_to_markup($name_type_entity_ref->taggedText)
1303
        . ($preferredStableUri ? " ". l($preferredStableUri,  $preferredStableUri) : '')
1304
        . $annotations_and_sources->footNoteKeysMarkup()
1305
        . '</div>');
1306
      }
1307
  }
1308
  return $render_array;
1309
}
1310

    
1311
/**
1312
 * Composes the specimen type designations with map from the the $type_entity_refs
1313
 *
1314
 * @param $type_entity_refs array
1315
 *   an associative array of specimen type type => TypedEntityReference for specimen type designations as
1316
 *   produced by the eu.etaxonomy.cdm.api.service.name.TypeDesignationSetManager
1317
 *
1318
 * @param $show_media_specimen
1319
 * @return array
1320
 *    A drupal render array with the following elements:
1321
 *    - 'type_designations'
1322
 *    - 'map'
1323
 *
1324
 * @ingroup compose
1325
 *
1326
 */
1327
function compose_specimen_type_designations($type_entity_refs, $show_media_specimen){
1328

    
1329
  $render_array = array();
1330

    
1331
  $type_designation_list = array();
1332
  uksort($type_entity_refs, "compare_type_designation_status_labels");
1333
  foreach($type_entity_refs as $type_status => $type_designation_entity_refs){
1334
    foreach($type_designation_entity_refs as $type_designation_entity_ref){
1335

    
1336
      $type_designation = cdm_ws_get(CDM_WS_PORTAL_TYPEDESIGNATION, array($type_designation_entity_ref->uuid));
1337
      $type_designation_list[] = $type_designation; // collect for the map
1338

    
1339
      $derived_unit_facade_dto = cdm_ws_get(CDM_WS_PORTAL_DERIVEDUNIT_FACADE, $type_designation->typeSpecimen->uuid);
1340
      // the media specimen is not contained in the $type_designation returned by CDM_PORTAL_TYPEDESIGNATION, so we need to fetch it separately
1341
      $mediaSpecimen = cdm_ws_get(CDM_WS_PORTAL_OCCURRENCE, array($type_designation->typeSpecimen->uuid, 'mediaSpecimen'));
1342

    
1343

    
1344
      $preferredStableUri = '';
1345
      $citation_markup = '';
1346
      $media = '';
1347

    
1348
      // annotations and sources for the $derived_unit_facade_dto
1349
      RenderHints::setAnnotationsAndSourceConfig(annotations_and_sources_config_typedesignations());
1350
      $annotations_and_sources = handle_annotations_and_sources($derived_unit_facade_dto);
1351
      $source_citations = $annotations_and_sources->getSourceReferences();
1352
      $foot_note_keys = $annotations_and_sources->footNoteKeysMarkup();
1353

    
1354
      // preferredStableUri
1355
      if(isset($type_designation->typeSpecimen->preferredStableUri) && $type_designation->typeSpecimen->preferredStableUri){
1356
        $preferredStableUri = $type_designation->typeSpecimen->preferredStableUri;
1357
      }
1358

    
1359
      if($show_media_specimen && $mediaSpecimen){
1360
        // compose output
1361
        // mediaURI
1362
        if(isset($mediaSpecimen->representations[0])) {
1363
          $gallery_settings = getGallerySettings(CDM_DATAPORTAL_SPECIMEN_GALLERY_NAME);
1364
          $captionElements = array(
1365
            '#uri' => t('open media'),
1366
            'elements' => array('-none-'),
1367
            'sources_as_content' => true
1368
          );
1369
          $media = compose_cdm_media_gallery(array(
1370
            'mediaList' => array($mediaSpecimen),
1371
            'galleryName' => CDM_DATAPORTAL_TYPE_SPECIMEN_GALLERY_NAME . '_' . $type_designation_entity_ref->uuid,
1372
            'maxExtend' => $gallery_settings['cdm_dataportal_media_maxextend'],
1373
            'cols' => $gallery_settings['cdm_dataportal_media_cols'],
1374
            'captionElements' => $captionElements,
1375
          ));
1376
        }
1377
        // citation and detail for the media specimen
1378
        RenderHints::setAnnotationsAndSourceConfig(annotations_and_sources_config_typedesignations());
1379
        $annotations_and_sources = handle_annotations_and_sources($mediaSpecimen);
1380
        if($annotations_and_sources->hasSourceReferences()){
1381
          $source_citations = array_merge($source_citations, $annotations_and_sources->getSourceReferences());
1382
        }
1383
        if($annotations_and_sources->hasFootnoteKeys()){
1384
          $foot_note_keys .= ', ' . $annotations_and_sources->footNoteKeysMarkup();
1385
        }
1386
      }
1387

    
1388
      $citation_markup = join(', ', $source_citations);
1389

    
1390
      $specimen_markup = $derived_unit_facade_dto->titleCache;
1391
      if(isset($derived_unit_facade_dto->specimenLabel) && $derived_unit_facade_dto->specimenLabel){
1392
        $specimen_markup = str_replace(
1393
          $derived_unit_facade_dto->specimenLabel,
1394
          l($derived_unit_facade_dto->specimenLabel, path_to_specimen($type_designation->typeSpecimen->uuid)), $specimen_markup);
1395
      }
1396

    
1397
      $type_designation_render_array = markup_to_render_array(
1398
        '<div class="type_designation_entity_ref ' . html_class_attribute_ref($type_designation_entity_ref)  . '">
1399
          <span class="type-status">' . ucfirst($type_status) . "</span>: "
1400
        . $specimen_markup . $foot_note_keys
1401
        . ($citation_markup ? ' '. $citation_markup : '')
1402
        . ($preferredStableUri ? " ". l($preferredStableUri,  $preferredStableUri) : '')
1403
        . $media
1404
        . '</div>');
1405

    
1406
      $render_array['type_designations'][] = $type_designation_render_array;
1407
    }
1408
  }
1409
  if(count($type_designation_list) > 0 ){
1410
    $render_array['map'] = compose_type_designations_map($type_designation_list);
1411
  } else {
1412
    $render_array['map'] = array();
1413
  }
1414
  return $render_array;
1415
}
1416

    
1417
/**
1418
 * Creates the markup for the given name relationship.
1419
 *
1420
 * For the footnotes see handle_annotations_and_sources().
1421
 *
1422
 * @param $other_name
1423
 *      The other name from the NameRelationship see get_other_name()
1424
 * @param $current_taxon_uuid
1425
 * @param $show_name_cache_only
1426
 *    The nameCache will be shown instead of the titleCache if this parameter is true.
1427
 * @return null|string
1428
 *    The markup or null
1429
 *
1430
 * @see \get_other_name
1431
 */
1432
function name_relationship_markup($current_name_uuid, $name_rel, $current_taxon_uuid, $show_name_cache_only = false){
1433

    
1434
  $relationship_markup = null;
1435

    
1436
  $other_name = get_other_name($current_name_uuid, $name_rel);
1437

    
1438
  cdm_load_tagged_full_title($other_name);
1439

    
1440
  $highlited_synonym_uuid = isset ($other_name->taxonBases[0]->uuid) ? $other_name->taxonBases[0]->uuid : '';
1441
  if($show_name_cache_only){
1442
    $relationship_markup = l(
1443
      '<span class="' . html_class_attribute_ref($other_name) . '"">' . $other_name->nameCache . '</span>',
1444
      path_to_name($other_name->uuid, $current_taxon_uuid, $highlited_synonym_uuid, false),
1445
      array('html' => true)
1446
    );
1447
    $annotations_and_sources = handle_annotations_and_sources($other_name);
1448
    $relationship_markup .= $annotations_and_sources->footNoteKeysMarkup();
1449
  } else {
1450
    $relationship_markup = render_taxon_or_name($other_name,
1451
      url(path_to_name($other_name->uuid, $current_taxon_uuid, $highlited_synonym_uuid, false))
1452
    );
1453
  }
1454

    
1455
  return $relationship_markup;
1456
}
1457

    
1458
/**
1459
 * Determined the other name which is contained in the NameRelationship entity.
1460
 *
1461
 * @param $current_name_uuid
1462
 *   The uuid of this name.
1463
 * @param $name_rel
1464
 *   The cdm NameRelationship entity
1465
 *
1466
 * @return object
1467
 *   The other cdm Name entity.
1468
 */
1469
function get_other_name($current_name_uuid, $name_rel) {
1470
  $current_name_is_toName = $current_name_uuid == $name_rel->toName->uuid;
1471

    
1472
  if ($current_name_is_toName) {
1473
    $name = $name_rel->fromName;
1474
  }
1475
  else {
1476
    $name = $name_rel->toName;
1477
  }
1478
  return $name;
1479
}
1480

    
1481

    
1482
/**
1483
 * Composes an inline representation of selected name relationships
1484
 *
1485
 * The output of this function will be usually appended to taxon name representations.
1486
 * Only the following types are displayed: LATER_HOMONYM, TREATED_AS_LATER_HOMONYM, BLOCKING_NAME_FOR, ORTHOGRAPHIC_VARIANT
1487
 *
1488
 * LATER_HOMONYM, TREATED_AS_LATER_HOMONYM, BLOCKING_NAME_FOR are displayed as
1489
 * non {titleCache} nec {titleCache} nec {titleCache} whereas the related names
1490
 * are ordered alphabetically.
1491
 *
1492
 * ORTHOGRAPHIC_VARIANT is displayed as 'ort. var. {nameCache}'
1493
 *
1494
 * Related issues:
1495
 *   - https://dev.e-taxonomy.eu/redmine/issues/5697 "Show name conserved against as [non xxx]"
1496
 *   - https://dev.e-taxonomy.eu/redmine/issues/6678 "How to correctly show name relationship "orth. var." in dataportal"
1497
 *   - https://dev.e-taxonomy.eu/redmine/issues/5857
1498
 *   - https://dev.e-taxonomy.eu/redmine/issues/2001 "[Cichorieae Portal] Name Relationship -> blocking name are not shown"
1499
 *
1500
 * @param $name_relations
1501
 *    The list of CDM NameRelationsips
1502
 * @param $current_name_uuid
1503
 *    The Uuid of the name for which the relations are to be rendered, the current name will be hidden when
1504
 *    rendering the relation an only the other name is shown. Parameter is REQUIRED.
1505
 * @param $suppress_if_current_name_is_source
1506
 *    The display of the relation will be
1507
 *    suppressed is the current name is on the source of the relation edge.
1508
 *    That is if it is on the from side of the relation. Except for 'blocking name for' which is
1509
 *    an inverse relation. For this relation type the toName is taken in to account.
1510
 * @param $current_taxon_uuid
1511
 *    The taxon to be omitted from related taxa. This is only used to create links, see path_to_name()
1512
 * @return array
1513
 *    A drupal render array
1514
 *
1515
 * @ingroup Compose
1516
 */
1517
function compose_name_relationships_inline($name_relations, $current_name_uuid, $current_taxon_uuid, $suppress_if_current_name_is_source = true) {
1518

    
1519
  RenderHints::pushToRenderStack('homonym');
1520
  // the render stack element homonyms is being used in the default render templates !!!, see NameRenderConfiguration::CDM_NAME_RENDER_TEMPLATES_DEFAULT
1521

    
1522
  $selected_name_rel_uuids = variable_get(CDM_NAME_RELATIONSHIP_INLINE_TYPES, unserialize(CDM_NAME_RELATIONSHIP_INLINE_TYPES_DEFAULT));
1523
  $name_rel_type_filter = array('direct' => array(), 'inverse' => array());
1524
  foreach ($selected_name_rel_uuids as $uuid){
1525
    $name_rel_type_filter['direct'][$uuid] = $uuid;
1526
    if($uuid != UUID_NAMERELATIONSHIPTYPE_MISSPELLING){
1527
      $name_rel_type_filter['inverse'][$uuid] = $uuid;
1528
    }
1529
  }
1530

    
1531
  $list_prefix = '<span class="name_relationships">[';
1532
  $list_suffix = ']</span>';
1533
  $item_prefix = '<span class="item">';
1534
  $item_suffix = '</span> ';
1535
  $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);
1536

    
1537
  // remove the glue space from the last item element which has been added by the $item_suffix = '</span> '
1538
  $items_ctn = count($render_array['list']['items']);
1539
  if($items_ctn){
1540
    $render_array['list']['items'][$items_ctn - 1]['#suffix'] = '</span>';
1541
  }
1542

    
1543
  RenderHints::popFromRenderStack();
1544
  return $render_array;
1545
}
1546

    
1547
/**
1548
 * Composes a list representation of the name relationships.
1549
 *
1550
 * The output of this function will be usually appended to taxon name representations.
1551
 *
1552
 * Related issues:
1553
 *   - https://dev.e-taxonomy.eu/redmine/issues/5697 "Show name conserved against as [non xxx]"
1554
 *   - https://dev.e-taxonomy.eu/redmine/issues/6678 "How to correctly show name relationship "orth. var." in dataportal"
1555
 *   - https://dev.e-taxonomy.eu/redmine/issues/5857
1556
 *
1557
 * @param $name_relations
1558
 *    The list of CDM NameRelationsips
1559
 * @param $current_name_uuid
1560
 *    The Uuid of the name for which the relations are to be rendered, the current name will be hidden when
1561
 *    rendering the relation an only the other name is shown. Parameter is REQUIRED.
1562
 * @param $current_taxon_uuid
1563
 *    The taxon to be omitted from related taxa. This is only used to create links, see path_to_name()
1564
 * @return array
1565
 *    A drupal render array
1566
 *
1567
 * @ingroup Compose
1568
 */
1569
function compose_name_relationships_list($name_relations, $current_name_uuid, $current_taxon_uuid) {
1570

    
1571
  // $ordered_name_relation_type_uuids = array_keys(cdm_terms_by_type_as_option('NameRelationshipType', CDM_ORDER_BY_ORDER_INDEX_ASC));
1572

    
1573
  $key = 'name_relationships';
1574
  RenderHints::pushToRenderStack($key);
1575
  if(RenderHints::isUnsetFootnoteListKey()){
1576
    RenderHints::setFootnoteListKey($key);
1577
  }
1578
  // the render stack element homonyms is being used in the default render templates !!!, see CDM_NAME_RENDER_TEMPLATES_DEFAULT
1579

    
1580
  $selected_name_rel_uuids = variable_get(CDM_NAME_RELATIONSHIP_LIST_TYPES, cdm_vocabulary_as_defaults(UUID_NAME_RELATIONSHIP_TYPE));
1581
  $name_rel_type_filter = array('direct' => array(), 'inverse' => array());
1582
  foreach ($selected_name_rel_uuids as $uuid){
1583
    $name_rel_type_filter['direct'][$uuid] = $uuid;
1584
    $name_rel_type_filter['inverse'][$uuid] = $uuid;
1585
  }
1586

    
1587
  $list_prefix = '<div class="relationships_list name_relationships">';
1588
  $list_suffix = '</div>';
1589
  $item_prefix = '<div class="item">';
1590
  $item_suffix = '</div>';
1591

    
1592
  $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);
1593

    
1594
  RenderHints::popFromRenderStack();
1595
  if(RenderHints::getFootnoteListKey() == $key) {
1596
    $render_array['footnotes'] = markup_to_render_array(render_footnotes(RenderHints::getFootnoteListKey()));
1597
    RenderHints::clearFootnoteListKey();
1598
  }
1599
  return $render_array;
1600
}
1601

    
1602
/**
1603
 * @param $name_relations
1604
 * @param $name_rel_type_filter
1605
 *   Associative array with two keys:
1606
 *   - 'direct': the relationship type uuids for the direct direction of the relation edge to be included
1607
 *   - 'inverse': the relationship type uuids for the direct direction of the relation edge to be included
1608
 * @param $current_name_uuid
1609
 * @param $current_taxon_uuid
1610
 * @param $list_prefix
1611
 * @param $list_suffix
1612
 * @param $item_prefix
1613
 * @param $item_suffix
1614
 * @return array
1615
 *
1616
 * @ingroup Compose
1617
 */
1618
function compose_name_relationships($name_relations, $name_rel_type_filter, $current_name_uuid, $current_taxon_uuid,
1619
                                    $list_prefix, $list_suffix, $item_prefix, $item_suffix)
1620
{
1621
  $non_nec_name_reltype_uuids = array(UUID_NAMERELATIONSHIPTYPE_LATER_HOMONYM,
1622
    UUID_NAMERELATIONSHIPTYPE_TREATED_AS_LATER_HOMONYM,
1623
    UUID_NAMERELATIONSHIPTYPE_CONSERVED_AGAINST,
1624
    UUID_NAMERELATIONSHIPTYPE_MISSPELLING,
1625
    UUID_NAMERELATIONSHIPTYPE_BLOCKING_NAME_FOR,
1626
    UUID_NAMERELATIONSHIPTYPE_AVOIDS_HOMONYM_OF,
1627
    UUID_NAMERELATIONSHIPTYPE_IS_NOT);
1628

    
1629
  $render_array = array(
1630
    'list' => array(
1631
      '#prefix' => $list_prefix,
1632
      '#suffix' => $list_suffix,
1633
      'items' => array()
1634
    ),
1635
    'footnotes' => array()
1636
  );
1637

    
1638
  if ($name_relations) {
1639

    
1640
    // remove all relations which are not selected in the settings and
1641
    // separate all LATER_HOMONYM, TREATED_AS_LATER_HOMONYM, BLOCKING_NAME_FOR relations and ORTHOGRAPHIC_VARIANTs
1642
    // for special handling
1643
    $filtered_name_rels = array();
1644
    $non_nec_name_rels = array();
1645
    $orthographic_variants = array();
1646
    foreach ($name_relations as $name_rel) {
1647
      $rel_type_uuid = $name_rel->type->uuid;
1648
      $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1649
      if ((!$is_inverse_relation && isset($name_rel_type_filter['direct'][$rel_type_uuid]) && $name_rel_type_filter['direct'][$rel_type_uuid])
1650
        ||($is_inverse_relation && isset($name_rel_type_filter['inverse'][$rel_type_uuid]) && $name_rel_type_filter['inverse'][$rel_type_uuid])) {
1651

    
1652
        if (array_search($rel_type_uuid, $non_nec_name_reltype_uuids) !== false && (
1653
            $current_name_uuid == $name_rel->fromName->uuid && $rel_type_uuid != UUID_NAMERELATIONSHIPTYPE_BLOCKING_NAME_FOR
1654
            || $current_name_uuid == $name_rel->toName->uuid && $rel_type_uuid == UUID_NAMERELATIONSHIPTYPE_BLOCKING_NAME_FOR
1655
          )
1656
        ){
1657
          $non_nec_name_rels[] = $name_rel;
1658
        } else if (UUID_NAMERELATIONSHIPTYPE_ORTHOGRAPHIC_VARIANT == $rel_type_uuid) {
1659
          $orthographic_variants[] = $name_rel;
1660
        } else {
1661

    
1662
          $filtered_name_rels[] = $name_rel;
1663
        }
1664
      }
1665
    }
1666
    $name_relations = $filtered_name_rels;
1667

    
1668
    usort($name_relations, 'compare_name_relations_by_term_order_index');
1669

    
1670
    // compose
1671
    $show_name_cache_only = FALSE;
1672
    foreach ($name_relations as $name_rel) {
1673

    
1674
      $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1675
      $rel_footnote_key_markup = render_footnote_key(handle_name_relationship_as_footnote($name_rel),'');
1676
      $relationship_markup = name_relationship_markup($current_name_uuid, $name_rel, $current_taxon_uuid, $show_name_cache_only);
1677
      $label = cdm_relationship_type_term_abbreviated_label($name_rel->type, $is_inverse_relation);
1678

    
1679
      $symbol = cdm_relationship_type_term_symbol($name_rel->type, $is_inverse_relation);
1680
      $symbol_markup = '<span class="symbol" title="' . $label . '">' . $symbol . '</span>' . $rel_footnote_key_markup . ' ';
1681
      $relationship_markup = $symbol_markup . $relationship_markup;
1682
      if ($relationship_markup) {
1683
        $render_array['list']['items'][] = markup_to_render_array($relationship_markup,
1684
          null,
1685
          $item_prefix,
1686
          $item_suffix);
1687
      }
1688
    }
1689

    
1690
    // name relationships to be displayed as non nec
1691
    if (count($non_nec_name_rels) > 0) {
1692
      $non_nec_markup = '';
1693
      $show_name_cache_only = FALSE;
1694
      foreach ($non_nec_name_rels as $name_rel) {
1695

    
1696
        $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1697
        $rel_footnote_key_markup = render_footnote_key(handle_name_relationship_as_footnote($name_rel),'');
1698
        $relationship_markup = name_relationship_markup($current_name_uuid, $name_rel, $current_taxon_uuid, $show_name_cache_only);
1699
        $label = cdm_relationship_type_term_abbreviated_label($name_rel->type, $is_inverse_relation);
1700

    
1701
        $symbol = $non_nec_markup ? ' nec ' : 'non';
1702
        $symbol_markup = '<span class="symbol" title="' . $label . '">' . $symbol . '</span>' . $rel_footnote_key_markup .  ' ';
1703
        $non_nec_markup .= $symbol_markup . $relationship_markup;
1704
      }
1705
      if ($non_nec_markup) {
1706
        $render_array['list']['items'][] = markup_to_render_array($non_nec_markup,
1707
          null,
1708
          $item_prefix,
1709
          $item_suffix);
1710
      }
1711
    }
1712

    
1713
    // orthographic variants
1714
    if (count($orthographic_variants) > 0) {
1715
      $show_name_cache_only = TRUE;
1716
      foreach ($orthographic_variants as $name_rel) {
1717

    
1718
        $is_inverse_relation = $current_name_uuid == $name_rel->toName->uuid;
1719
        $rel_footnote_key_markup = render_footnote_key(handle_name_relationship_as_footnote($name_rel),'');
1720
        $relationship_markup = name_relationship_markup($current_name_uuid, $name_rel, $current_taxon_uuid, $show_name_cache_only);
1721
        $label = cdm_relationship_type_term_abbreviated_label($name_rel->type, $is_inverse_relation);
1722
        $symbol = cdm_relationship_type_term_symbol($name_rel->type, $is_inverse_relation);
1723
        $symbol_markup = '<span class="symbol" title="' . $label . '">' . $symbol . '</span>' . $rel_footnote_key_markup .  ' ';
1724
        $relationship_markup = $symbol_markup . $relationship_markup;
1725
      }
1726
      if (isset($relationship_markup) && $relationship_markup) {
1727
        $render_array['list']['items'][] = markup_to_render_array($relationship_markup,
1728
          null,
1729
          $item_prefix,
1730
          $item_suffix);
1731
      }
1732
    }
1733
  }
1734
  return $render_array;
1735
}
1736

    
1737

    
1738

    
1739
/**
1740
 * @param $taxon
1741
 * @return array
1742
 */
1743
function cdm_name_relationships_for_taxon($taxon)
1744
{
1745
  $from_name_relations = cdm_ws_get(CDM_WS_PORTAL_TAXON_FROM_NAMERELATIONS, $taxon->uuid);
1746
  $to_name_relations = cdm_ws_get(CDM_WS_PORTAL_TAXON_TO_NAMERELATIONS, $taxon->uuid);
1747
  $name_relations = array_merge($from_name_relations, $to_name_relations);
1748
  return $name_relations;
1749
}
1750

    
1751

    
1752
/**
1753
 * Recursively searches the array for the $key and sets the given value.
1754
 *
1755
 * Expects the key to be used only once in nested array structures.
1756
 *
1757
 * @param mixed $key
1758
 *   Key to search for.
1759
 * @param mixed $value
1760
 *   Value to set.'
1761
 * @param array $array
1762
 *   Array to search in.
1763
 *
1764
 * @return array
1765
 *   The array the key has been found.
1766
 */
1767
function &array_setr($key, $value, array &$array) {
1768
  $res = NULL;
1769
  foreach ($array as $k => &$v) {
1770
    if ($key == $k) {
1771
      $v = $value;
1772
      return $array;
1773
    }
1774
    elseif (is_array($v)) {
1775
      $innerArray = array_setr($key, $value, $v);
1776
      if ($innerArray) {
1777
        return $array;
1778
      }
1779
    }
1780
  }
1781
  return $res;
1782
}
1783

    
1784
/**
1785
 * Recursively searches the array for the $key and sets is to $new_key
1786
 *
1787
 * Expects the key to be used only once in nested array structures.
1788
 *
1789
 * @param mixed $key
1790
 *   Key to search for.
1791
 * @param mixed $new_key
1792
 *   The new key to use
1793
 * @param array $array
1794
 *   Array to search in.
1795
 *
1796
 * @return bool
1797
 *   True if the key has been found.
1798
 */
1799
function array_replace_keyr($key, $new_key, array &$array) {
1800
  $res = NULL;
1801
  if(array_key_exists($key, $array)){
1802
    $value = $array[$key];
1803
    unset($array[$key]);
1804
    $array[$new_key] = $value;
1805
    return true;
1806
  } else {
1807
    // search in next level
1808
    foreach ($array as &$v) {
1809
        if (is_array($v)) {
1810
          array_replace_keyr($key, $new_key, $v);
1811
        }
1812
      }
1813
  }
1814

    
1815
  return false;
1816
}
1817

    
1818
/**
1819
 * @todo Please document this function.
1820
 * @see http://drupal.org/node/1354
1821
 */
1822
function &get_preceding_contentElement($contentElementKey, array &$renderTemplate) {
1823
  $res = NULL;
1824
  $precedingElement = NULL;
1825
  foreach ($renderTemplate as &$part) {
1826
    foreach ($part as $key => &$element) {
1827
      if ($key == $contentElementKey) {
1828
        return $precedingElement;
1829
      }
1830
      $precedingElement = $element;
1831
    }
1832
  }
1833
  return $res;
1834
}
1835

    
1836
/**
1837
 * @todo Please document this function.
1838
 * @see http://drupal.org/node/1354
1839
 */
1840
function &get_preceding_contentElementKey($contentElementKey, array &$renderTemplate) {
1841
  $res = NULL;
1842
  $precedingKey = NULL;
1843
  foreach ($renderTemplate as &$part) {
1844
    if (is_array($part)) {
1845
      foreach ($part as $key => &$element) {
1846
        if ($key == $contentElementKey) {
1847
          return $precedingKey;
1848
        }
1849
        if (!str_beginsWith($key, '#')) {
1850
          $precedingKey = $key;
1851
        }
1852
      }
1853
    }
1854
  }
1855
  return $res;
1856
}
1857

    
1858
function nameTypeToDTYPE($dtype){
1859
  static $nameTypeLabelMap = array(
1860
    "ICNB" => "BacterialName",
1861
    "ICNAFP" => "BotanicalName",
1862
    "ICNCP" => "CultivarPlantName",
1863
    "ICZN" => "ZoologicalName",
1864
    "ICVCN" => "ViralName",
1865
    "Any taxon name" => "TaxonName",
1866
    "NonViral" => "TaxonName",
1867
    "Fungus" => "BotanicalName",
1868
    "Plant" => "BotanicalName",
1869
    "Algae" => "BotanicalName",
1870
  );
1871
  return $nameTypeLabelMap[$dtype];
1872

    
1873
}
1874

    
1875

    
1876
function compare_name_relations_by_term_order_index($name_rel1, $name_rel2){
1877
  return compare_terms_by_order_index($name_rel1->type, $name_rel2->type);
1878
}
1879

    
1880
/**
1881
 * Provides an array with the different registration types covered by the passed registration.
1882
 *
1883
 * The labels in the returned array are translatable.
1884
 *
1885
 * See also https://dev.e-taxonomy.eu/redmine/issues/8016
1886
 *
1887
 * @param $registration_dto
1888
 * @return array
1889
 *    An array of the labels describing the different registration types covered by the passed registration.
1890
 */
1891
function registration_types($registration_dto){
1892
  $reg_type_labels = array();
1893
  if(isset($registration_dto->nameRef)){
1894
    $reg_type_labels["name"] = t("new name");
1895
    $reg_type_labels["taxon"] = t("new taxon");
1896
    $name_relations = cdm_ws_fetch_all(str_replace("$0", $registration_dto->nameRef->uuid, CDM_WS_PORTAL_NAME_NAME_RELATIONS));
1897
    $is_new_combination = true;
1898
    foreach($name_relations as $name_rel){
1899
      if(isset($name_rel->type->uuid)){
1900
        $name_is_from_name = $registration_dto->nameRef->uuid == $name_rel->fromName->uuid;
1901
        switch($name_rel->type->uuid) {
1902
          case UUID_NAMERELATIONSHIPTYPE_BASIONYM:
1903
            if(!$name_is_from_name){
1904
              $reg_type_labels["basionym"] = t("new combination");
1905
              $is_new_combination = true;
1906
            }
1907
            break;
1908
          case UUID_NAMERELATIONSHIPTYPE_REPLACED_SYNONYM:
1909
            if(!$name_is_from_name) {
1910
              $is_new_combination = true;
1911
            }
1912
            break;
1913
          case UUID_NAMERELATIONSHIPTYPE_VALIDATED_BY_NAME:
1914
            if(!$name_is_from_name) {
1915
              $reg_type_labels["validation"] = t("validation");
1916
            }
1917
            break;
1918
          case UUID_NAMERELATIONSHIPTYPE_ORTHOGRAPHIC_VARIANT:
1919
            if(!$name_is_from_name) {
1920
              $reg_type_labels["orth_var"] = t("orthographical correction");
1921
            }break;
1922
          default:
1923
            // NOTHING
1924
        }
1925
      }
1926
    }
1927
    if($is_new_combination){
1928
      unset($reg_type_labels["taxon"]);
1929
    }
1930
  }
1931
  if(isset($registration_dto->orderedTypeDesignationSets)){
1932
    $reg_type_labels[] = t("new nomenclatural type");
1933
  }
1934
  return $reg_type_labels;
1935
}
1936

    
1937
/**
1938
 * Collects and deduplicates the type designations associated with the passes synonyms.
1939
 *
1940
 * @param $synonymy_group
1941
 *    An array containing a homotypic or heterotypic group of names.
1942
 * @param $accepted_taxon_name_uuid
1943
 *    The uuid of the accepted taxon name. Optional parameter which is required when composing
1944
 *    the information for the homotypic group. In this case the accepted taxon is not included
1945
 *    in the $synonymy_group and must therefor passed in this second parameter.
1946
 *
1947
 * @return array
1948
 *    The CDM TypeDesignation entities
1949
 */
1950
function type_designations_for_synonymy_group($synonymy_group, $accepted_taxon_name_uuid = null)
1951
{
1952
  if (count($synonymy_group) > 0) {
1953
    $name_uuid = array_pop($synonymy_group)->name->uuid;
1954
  } else {
1955
    $name_uuid = $accepted_taxon_name_uuid;
1956
  }
1957
  if ($name_uuid) {
1958
   $type_designations = cdm_ws_get(CDM_WS_PORTAL_NAME_TYPEDESIGNATIONS_IN_HOMOTYPICAL_GROUP, $name_uuid);
1959
    if ($type_designations) {
1960
      return $type_designations;
1961
    }
1962
  }
1963

    
1964
  return array();
1965
}
1966

    
1967

    
1968
/**
1969
 * Compares two SpecimenTypeDesignations
1970
 *
1971
 * @param object $a
1972
 *   A SpecimenTypeDesignation.
1973
 * @param object $b
1974
 *   SpecimenTypeDesignation.
1975
 */
1976
function compare_specimen_type_designation($a, $b) {
1977

    
1978
  $cmp_by_status = compare_type_designations_by_status($a,$b);
1979
  if($cmp_by_status !== 0){
1980
    return $cmp_by_status;
1981
  }
1982

    
1983
  $aQuantifier = FALSE;
1984
  $bQuantifier = FALSE;
1985
  if ($aQuantifier == $bQuantifier) {
1986
    // Sort alphabetically.
1987
    $a_text =  isset($a->typeSpecimen->titleCache) ? preg_replace('/[\[\]\"]/', '', $a->typeSpecimen->titleCache) : '';
1988
    $b_text =  isset($b->typeSpecimen->titleCache) ? preg_replace('/[\[\]\"]/', '', $b->typeSpecimen->titleCache) : '';
1989
    return strcasecmp($a_text, $b_text);
1990
  }
1991
  return ($aQuantifier < $bQuantifier) ? -1 : (($aQuantifier > $bQuantifier) ? 1 : 0);
1992
}
1993

    
1994
/**
1995
 * Compares the status of two TypeDesignations
1996
 *
1997
 * @param object $a
1998
 *   A TypeDesignation
1999
 * @param object $b
2000
 *   TypeDesignation
2001
 */
2002
function compare_type_designations_by_status($a, $b) {
2003
  $status_a = isset($a->typeStatus) ? $a->typeStatus : null;
2004
  $status_b = isset($b->typeStatus) ? $b->typeStatus : null;
2005
  return compare_type_designation_status($status_a, $status_b);
2006
}
2007

    
2008
/**
2009
 * Compares two TypeDesignationStatusBase
2010
 *
2011
 * @param object $a
2012
 *   A TypeDesignationStatusBase.
2013
 * @param object $b
2014
 *   TypeDesignationStatusBase.
2015
 */
2016
function compare_type_designation_status($a, $b) {
2017
  $type_status_order = type_status_order();
2018
  $aQuantifier = FALSE;
2019
  $bQuantifier = FALSE;
2020
  if (isset($a->label) && isset($b->label)) {
2021
    $aQuantifier = array_search($a->label, $type_status_order);
2022
    $bQuantifier = array_search($b->label, $type_status_order);
2023
  }
2024
  return ($aQuantifier < $bQuantifier) ? -1 : (($aQuantifier > $bQuantifier) ? 1 : 0);
2025
}
2026

    
2027
/**
2028
 * Compares the two TextualTypeDesignations
2029
 *
2030
 * @param object $a
2031
 *   A TextualTypeDesignations.
2032
 * @param object $b
2033
 *   TextualTypeDesignations.
2034
 */
2035
function compare_textual_type_designation($a, $b) {
2036

    
2037
  $cmp_by_status = compare_type_designations_by_status($a,$b);
2038
  if($cmp_by_status !== 0){
2039
    return $cmp_by_status;
2040
  }
2041

    
2042
  $aQuantifier = FALSE;
2043
  $bQuantifier = FALSE;
2044
  if ($aQuantifier == $bQuantifier) {
2045
    // Sort alphabetically.
2046
    $a_text =  isset($a->text_L10n->text) ? $a->text_L10n->text : '';
2047
    $b_text =  isset($b->text_L10n->text) ? $b->text_L10n->text : '';
2048
    return strcasecmp($a_text, $b_text);
2049
  }
2050
  return ($aQuantifier < $bQuantifier) ? -1 : (($aQuantifier > $bQuantifier) ? 1 : 0);
2051
}
2052

    
2053

    
2054
/**
2055
 * Compares two SpecimenTypeDesignation status labels
2056
 *
2057
 * @param string $a
2058
 *   A TypeDesignationStatus label.
2059
 * @param string $b
2060
 *   A TypeDesignationStatus label.
2061
 */
2062
function compare_type_designation_status_labels($a, $b) {
2063

    
2064
  $type_status_order = type_status_order();
2065

    
2066
  $aQuantifier = FALSE;
2067
  $bQuantifier = FALSE;
2068
  if (isset($a) && isset($b)) {
2069
    $aQuantifier = array_search(ucfirst($a), $type_status_order);
2070
    $bQuantifier = array_search(ucfirst($b), $type_status_order);
2071
  }
2072
  return ($aQuantifier < $bQuantifier) ? -1 : 1;
2073
}
2074

    
2075
/**
2076
 * Preliminary implementation of a preset to define a sort order for
2077
 * type designation status.
2078
 *
2079
 * TODO this is only preliminary and may break in future,
2080
 *      see https://dev.e-taxonomy.eu/redmine/issues/8402?issue_count=96&issue_position=4&next_issue_id=8351&prev_issue_id=7966#note-4
2081
 * @return array
2082
 *   The array of orderd type labels
2083
 */
2084
function type_status_order()
2085
{
2086
  /*
2087
    This is the desired sort order as of now: Holotype Isotype Lectotype
2088
    Isolectotype Syntype.
2089
    TODO Basically, what we are trying to do is, we define
2090
    an ordered array of TypeDesignation-states and use the index of this array
2091
    for comparison. This array has to be filled with the cdm- TypeDesignation
2092
    states and the order should be parameterisable inside the dataportal.
2093
    */
2094
  static $type_status_order = array(
2095
    'Epitype',
2096
    'Holotype',
2097
    'Isotype',
2098
    'Lectotype',
2099
    'Isolectotype',
2100
    'Syntype',
2101
    'Paratype'
2102
  );
2103
  return $type_status_order;
2104
}
2105

    
2106
/**
2107
 * Return HTML for the lectotype citation with the correct layout.
2108
 *
2109
 * This function prints the lectotype citation with the correct layout.
2110
 * Lectotypes are renderized in the synonymy tab of a taxon if they exist.
2111
 *
2112
 * @param mixed $typeDesignation
2113
 *   Object containing the lectotype citation to print.
2114
 *
2115
 * @return string
2116
 *   Valid html string.
2117
 */
2118
function type_designation_citation_layout($typeDesignation, $footnote_separator = ',') {
2119
  $res = '';
2120
  $citation = $typeDesignation->designationSource->citation;
2121
  $pages = $typeDesignation->designationSource->citationMicroReference;
2122
  if(isset($typeDesignation->typeStatus->uuid) && isset($typeDesignation->typeStatus->representation_L10n)) {
2123
    if ( $typeDesignation->typeStatus->uuid == UUID_NTD_ORIGINAL_DESIGNATION || $typeDesignation->typeStatus->uuid == UUID_NTD_MONOTYPY) {
2124
      $res = ' (' . $typeDesignation->typeStatus->representation_L10n . ')';
2125
      return $res;
2126
    }
2127
  }
2128

    
2129
  if ($citation) {
2130
    // $type = $typeDesignation_citation->type;
2131
    $year = isset($citation->datePublished->start) ? substr($citation->datePublished->start, 0, 4) : '';
2132
    $author = isset($citation->authorship->titleCache) ? $citation->authorship->titleCache : '';
2133
    $res .= ' (designated by ';
2134
    $res .= $author;
2135
    $res .= ($year ? ' ' . $year : '');
2136
    $res .= ($pages ? ': ' . $pages : '');
2137
    // $res .= ')';
2138

    
2139
    // footnotes should be rendered in the parent element so we
2140
    // are relying on the FootnoteListKey set there
2141
    $fkey_typeDesignation = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $citation->titleCache);
2142
    $res .= render_footnote_key($fkey_typeDesignation, $footnote_separator,TRUE) . ')';
2143
  }
2144
  return $res;
2145
}
2146

    
2147
/**
2148
 * Creates markup for the status of a type designation. In case the status or its representation is missing the label will be set to "Type"
2149
 *
2150
 * @param $type_designation
2151
 * @return string
2152
 */
2153
function type_designation_status_label_markup($type_designation)
2154
{
2155
  return '<span class="type-status">'
2156
    . ((isset($type_designation->typeStatus->representation_L10n)) ? ucfirst($type_designation->typeStatus->representation_L10n) : t('Type')) . '</span>'
2157
    ;
2158
}
2159

    
2160
/**
2161
 * Creates markup for the status of a type designation DTO.
2162
 * In case the status or its representation is missing the label will be set to "Type"
2163
 *
2164
 * @param $type_designation
2165
 * @return string
2166
 */
2167
function type_designation_dto_status_label_markup($type_designation)
2168
{
2169
  return '<span class="type-status">'
2170
    . ((isset($type_designation->typeStatus_L10n)) ? ucfirst($type_designation->typeStatus_L10n) : t('Type')) . '</span>'
2171
    ;
2172
}
(7-7/16)