Project

General

Profile

Download (19.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/**
3
 * @file
4
 * functions for annotation and sources handling which are to be rendered as
5
 * footnotes.
6
 *
7
 * @copyright
8
 *   (C) 2007-2020 EDIT
9
 *   European Distributed Institute of Taxonomy
10
 *   http://www.e-taxonomy.eu
11
 *
12
 *   The contents of this module are subject to the Mozilla
13
 *   Public License Version 1.1.
14
 * @see http://www.mozilla.org/MPL/MPL-1.1.html
15
 *
16
 * @author
17
 *   - Andreas Kohlbecker <a.kohlbecker@BGBM.org>
18
 */
19
const MEMBER_OF_FOOTNOTES = ' member-of-footnotes-';
20

    
21
/**
22
 * Creates the footnotes for the given CDM instance.
23
 *
24
 * Footnotes are created for annotations and original sources whereas the resulting footnote keys depend on the
25
 * parameters $footnote_list_key and $is_bibliography_aware, see parameter $footnote_list_key
26
 * for more details.
27
 *
28
 * possible keys for annotation and source footnotes:
29
 *       - $footnote_list_key
30
 *       - RenderHints::getFootnoteListKey()
31
 *     - original source footnotes
32
 *       - "BIBLIOGRAPHY" (when !$is_bibliography_aware && bibliography_settings['enabled'] == 1 )
33
 *       - "BIBLIOGRAPHY-$footnote_list_key" (when !$is_bibliography_aware && bibliography_settings['enabled'] == 0 )
34
 *       - $footnote_list_key (when $is_bibliography_aware)
35
 *
36
 * @param $cdm_entity
37
 *   A CDM entity
38
 * @param $footnote_list_key string
39
 *    Optional parameter. If this parameter is left empty (null, 0, "") the footnote key will be determined by the nested
40
 *    method calls by calling RenderHints::getFootnoteListKey().
41
 *    For original sources the $footnote_list_key will be overwritten by bibliography_footnote_list_key() when
42
 *    $is_bibliography_aware is set TRUE.
43
 * @param bool $do_link_to_reference
44
 *    Create a link to the reference pages for sources when TRUE.
45
 * @param bool $do_link_to_name_used_in_source
46
 *    Create a link to the name pages for name in source when TRUE.
47
 * @param bool $is_bibliography_aware
48
 *    Put source references into the bibliography when this param is TRUE.
49
 *    For original sources the $footnote_list_key will be overwritten
50
 *    by bibliography_footnote_list_key() when
51
 *    $is_bibliography_aware is set TRUE.
52
 * @return array
53
 *   An array of the footnote keys for the supplied cdm entity
54
 *
55
 * NOTE: Only used in @see handle_annotations_and_sources()
56
 */
57
function cdm_entity_footnotes(
58
  $cdm_entity,
59
  $footnote_list_key = NULL,
60
  $do_link_to_reference = FALSE,
61
  $do_link_to_name_used_in_source = FALSE,
62
  $is_bibliography_aware = FALSE
63
){
64

    
65
  $sources = cdm_entity_sources_sorted($cdm_entity);
66

    
67
  if (!isset($footnote_list_key) || !$footnote_list_key) {
68
    $footnote_list_key = RenderHints::getFootnoteListKey();
69
  }
70

    
71
  // Annotations as footnotes.
72
  $footnote_keys = cdm_entity_annotations_as_footnote_keys($cdm_entity, $footnote_list_key);
73

    
74
  // Source references as footnotes.
75
  if($is_bibliography_aware){
76
    $bibliography_settings = get_bibliography_settings();
77
    $sources_footnote_list_key = bibliography_footnote_list_key($footnote_list_key);
78
    $original_source_footnote_tag = $bibliography_settings['enabled'] == 1 ? 'div' : null; // null will cause bibliography_footnote_list_key to use the default
79
  } else {
80
    $sources_footnote_list_key = $footnote_list_key;
81
    $original_source_footnote_tag = NULL;
82
  }
83

    
84
  foreach ($sources as $source) {
85
    if (_is_original_source_type($source)) {
86
      $fn_key = FootnoteManager::addNewFootnote(
87
        $sources_footnote_list_key,
88
        render_original_source(
89
          $source,
90
          $do_link_to_reference,
91
          $do_link_to_name_used_in_source
92
        ),
93
        $original_source_footnote_tag
94
      );
95
      // Ensure uniqueness of the footnote keys.
96
      if(array_search($fn_key, $footnote_keys)=== false) {
97
        $footnote_keys[] = $fn_key;
98
      }
99
    }
100
  }
101
  // Sort and render footnote keys.
102
  asort($footnote_keys);
103
  return $footnote_keys;
104
}
105

    
106
/**
107
 * Fetches the list of visible annotations for the cdm entity or for the comparable
108
 * object and returns the footnote keys.
109
 *
110
 * The footnotes are passed to the FootnoteManager in order to store the
111
 * annotations and to create the footnote keys.
112

    
113
 * @param stdClass $cdm_entity
114
 *   A single CdmBase instance ore comparable object.
115
 * @param $footnote_list_key string
116
 *    optional parameter. If this parameter is left empty (null, 0, "") the
117
 *    footnote key will be set to RenderHints::getFootnoteListKey()
118
 *    otherwise the supplied $footnote_list_key will be used.
119
 * @return array of footnote keys
120
 *
121
 * @see cdm_fetch_visible_annotations()
122
 */
123
function cdm_entity_annotations_as_footnote_keys(stdClass $cdm_entity, $footnote_list_key = NULL) {
124

    
125
  $foot_note_keys = [];
126

    
127
  if (!isset($footnote_list_key) || !$footnote_list_key) {
128
    $footnote_list_key = RenderHints::getFootnoteListKey();
129
  }
130

    
131
  // Adding the footnotes keys.
132
  $annotations = cdm_fetch_visible_annotations($cdm_entity);
133
  if (is_array($annotations)) {
134
    foreach ($annotations as $annotation) {
135
      $foot_note_keys[] = FootnoteManager::addNewFootnote($footnote_list_key, $annotation->text);
136
    }
137
  }
138

    
139
  return $foot_note_keys;
140
}
141

    
142
/**
143
 * Creates markup for an array of foot note keys
144
 *
145
 * @param array $footnote_keys
146
 * @param string $separator
147
 *
148
 * @return string
149
 */
150
function render_footnote_keys(array $footnote_keys, $separator) {
151

    
152
  $footnotes_markup = '';
153
  foreach ($footnote_keys as $foot_note_key) {
154
    try {
155
      $footnotes_markup .= render_footnote_key($foot_note_key, ($footnotes_markup ? $separator : ''));
156
    } catch (Exception $e) {
157
      drupal_set_message("Exception: " . $e->getMessage(), 'error');
158
    }
159
  }
160
  return $footnotes_markup;
161
}
162

    
163
/**
164
 * Creates markup for a foot note key
165
 *
166
 * @param null $footnoteKey
167
 * @param string $separator
168
 * @param bool $separator_off
169
 *
170
 * @return string
171
 *   The footnote key markup
172
 */
173
function render_footnote_key($footnoteKey = null, $separator = '', $separator_off = false) {
174

    
175
  if (!is_object($footnoteKey) or !isset($footnoteKey->footnoteListKey)) {
176
    return '';
177
  }
178
  if (variable_get('cdm_dataportal_all_footnotes', CDM_DATAPORTAL_ALL_FOOTNOTES)) {
179
    return '';
180
  }
181

    
182
  if ($separator_off) {
183
    $separator = '';
184
  }
185
  $out = '<span class="footnote-key footnote-key-' . $footnoteKey->keyStr . MEMBER_OF_FOOTNOTES . $footnoteKey->footnoteListKey . '">'
186
    . $separator . '<a href="#footnote-' . $footnoteKey->keyStr . '">' . $footnoteKey->keyStr . '</a>' . '</span>';
187
  return $out;
188
}
189

    
190
/**
191
 * Create the markup for a footnote. This method is used in {@link Footnote::doRender()}
192
 * @param null $footnoteKey
193
 * @param null $footnoteText
194
 * @param string $enclosing_tag
195
 *   default is 'span'
196
 *
197
 * @return string
198
 *
199
 */
200
function render_footnote($footnoteKey = null, $footnoteText = null, $enclosing_tag = 'span', $footnote_list_key = null) {
201
  _add_js_footnotes();
202
  if($enclosing_tag == null){
203
    $enclosing_tag = 'span';
204
  }
205
  $class_attribute_member_of = '';
206
  if($footnote_list_key){
207
    $class_attribute_member_of = MEMBER_OF_FOOTNOTES . $footnote_list_key;
208
  }
209
  return '<' . $enclosing_tag . ' class="footnote footnote-' . $footnoteKey . $class_attribute_member_of . '">'
210
    . '<a name="footnote-' . $footnoteKey . '"></a>'
211
    . '<span class="footnote-anchor">' . $footnoteKey . '.</span>&nbsp;' . $footnoteText
212
    . '</' . $enclosing_tag . '>';
213
}
214

    
215

    
216

    
217
/**
218
 * Create markup for the footnotes mapped to the $footnoteListKey.
219
 *
220
 * @param null $footnote_list_key
221
 *  The footnote list key, see RenderHints::getFootnoteListKey()
222
 * @param $element_tag
223
 *  The tag for the footnote element
224
 *
225
 * @return string
226
 *   The markup
227
 */
228
function render_footnotes($footnote_list_key = null, $element_tag = 'span') {
229

    
230
  if (variable_get('cdm_dataportal_all_footnotes', CDM_DATAPORTAL_ALL_FOOTNOTES)) {
231
    return '';
232
  }
233

    
234
  if (!isset($footnote_list_key) || !$footnote_list_key) {
235
    $footnote_list_key = RenderHints::getFootnoteListKey();
236
  }
237

    
238
  $out = '<' . $element_tag . ' class="footnotes footnotes-' . $footnote_list_key . ' ">'
239
    . FootnoteManager::renderFootnoteList($footnote_list_key)
240
    . '</' . $element_tag . '>';
241

    
242
  FootnoteManager::removeFootnoteList($footnote_list_key);
243
  return $out;
244
}
245

    
246
/**
247
 * This method determines the footnote key for original sources to be shown in the bibliography block
248
 *
249
 * The footnote key depends on the value of the 'enabled' value of the bibliography_settings
250
 *    - enabled == 1 -> "BIBLIOGRAPHY"
251
 *    - enabled == 0 -> "BIBLIOGRAPHY-$key_suggestion"
252
 *
253
 * @see get_bibliography_settings() and @see constant BIBLIOGRAPHY_FOOTNOTE_KEY
254
 *
255
 * @param $key_suggestion string
256
 *    optional parameter. If this parameter is left empty (null, 0, "") the footnote key will be retrieved by
257
 *    calling RenderHints::getFootnoteListKey().
258

    
259
 *
260
 * @return string
261
 *  the footnote_list_key
262
 */
263
function bibliography_footnote_list_key($key_suggestion = null) {
264
  if(!$key_suggestion){
265
    $key_suggestion = RenderHints::getFootnoteListKey();
266
  }
267
  $bibliography_settings = get_bibliography_settings();
268
  $footnote_list_key = $bibliography_settings['enabled'] == 1 ? BIBLIOGRAPHY_FOOTNOTE_KEY : BIBLIOGRAPHY_FOOTNOTE_KEY . '-' . $key_suggestion;
269
  return $footnote_list_key;
270
}
271

    
272

    
273
/**
274
 * Creates footnote markup for the name relationship and
275
 * registers it in the {@link \FootnoteManager}. The resulting foonote
276
 * key is returned as markup.
277
 *
278
 * @param $name_rel
279
 *   The cdm name relationship
280
 * @return \FootnoteKey
281
 *  The FootnoteKey
282
 */
283
function handle_name_relationship_as_footnote($name_rel)
284
{
285
  $footnote_markup = '';
286
  $fnkey = null;
287
  if (isset($name_rel->ruleConsidered) && $name_rel->ruleConsidered) {
288
    $footnote_markup = '<span class="rule_considered">' . $name_rel->ruleConsidered . '</span> ';
289
  }
290
  if (isset($name_rel->source->citation)) {
291
    $footnote_markup .= '<span class="reference">' . $name_rel->source->citation->titleCache . '</span>';
292
  }
293
  if (isset($name_rel->source->citationMicroReference) && $name_rel->source->citationMicroReference) {
294
    $footnote_markup .= (isset($name_rel->source->citation) ? ':' : '') . ' <span class="reference_detail">' . $name_rel->source->citationMicroReference . '</span>';
295
  }
296
  if ($footnote_markup) {
297
    $fnkey = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $footnote_markup);
298
  }
299
  return $fnkey;
300
}
301

    
302
/**
303
 * Creates footnote markup for nomenclatural status and
304
 * registers it in the {@link \FootnoteManager}. The resulting foonote
305
 * key is returned as markup.
306
 *
307
 * @param $nom_status
308
 * @return \FootnoteKey
309
 *  The FootnoteKey
310
 */
311
function handle_nomenclatural_status_as_footnote($nom_status)
312
{
313
  // NomenclaturalStatus is a subclass of ReferencedEntityBase
314
  // and has the same structure as TaxonNameRelationship
315
  return handle_name_relationship_as_footnote($nom_status);
316
}
317

    
318
/**
319
 * Creates footnote markup for nomenclatural reference of the name and
320
 * registers it in the {@link \FootnoteManager}. The resulting foonote
321
 * key is returned as markup.
322
 *
323
 * @param $name
324
 * The name whose nomenclatural reference is to be shown as footnote
325
 * @return \FootnoteKey
326
 *  The FootnoteKey
327
 */
328
function handle_nomenclatural_reference_as_footnote($name)
329
{
330
  $footnote_markup = '';
331
  $footnote_key_markup = '';
332
  if (isset($name->nomenclaturalSource->citation) && $name->nomenclaturalSource->citation) {
333
    $footnote_markup .= '<span class="reference">' . $name->nomenclaturalSource->citation->titleCache . '</span>';
334
  }
335
  if (isset($name->nomenclaturalSource->citationMicroReference)) {
336
    $footnote_markup .= ($footnote_key_markup ? ':' : '') . '<span class="reference_detail">' . $name->nomenclaturalSource->citationMicroReference . '</span>';
337
  }
338
  $fnkey = null;
339
  if ($footnote_markup) {
340
    $fnkey = FootnoteManager::addNewFootnote(RenderHints::getFootnoteListKey(), $footnote_markup);
341
  }
342
  return $fnkey;
343
}
344

    
345
/* ============ annotations_and_sources handling =================== */
346

    
347
const ANNOTATIONS_AND_SOURCE_CONFIG_DEFAULT = [
348
  'sources_as_content' => FALSE,
349
  'link_to_name_used_in_source' => TRUE,
350
  'link_to_reference' => TRUE,
351
  'add_footnote_keys' => TRUE,
352
  'bibliography_aware' => FALSE
353
];
354

    
355
  /**
356
 * Provides the default configuration for handle_annotations_and_sources() in the
357
 * synonymy.
358
 *
359
 * @return bool[]
360
 */
361
function synonymy_annotations_and_source_config() {
362
  static $annotations_and_sources_config = null;
363
  if(!$annotations_and_sources_config){
364
    $bibliography_settings = get_bibliography_settings();
365
    $annotations_and_sources_config = [
366
      'sources_as_content' => FALSE,
367
      'link_to_name_used_in_source' => TRUE,
368
      'link_to_reference' => TRUE,
369
      'add_footnote_keys' => TRUE,
370
      'bibliography_aware' => $bibliography_settings['enabled'] == 1
371
    ];
372
  }
373
  return $annotations_and_sources_config;
374
}
375

    
376
/**
377
 * Provides the default configuration for typedesignations which
378
 * are passed to the handle_annotations_and_sources()
379
 * function:
380
 * - 'sources_as_content' => TRUE,
381
 * - 'link_to_name_used_in_source' => FALSE,
382
 * - 'link_to_reference' => TRUE,
383
 * - 'add_footnote_keys' => FALSE,
384
 * - 'bibliography_aware' => FALSE
385
 *
386
 * @return array
387
 */
388
function annotations_and_sources_config_typedesignations() {
389
  static $annotations_and_sources_config = [
390
    'sources_as_content' => TRUE,
391
    'link_to_name_used_in_source' => FALSE,
392
    'link_to_reference' => TRUE,
393
    'add_footnote_keys' => FALSE,
394
    'bibliography_aware' => FALSE
395
  ];
396
  return $annotations_and_sources_config;
397
}
398

    
399
/**
400
 * Provides the default configuration for occurrences which
401
 * are passed to the handle_annotations_and_sources()
402
 * function:
403
 * - 'sources_as_content' => TRUE,
404
 * - 'link_to_name_used_in_source' => TRUE,
405
 * - 'link_to_reference' => FALSE,
406
 * - 'add_footnote_keys' => FALSE,
407
 * - 'bibliography_aware' => FALSE
408
 *
409
 * @return array
410
 */
411
function annotations_and_sources_config_occurrences() {
412
  static $annotations_and_sources_config = [
413
    'sources_as_content' => TRUE,
414
    'link_to_name_used_in_source' => TRUE,
415
    'link_to_reference' => FALSE,
416
    'add_footnote_keys' => FALSE,
417
    'bibliography_aware' => FALSE
418
  ];
419
  return $annotations_and_sources_config;
420
}
421

    
422
function annotation_and_source_config_taxon_node() {
423
  static $conf = null;
424
  if(!$conf){
425
    $bibliography_settings = get_bibliography_settings();
426
    $conf = [
427
      'sources_as_content' => false,
428
      'link_to_name_used_in_source' => false,
429
      'link_to_reference' => true,
430
      'add_footnote_keys' => true,
431
      'bibliography_aware' => $bibliography_settings['enabled'] == 1
432
    ];
433
  }
434
  return $conf;
435
}
436

    
437
/**
438
 * Creates a handle_annotations_and_sources configuration array from feature_block_settings.
439
 *
440
 * The handle_annotations_and_sources configuration array is meant to be used for the
441
 * method handle_annotations_and_sources().
442
 *
443
 * @param $feature_block_settings array
444
 *
445
 * @return array
446
 *   The configuration array for handle_annotations_and_sources()
447
 */
448
function handle_annotations_and_sources_config($feature_block_settings){
449

    
450
  $config = [
451
    'sources_as_content' => $feature_block_settings['sources_as_content'] == 1,
452
    'link_to_name_used_in_source' => $feature_block_settings['link_to_name_used_in_source'] == 1,
453
    'link_to_reference' => $feature_block_settings['link_to_reference'] == 1,
454
    'add_footnote_keys' => (
455
      $feature_block_settings['sources_as_content'] !== 1 ||
456
      $feature_block_settings['sources_as_content_to_bibliography'] == 1
457
    ),
458
    'bibliography_aware' => TRUE // FIXME shouldn't this be retrieved from the settings?
459
  ];
460
  return $config;
461
}
462

    
463
/**
464
 * @param $entity
465
 *    The cdm entity for which the annotations and sources are to be handled.
466
 * @param $inline_text_prefix
467
 *   Only used to decide if the source references should be enclosed in
468
 *   brackets or not when displayed inline. This text will not be included into
469
 *   the response.
470
 * @param $footnote_list_key_suggestion string
471
 *   Optional parameter. If this parameter is left empty (null, 0, "") the
472
 *   footnote key will be determined by the nested method calls by calling
473
 *   RenderHints::getFootnoteListKey().
474
 *
475
 * @return AnnotationsAndSources
476
 *  an object with the following elements:
477
 *   - foot_note_keys: all footnote keys as markup
478
 *   - source_references: an array of the source references citations
479
 *   - names used in source: an associative array of the names in source,
480
 *        the name in source strings are de-duplicated
481
 *        !!!NOTE!!!!: this field will most probably be removed soon (TODO)
482
 */
483
function handle_annotations_and_sources($entity, $inline_text_prefix = null, $footnote_list_key_suggestion = null, AnnotationsAndSources $annotationsAndSources = null) {
484

    
485
  if($annotationsAndSources == null){
486
    $annotationsAndSources = new AnnotationsAndSources();
487
  }
488

    
489
  // some entity types only have single sources:
490
  $sources = cdm_entity_sources_sorted($entity);
491

    
492
  $config = RenderHints::getAnnotationsAndSourceConfig();
493

    
494
  if ($config['sources_as_content']) {
495
    foreach ($sources as $source) {
496
      if (_is_original_source_type($source)) {
497
        $reference_citation = render_original_source(
498
          $source,
499
          $config['link_to_reference'],
500
          $config['link_to_name_used_in_source']
501
        );
502

    
503
        if ($reference_citation) {
504
          if (empty($inline_text_prefix)) {
505
            $annotationsAndSources->addSourceReferencesCitation($reference_citation);
506
          } else {
507
            $annotationsAndSources->addSourceReferencesCitation(' (' . $reference_citation . ')');
508
          }
509
        }
510

    
511
        // also put the name in source into the array, these are already included in the $reference_citation but are
512
        // still required to be available separately in some contexts.
513
        $name_in_source_render_array = compose_name_in_source(
514
          $source,
515
          $config['link_to_name_used_in_source']
516
        );
517

    
518
        if (!empty($name_in_source_render_array)) {
519
          $annotationsAndSources->putNamesUsedInSource($name_in_source_render_array['#_plaintext'], drupal_render($name_in_source_render_array));
520
        }
521
      }
522
    } // END of loop over sources
523

    
524
    // annotations footnotes separate from sources
525
    $footnote_keys = cdm_entity_annotations_as_footnote_keys($entity, $footnote_list_key_suggestion);
526
    $annotationsAndSources->addAllFootNoteKeys($footnote_keys);
527

    
528
  } // END of references inline
529

    
530
  // footnotes for sources and annotations or put into into bibliography if requested ...
531
  if ($config['add_footnote_keys']) {
532
    $annotationsAndSources->addAllFootNoteKeys(cdm_entity_footnotes(
533
      $entity,
534
      $footnote_list_key_suggestion,
535
      $config['link_to_reference'],
536
      $config['link_to_name_used_in_source'],
537
      (!empty($config['bibliography_aware']) ? $config['bibliography_aware'] : FALSE)
538
    ));
539
  }
540
  return $annotationsAndSources;
541
}
542

    
543
/**
544
 * Get the source or the sources from a cdm entity and return them ordered by see compare_original_sources()
545
 * (Some entity types only have single sources)
546
 * @param $entity
547
 *
548
 * @return array
549
 */
550
function cdm_entity_sources_sorted($entity) {
551
  if (isset($entity->source) && is_object($entity->source)) {
552
    $sources = [$entity->source];
553
  }
554
  else if (isset($entity->sources)) {
555
    $sources = $entity->sources;
556
  }
557
  else {
558
    // try to load the sources
559
    if(isset_not_empty($entity->uuid)){
560
      $sources = cdm_ws_fetch_all(cdm_compose_ws_url('portal/' . cdm_ws_base_uri($entity->class), [ $entity->uuid, 'sources']));
561
    } else {
562
      // this may happen with DerivedUnitFaced, also with others?
563
      $sources = [];
564
    }
565
  }
566
  usort($sources, 'compare_original_sources');
567
  return $sources;
568
}
569

    
570
/**
571
 * Compare two different footnotes objects.
572
 *
573
 * The comparison is based on the footnote key. The one which is
574
 * displayed as footnote number.
575
 *
576
 * @param mixed $a
577
 *   Footnote object $a.
578
 * @param mixed $b
579
 *   Footnote object $b.
580
 *
581
 * @return int
582
 *
583
 * @deprecated seems to be unused: TODO remove!
584
 */
585
function footnotes_key_compare($a, $b) {
586
  $res = 0;
587
  if (empty($a) || empty($b)) {
588
    return $res;
589
  }
590
  if ($a->keyStr < $b->keyStr) {
591
    $res = -1;
592
  }
593
  elseif ($a->keyStr > $b->keyStr) {
594
    $res = 1;
595
  }
596
  return $res;
597
}
598

    
599

    
(4-4/15)