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
  $statusHtml = '';
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>', $renderTemplate);
424
    }
425
  }
426

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

    
441

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

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

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

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

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

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

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

    
538
  $homonyms_array = array();
539

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

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

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

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

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

    
590

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

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

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