Project

General

Profile

Download (23 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 template 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
 * The following keys are curretly recogized:
40
 *
41
 *   - list_of_taxa:
42
 *   - acceptedFor:
43
 *   - taxon_page_synonymy
44
 *   - typedesignations
45
 *   - taxon_page_title
46
 *   - polytomousKey
47
 *   - na: name + authorship
48
 *   - nar:name + authorship + reference
49
 *   - #DEFAULT
50
 *
51
 * A single render template can be used for multiple render paths. In this case the according key of the render templates
52
 * array element should be the list of these render paths concatenated by ONLY a comma character without any whitespace.
53
 *
54
 * A render template is an associative array. The keys of this array are referring to the keys as defined in the part
55
 * definitions array.
56
 * @see get_partDefinition($taxonNameType) for more information
57
 *
58
 * The value of the render template element must be set to TRUE in order to let this part being rendered.
59
 * The namePart, nameAuthorPart and referencePart can also hold an associative array with a single
60
 * element: array('#uri' => TRUE). The value of the #uri element will be replaced by the according
61
 * links if the parameters $nameLink or $refenceLink are set.
62
 *
63
 * @param string $renderPath
64
 *   The render path can consist of multiple dot separated elements
65
 *   @see RenderHints::getRenderPath()
66
 * @param string $nameLink
67
 *   The link path ot URL to be used for name parts if a link is forseen in the template
68
 *   matching the given $renderPath.
69
 * @param string $referenceLink
70
 *   The link path ot URL to be used for nomenclatural reference parts if a link is forseen
71
 *   in the template matching the given $renderPath.
72
 * @return array
73
 *   An associative array, the render template
74
 */
75
function get_nameRenderTemplate($renderPath, $nameLink = NULL, $referenceLink = NULL) {
76

    
77
  static $default_render_templates = NULL;
78
  static $split_render_templates = NULL;
79

    
80

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

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

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

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

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

    
129

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

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

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

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

    
159
  return $template;
160
}
161

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

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

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

    
234
  if (array_key_exists($taxonNameType, $part_definitions)) {
235
    return $part_definitions[$taxonNameType];
236
  } else {
237
    return $part_definitions['#DEFAULT']; // covers ViralNames and general NonViralNames
238
  }
239

    
240
}
241

    
242

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

    
274
  if($taxon_name_or_taxon_base->class == 'Taxon' || $taxon_name_or_taxon_base->class == 'Synonym'){
275
    $taxonName = $taxon_name_or_taxon_base->name;
276
    // use the TaxonBase.taggedTitle so we have the secRef
277
    $taggedTitle = $taxon_name_or_taxon_base->taggedTitle;
278
  } else {
279
    // assuming this is a TaxonNameBase
280
    $taxonName = $taxon_name_or_taxon_base;
281
    $taggedTitle = $taxon_name_or_taxon_base->taggedName;
282
  }
283

    
284

    
285
  $renderTemplate = get_nameRenderTemplate(RenderHints::getRenderPath(), $nameLink, $refenceLink);
286
  $partDefinition = get_partDefinition($taxonName->class);
287

    
288
  // Apply definitions to template.
289
  foreach ($renderTemplate as $part => $uri) {
290

    
291
    if (isset($partDefinition[$part])) {
292
      $renderTemplate[$part] = $partDefinition[$part];
293
    }
294
    if (is_array($uri) && isset($uri['#uri'])) {
295
      $renderTemplate[$part]['#uri'] = $uri['#uri'];
296
    }
297
  }
298

    
299
  $secref_tagged_text = split_secref_from_tagged_text($taggedTitle);
300
  $nom_status_tagged_text = split_nomstatus_from_tagged_text($taggedTitle);
301
  normalize_tagged_text($taggedTitle);
302

    
303
  $firstEntryIsValidNamePart =
304
    isset($taggedTitle)
305
    && is_array($taggedTitle)
306
    && isset($taggedTitle[0]->text)
307
    && is_string($taggedTitle[0]->text)
308
    && $taggedTitle[0]->text != ''
309
    && isset($taggedTitle[0]->type)
310
    && $taggedTitle[0]->type == 'name';
311
  $lastAuthorElementString = FALSE;
312

    
313
  // Got to use second entry as first one, see ToDo comment below ...
314
  if ($firstEntryIsValidNamePart) {
315

    
316
    $taggedName = $taggedTitle;
317
    $hasNamePart_with_Authors = isset($renderTemplate['namePart']) && isset($renderTemplate['namePart']['authors']);
318
    $hasNameAuthorPart_with_Authors = isset($renderTemplate['nameAuthorPart']) && isset($renderTemplate['nameAuthorPart']['authors']);
319

    
320
    if (!(($hasNamePart_with_Authors) || ($hasNameAuthorPart_with_Authors))) {
321
      // Find author and split off from name.
322
      // TODO expecting to find the author as the last element.
323
      /*
324
      if($taggedName[count($taggedName)- 1]->type == 'authors'){
325
        $authorTeam = $taggedName[count($taggedName)- 1]->text;
326
        unset($taggedName[count($taggedName)- 1]);
327
      }
328
      */
329

    
330
      // Remove all authors.
331
      $taggedNameNew = array();
332
      foreach ($taggedName as $element) {
333
        if ($element->type != 'authors') {
334
          $taggedNameNew[] = $element;
335
        }
336
        else {
337
          $lastAuthorElementString = $element->text;
338
        }
339
      }
340
      $taggedName = $taggedNameNew;
341
      unset($taggedNameNew);
342
    }
343
    $name = '<span class="' . $taxonName->class . '">' . cdm_tagged_text_to_markup($taggedName, 'span', ' ', $skiptags) . '</span>';
344
  }
345
  else {
346
    $name = '<span class="' . $taxonName->class . '_titleCache">' . $taxonName->titleCache . '</span>';
347
  }
348

    
349
  // Fill name into $renderTemplate.
350
  array_setr('name', $name, $renderTemplate);
351

    
352
  // Fill with authorTeam.
353
  /*
354
  if($authorTeam){
355
    $authorTeamHtml = ' <span class="authorTeam">'.$authorTeam.'</span>';
356
    array_setr('authorTeam', $authorTeamHtml, $renderTemplate);
357
  }
358
  */
359

    
360
  // Fill with reference.
361
  if (isset($renderTemplate['referencePart']) && !$is_type_designation) {
362

    
363
    // default separator
364
    $separator = '';
365

    
366
    // [Eckhard]:"Komma nach dem Taxonnamen ist grunsätzlich falsch,
367
    // Komma nach dem Autornamen ist überall dort falsch, wo ein "in" folgt."
368
    if (isset($renderTemplate['referencePart']['reference']) && isset($taxonName->nomenclaturalReference)) {
369
      $microreference = NULL;
370
      if (isset($renderTemplate['referencePart']['microreference'])&& isset($taxonName->nomenclaturalMicroReference)) {
371
        $microreference = $taxonName->nomenclaturalMicroReference;
372
      }
373
      $citation = cdm_ws_getNomenclaturalReference($taxonName->nomenclaturalReference->uuid, $microreference);
374

    
375
      // Find preceding element of the reference.
376
      $precedingKey = get_preceding_contentElementKey('reference', $renderTemplate);
377
      if (str_beginsWith($citation, ", in")) {
378
        $citation = substr($citation, 2);
379
        $separator = ' ';
380
      }
381
      elseif (!str_beginsWith($citation, "in") && $precedingKey == 'authors') {
382
        $separator = ', ';
383
      } else {
384
        $separator = ' ';
385
      }
386

    
387

    
388
      $referenceArray['#separator'] = $separator;
389
      $referenceArray['#html'] = '<span class="reference">' . $citation . '</span>';
390
      array_setr('reference', $referenceArray, $renderTemplate);
391
    }
392

    
393
    // If authors have been removed from the name part the last named authorteam
394
    // should be added to the reference citation, otherwise, keep the separator
395
    // out of the reference.
396
    if (isset($renderTemplate['referencePart']['authors']) && $lastAuthorElementString) {
397
      // If the nomenclaturalReference citation is not included in the
398
      // reference part but diplay of the microreference
399
      // is wanted, append the microreference to the authorTeam.
400
      $citation = '';
401
      if (!isset($renderTemplate['referencePart']['reference']) && isset($renderTemplate['referencePart']['microreference'])) {
402
        $separator = ": ";
403
        $citation = $taxonName->nomenclaturalMicroReference;
404
      }
405
      $referenceArray['#html'] = ' <span class="reference">' . $lastAuthorElementString . $separator . $citation . '</span>';
406
      array_setr('authors', $referenceArray, $renderTemplate);
407
    }
408
  }
409

    
410
  $is_reference_year = false;
411
  if (isset($renderTemplate['referenceYearPart']['reference.year'])) {
412
    if(isset($taxonName->nomenclaturalReference->datePublished)){
413
      $referenceArray['#html'] = ' <span class="reference">' . timePeriodToString($taxonName->nomenclaturalReference->datePublished) . '</span>';
414
      array_setr('reference.year', $referenceArray, $renderTemplate);
415
      $is_reference_year = true;
416
    }
417
  }
418

    
419
  // Fill with status.
420
  if(isset($renderTemplate['statusPart'])){
421
    if (isset($nom_status_tagged_text[0])) {
422
      if (array_setr('status', TRUE, $renderTemplate)) {
423
        array_setr('status', '<span class="nomenclatural_status">' . cdm_tagged_text_to_markup($nom_status_tagged_text, 'span', '', array('postSeparator')) . '</span>', $renderTemplate);
424
      }
425
    }
426
  }
427

    
428
  if (isset($renderTemplate['secReferencePart'])){
429
    if(isset($secref_tagged_text[1])){
430
      $post_separator_markup = $is_reference_year ? '.': '';
431
      if(isset($nom_status_tagged_text[count($nom_status_tagged_text -1 )]) && $nom_status_tagged_text[count($nom_status_tagged_text -1 )]->type ==  'postSeparator'){
432
        $post_separator_markup = cdm_tagged_text_to_markup(array($nom_status_tagged_text[count($nom_status_tagged_text -1 )]));
433
      };
434
      array_setr('secReference',
435
        $post_separator_markup
436
          . ' <span class="sec_reference">'
437
          . join(' ', cdm_tagged_text_values($secref_tagged_text))
438
          . '</span>', $renderTemplate);
439
    }
440
  }
441

    
442

    
443
  // Fill with protologues etc...
444
  $descriptionHtml = '';
445
  if (array_setr('description', TRUE, $renderTemplate)) {
446
    $descriptions = cdm_ws_get(CDM_WS_PORTAL_NAME_DESCRIPTIONS, $taxonName->uuid);
447
    foreach ($descriptions as $description) {
448
      if (!empty($description)) {
449
        foreach ($description->elements as $description_element) {
450
          $second_citation = '';
451
          if (isset($description_element->multilanguageText_L10n) && $description_element->multilanguageText_L10n->text) {
452
            $second_citation = '[& ' . $description_element->multilanguageText_L10n->text . '].';
453
          }
454
          $descriptionHtml .= $second_citation;
455
          $descriptionHtml .= theme("cdm_media", array(
456
              'descriptionElement' => $description_element,
457
              'mimeTypePreference' => array(
458
                'application/pdf',
459
                'image/png',
460
                'image/jpeg',
461
                'image/gif',
462
                'text/html',
463
              )
464
            )
465
          );
466

    
467
        }
468
      }
469
    }
470
    array_setr('description', $descriptionHtml, $renderTemplate);
471
  }
472

    
473
  // Render.
474
  $out = '<span class="' . html_class_attribute_ref($taxon_name_or_taxon_base). '" data-cdm-ref="/name/' . $taxonName->uuid . '">';
475

    
476
  foreach ($renderTemplate as $partName => $part) {
477
    $separator = '';
478
    $partHtml = '';
479
    $uri = FALSE;
480
    if (!is_array($part)) {
481
      continue;
482
    }
483
    if (isset($part['#uri']) && is_string($part['#uri'])) {
484
      $uri = $part['#uri'];
485
      unset($part['#uri']);
486
    }
487
    foreach ($part as $key => $content) {
488
      $html = '';
489
      if (is_array($content)) {
490
        $html = $content['#html'];
491
        if(isset($content['#separator'])) {
492
          $separator = $content['#separator'];
493
        }
494
      }
495
      elseif (is_string($content)) {
496
        $html = $content;
497
      }
498
      $partHtml .= '<span class="' . $key . '">' . $html . '</span>';
499
    }
500
    if ($uri) {
501
      // cannot use l() here since the #uri aleady should have been processed through uri() at this point
502
      $out .= $separator . '<a href="' . $uri . '" class="' . $partName . '">' . $partHtml . '</a>';
503

    
504
    }
505
    else {
506
      $out .= $separator . $partHtml;
507
    }
508
  }
509
  $out .= '</span>';
510
  if ($show_annotations) {
511
    // $out .= theme('cdm_annotations_as_footnotekeys', $taxonName);
512
  }
513
  return $out;
514
}
515

    
516
/**
517
 * Renders the string of Homonyms for a given taxon.
518
 *
519
 * @param $taxon
520
 *    A CDM Taxon instance
521
 * @return String
522
 *    The string of homomyns
523
 *
524
 * @throws \Exception
525
 */
526
function cdm_name_relationships_of($taxon) {
527
// =========== START OF HOMONYMS ========== //
528
  RenderHints::pushToRenderStack('homonym');
529
  // the render stack element homonyms is being used in the default render templates !!!, see CDM_NAME_RENDER_TEMPLATES_DEFAULT
530

    
531
  // Later homonym or treated as later homonym AND bloking names.
532
  // TODO apply filter ? $name_rels_to_show = variable_get('name_relationships_to_show', NULL);
533
  $from_name_relations = cdm_ws_get(CDM_WS_PORTAL_TAXON_FROM_NAMERELATIONS,
534
    $taxon->uuid);
535
  $to_name_relations = cdm_ws_get(CDM_WS_PORTAL_TAXON_TO_NAMERELATIONS,
536
    $taxon->uuid);
537
  $name_relations = array_merge($from_name_relations, $to_name_relations);
538

    
539
  $homonyms_array = array();
540

    
541
  if ($name_relations) {
542
    foreach ($name_relations as $element) {
543
      $taxon_html = NULL;
544
      switch ($element->type->uuid) {
545
        case UUID_LATER_HOMONYM :
546
          $elementTaxonBasesUuid = isset ($element->toName->taxonBases [0]->uuid) ? $element->toName->taxonBases [0]->uuid : '';
547

    
548
          //from relation ships -> only shown at fromName-synonym
549
          if ($taxon->name->uuid == $element->fromName->uuid) {
550
            $taxon_html =render_taxon_or_name($element->toName,
551
              url(path_to_name($element->toName->uuid, $taxon->uuid, $elementTaxonBasesUuid))
552
            );
553
          }
554
          break;
555
        case UUID_TREATED_AS_LATER_HOMONYM :
556
          $elementTaxonBasesUuid = isset ($element->toName->taxonBases [0]->uuid) ? $element->toName->taxonBases [0]->uuid : '';
557

    
558
          //from relation ships -> only shown at fromName-synonym
559
          if ($taxon->name->uuid == $element->fromName->uuid) {
560
            $taxon_html = render_taxon_or_name($element->toName, url(path_to_name($element->toName->uuid)));
561
          }
562
          break;
563
        case UUID_BLOCKING_NAME_FOR :
564
          $elementTaxonBasesUuid = isset ($element->fromName->taxonBases [0]->uuid) ? $element->fromName->taxonBases [0]->uuid : '';
565

    
566
          //to relation ships -> only shown at toName-synonym
567
          if ($taxon->name->uuid == $element->toName->uuid) {
568
            $taxon_html = render_taxon_or_name($element->fromName,
569
              url(path_to_name($element->fromName->uuid, $taxon->uuid, $elementTaxonBasesUuid))
570
            );
571
          }
572
          break;
573
        default:
574
          $taxon_html = NULL;
575
      }
576
      if (isset($taxon_html) && $taxon_html) {
577
        if (count($homonyms_array)) {
578
          $homonyms_array [] = 'nec ' . $taxon_html;
579
        }
580
        else {
581
          $homonyms_array [] = 'non ' . $taxon_html;
582
        }
583
      }
584
    }
585
  }
586

    
587
  RenderHints::popFromRenderStack();
588
  return (count($homonyms_array) ?'[' . trim(join(" ", $homonyms_array)) . ']' : '');
589
}
590

    
591

    
592
  /**
593
 * Recursively searches the array for the $key and sets the given value.
594
 *
595
 * @param mixed $key
596
 *   Key to search for.
597
 * @param mixed $value
598
 *   Value to set.'
599
 * @param array $array
600
 *   Array to search in.
601
 *
602
 * @return bool
603
 *   True if the key has been found.
604
 */
605
function &array_setr($key, $value, array &$array) {
606
  $res = NULL;
607
  foreach ($array as $k => &$v) {
608
    if ($key == $k) {
609
      $v = $value;
610
      return $array;
611
    }
612
    elseif (is_array($v)) {
613
      $innerArray = array_setr($key, $value, $v);
614
      if ($innerArray) {
615
        return $array;
616
      }
617
    }
618
  }
619
  return $res;
620
}
621

    
622
/**
623
 * @todo Please document this function.
624
 * @see http://drupal.org/node/1354
625
 */
626
function &get_preceding_contentElement($contentElementKey, array &$renderTemplate) {
627
  $res = NULL;
628
  $precedingElement = NULL;
629
  foreach ($renderTemplate as &$part) {
630
    foreach ($part as $key => &$element) {
631
      if ($key == $contentElementKey) {
632
        return $precedingElement;
633
      }
634
      $precedingElement = $element;
635
    }
636
  }
637
  return $res;
638
}
639

    
640
/**
641
 * @todo Please document this function.
642
 * @see http://drupal.org/node/1354
643
 */
644
function &get_preceding_contentElementKey($contentElementKey, array &$renderTemplate) {
645
  $res = NULL;
646
  $precedingKey = NULL;
647
  foreach ($renderTemplate as &$part) {
648
    if (is_array($part)) {
649
      foreach ($part as $key => &$element) {
650
        if ($key == $contentElementKey) {
651
          return $precedingKey;
652
        }
653
        if (!str_beginsWith($key, '#')) {
654
          $precedingKey = $key;
655
        }
656
      }
657
    }
658
  }
659
  return $res;
660
}
(5-5/8)