Project

General

Profile

Download (15.9 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2

    
3
/**
4
 * @file
5
 * Functions for handling CDM TaggedText arrays
6
 *
7
 *
8
 * @copyright
9
 *   (C) 2007-2018 EDIT
10
 *   European Distributed Institute of Taxonomy
11
 *   http://www.e-taxonomy.eu
12
 *
13
 *   The contents of this module are subject to the Mozilla
14
 *   Public License Version 1.1.
15
 * @see http://www.mozilla.org/MPL/MPL-1.1.html
16
 *
17
 * @author
18
 *   - Andreas Kohlbecker <a.kohlbecker@BGBM.org>
19
 */
20

    
21
function tagged_text_new($tag_type, $text = null){
22
  $tt = new stdClass();
23
  $tt->type = $tag_type;
24
  $tt->text = $text;
25
  return $tt;
26
}
27

    
28
/**
29
 * Adds an array of render options to specific tagged text elements.
30
 *
31
 * The attributes are added as $tagged_text_item['attributes']. Existing 'attributes' are
32
 * preserved by merging new ones  to the existing array.
33
 *
34
 * @param array $taggedtxt
35
 * @param array $attributes_map array
36
 *   An array of arrays with following elements in each element array:
37
 *    - 'filter-type': the tagged text type to which the attributes are applicable
38
 *    - 'filter-uuid': (optional) and optional filter to only match a specific uuid.
39
 *    - 'attributes': array of attributes as accepted by drupal_attributes()
40
 *    - 'prefix': like the drupal_render() '#prefix' option
41
 *    - 'suffix': like the drupal_render() '#prefix' option
42
 */
43
function cdm_tagged_text_add_options(array &$taggedtxt, array $attributes_map){
44

    
45
  foreach ($attributes_map as $attribute_data){
46
    foreach ($taggedtxt as &$tt){
47
      if($tt->type == $attribute_data['filter-type']){
48
        if(isset($attribute_data['filter-uuid'])){
49
          if($tt->uuid !== $attribute_data['filter-uuid']){
50
            // ignore
51
            continue;
52
          }
53
        }
54
        // $tt matched type and filter-uuid if set, apply options
55
        foreach (array('attributes', 'prefix', 'suffix') as $key ){
56
          if(isset($attribute_data[$key])){
57
            $tt->$key = $attribute_data[$key];
58
          }
59
        }
60
      }
61
    }
62
  }
63
}
64

    
65
/**
66
 * Walks the passed TaggedText array to find all elements which have a
67
 * TaggedText->entityReference. For each of these the taggedTexts is loaded
68
 * from the webservice and the original entry in the TaggedText array will be
69
 * replaced by the newly loaded array.
70
 *
71
 * Existing 'attributes' (@see cdm_tagged_text_add_options()) fields will be preserved by
72
 * copying them to each of the replacement tagged text items. 'prefix' will be added to
73
 * the first of the replace items and 'suffix' to the last one.
74
 *
75
 *
76
 * @param array $taggedtxt
77
 *    The original TaggedText array
78
 * @param array $skiptags
79
 *    Optional list of tag names to skip
80
 * @return array
81
 *    The new tagged text with all TaggedText->entityReference objects expanded
82
 */
83
function cdm_tagged_text_expand_entity_references(array $taggedtxt, $skiptags = array()) {
84
  $tagged_text_expanded = array();
85
  foreach ($taggedtxt as $tt) {
86
    if (isset($tt->entityReference) && !in_array($tt->type, $skiptags)) {
87
      $base_uri = cdm_ws_base_uri($tt->entityReference->type);
88
      if($base_uri){
89
        if(str_endsWith($base_uri, '$0')){
90
          // sanitize placeholders at the end
91
          $base_uri = substr($base_uri, 0, strlen($base_uri) - 2);
92
        }
93
        $tagged_text_method = "/taggedText";
94
        if($base_uri == CDM_WS_NAME){
95
          $tagged_text_method = "/taggedName";
96
        }
97
        $referenced_tt = cdm_ws_get($base_uri . "/" . $tt->entityReference->uuid . $tagged_text_method);
98
        if($referenced_tt){
99
          if(isset($tt->attributes)){
100
            foreach($referenced_tt as $reftt){
101
              $reftt->attributes = $tt->attributes;
102
            }
103
          }
104
          if(isset($tt->prefix)){
105
            $referenced_tt[0]->prefix = $tt->prefix;
106
          }
107
          if(isset($tt->suffix)){
108
            $referenced_tt[count($referenced_tt)-1]->suffix = $tt->suffix;
109
          }
110
          $tagged_text_expanded = array_merge($tagged_text_expanded, $referenced_tt);
111
          continue;
112
        }
113
      }
114
    }
115
    // default case
116
    $tagged_text_expanded[] = $tt;
117
  }
118
  return $tagged_text_expanded;
119
}
120

    
121
/**
122
 * Converts an array of TaggedText items into corresponding html tags.
123
 *
124
 * Each item is provided with a class attribute which is set to the key of the
125
 * TaggedText item.
126
 *
127
 * Tagged text where the type starts with 'PLACEHOLDER_' will be added to the markup as plain text whereas the
128
 * taggedText->type wrapped in curly brackets: '{'. $tt->text . '}' is used as text.
129
 * see tagged_text_extract_reference_and_detail()
130
 *
131
 * In addition to the tagged text element fields as defined in the cdm this method also recognizes:
132
 *    - 'attributes': array of attributes as accepted by drupal_attributes()
133
 *    - 'prefix': like the drupal_render() '#prefix' option
134
 *    - 'suffix': like the drupal_render() '#prefix' option
135
 * See also cdm_tagged_text_add_options()
136
 *
137
 * The algorithm of this functions is basically the same as for
138
 * eu.etaxonomy.cdm.strategy.cache.TaggedCacheHelper.createString(List<TaggedText> tags, HTMLTagRules htmlRules)
139
 *
140
 * @param array $taggedtxt
141
 *   Array with text items to convert.
142
 * @param array $skiptags
143
 *   Array of tag names to skip
144
 * @param $tag
145
 * @param $options
146
 *     - 'html' (default FALSE): Whether $text is HTML or just plain-text. NOTE! in this case the text is not
147
 *              translated by t()
148
 *
149
 * @return string
150
 *   The markup.
151
 */
152
function cdm_tagged_text_to_markup(array $taggedtxt, $skiptags = array(), $tag = 'span', $options = array()) {
153

    
154
  $out = '';
155
  $was_separator = false;
156
  $last_type = null;
157
  $last_suffix = '';
158
  $i = 0;
159
  foreach ($taggedtxt as $tt) {
160
    if (!in_array($tt->type, $skiptags) && $tt->text) {
161

    
162
      $is_first = $i == 0;
163
      $is_separator = is_tagged_text_sepatator_type($tt->type);
164
      if(str_beginsWith($tt->type, 'PLACEHOLDER_')){
165
        $out .=  '{'. $tt->type . '}';
166
      } else {
167

    
168
        // attributes
169
        $attributes = array();
170
        if(isset($tt->attributes)){
171
          $attributes = $tt->attributes;
172
        }
173
        if(!isset($attributes['class'])){
174
          $attributes['class'] = array();
175
        }
176
        $attributes['class'][] = $tt->type;
177
        if(isset($tt->entityReference)){
178
          $attributes['class'][] = html_class_attribute_ref($tt->entityReference);
179
        }
180

    
181
        // prefix and suffix
182
        $prefix = '';
183
        $suffix = '';
184
        if(isset($tt->prefix)){
185
          $prefix = $tt->prefix;
186
        }
187
        if(isset($tt->suffix)){
188
          $suffix = $tt->suffix;
189
        }
190

    
191
        if(($last_suffix || $last_type && $last_type != $tt->type) && $tag) {
192
          $out .= '</' . $tag . '>' . $last_suffix;
193
        }
194
        if(($prefix || !$last_type || $last_type != $tt->type) && $tag){
195
          $out .= $prefix . '<' . $tag . drupal_attributes($attributes) . '>';
196
        }
197
        if(!$is_separator && !$was_separator && !$is_first){
198
          $out .= " ";
199
        }
200
        if(isset($options['html']) &&  $options['html']){
201
          $out .= $tt->text;
202
        } else {
203
          $out .= t('@text', array('@text' => $tt->text));
204
        }
205
        $was_separator = $is_separator;
206
        $last_type = $tt->type;
207
        $last_suffix = $suffix;
208
      }
209
    }
210
    $i++;
211
  }
212
  if($tag) {
213
    $out .= '</' . $tag . '>';
214
  }
215
  return $out;
216
}
217

    
218
/**
219
 * Converts an array of TaggedText items into corresponding plain text string
220
 *
221
 * Each item is provided with a class attribute which is set to the key of the
222
 * TaggedText item.
223
 *
224
 * The algorithm of this functions is basically the same as for
225
 * eu.etaxonomy.cdm.strategy.cache.TaggedCacheHelper.createString(List<TaggedText> tags)
226
 *
227
 * @param array $taggedtxt
228
 *   Array with text items to convert.
229
 * @param array $skiptags
230
 *   Array of tag names to skip
231
 *
232
 * @return string
233
 *   The plain text
234
 */
235
function cdm_tagged_text_to_string(array $taggedtxt, $skiptags = array()) {
236

    
237
  return cdm_tagged_text_to_markup($taggedtxt, $skiptags, null);
238
}
239

    
240
/**
241
 * See cdmlib: boolean eu.etaxonomy.cdm.strategy.cache.TagEnum.isSeparator();
242
 *
243
 * @return bool
244
 */
245
function is_tagged_text_sepatator_type($tagged_text_type){
246
  static $separator_names = array('separator', 'postSeparator');
247
  $result = array_search($tagged_text_type, $separator_names) !== false;
248
  return $result;
249
}
250

    
251

    
252
/**
253
 * Finds the text tagged with $tag_type in an array of taggedText instances.
254
 *
255
 *
256
 * @param array $taggedtxt
257
 *   Array with text items.
258
 * @param array $include_tag_types
259
 *   Array of the tag types for which to find text items in the $taggedtxt array, or NULL
260
 *   to return all texts.
261
 *
262
 * @return array
263
 *   An array with the texts mapped by $tag_type.
264
 */
265
function cdm_tagged_text_values(array $taggedtxt, $include_tag_types = NULL) {
266
  $tokens = array();
267
  if (!empty($taggedtxt)) {
268
    foreach ($taggedtxt as $tagtxt) {
269
      if ($include_tag_types === NULL || array_search($tagtxt->type, $include_tag_types) !== false) {
270
        $tokens[] = $tagtxt->text;
271
      }
272
    }
273
  }
274
  return $tokens;
275
}
276

    
277
/**
278
 * Preprocess the taggedTitle arrays.
279
 *
280
 * Step 1: Turns 'newly' introduces tag types ("hybridSign")
281
 * into tag type "name"
282
 *
283
 * Step 2: Two taggedTexts which have the same type and which have
284
 * a separator between them are merged together.
285
 *
286
 * @param array $taggedTextList
287
 *    An array of TaggedText objects
288
 */
289
function normalize_tagged_text(&$taggedTextList) {
290

    
291
  if (is_array($taggedTextList)) {
292

    
293
    // First pass: rename.
294
    for ($i = 0; $i < count($taggedTextList); $i++) {
295

    
296
      if ($taggedTextList[$i]->type == "hybridSign") {
297
        $taggedTextList[$i]->type = "name";
298
      }
299
    }
300

    
301
    // Second pass: resolve separators.
302
    $taggedNameListNew = array();
303
    for ($i = 0; $i < count($taggedTextList); $i++) {
304

    
305
      // elements of the same type concatenated by a separator should be merged together
306
      if (isset($taggedTextList[$i + 2]) && $taggedTextList[$i + 1]->type == "separator" && $taggedTextList[$i]->type == $taggedTextList[$i + 2]->type) {
307
        $taggedName = clone $taggedTextList[$i];
308
        $taggedName->text = $taggedName->text . $taggedTextList[$i + 1]->text . $taggedTextList[$i + 2]->text;
309
        $taggedNameListNew[] = $taggedName;
310
        ++$i;
311
        ++$i;
312
        continue;
313
      }
314
      // no special handling
315
      $taggedNameListNew[] = $taggedTextList[$i];
316

    
317
    }
318
    $taggedTextList = $taggedNameListNew;
319
  }
320
}
321

    
322
/**
323
 * Extracts from a tagged text array the tagged text for a references which is concatenated with citation
324
 * detail separator and citation detail into one single element.
325
 *
326
 * @param $tagged_text
327
 *    The tagged text to operate on
328
 * @param string $ref_tag_type
329
 *    The tagtype for a secreference is "secReference", but "relSecReference" is also used in case of relationships.
330
 * @param bool $replace_with_placeholder
331
 *    Indicates the method to add a empty placeholder tagged text alement as relpacement for the extrated tagged text
332
 *    elements.
333
 * @param string $ref_detail_tag_type
334
 * @return array
335
 */
336
function tagged_text_extract_reference(&$tagged_text, $ref_tag_type = "reference", $replace_with_placeholder = false) {
337

    
338
  $extracted_tt = array();
339
  if (is_array($tagged_text)) {
340
    $extract_pos = null;
341
    for ($i = 0; $i < count($tagged_text); $i++) {
342
      if ($tagged_text[$i]->type == $ref_tag_type){
343
        if ($i > 0 && $tagged_text[$i - 1]->type == 'separator') {
344
          // the reference may be preceeded by a separator in case it is not a in-reference
345
          $extracted_tt[] = $tagged_text[$i - 1];
346
          unset($tagged_text[$i - 1]);
347
        } else {
348
          // need to add a separator to since the reference tagged text will become the first element
349
          // ant thus will not be preceded by a separator
350
          $extracted_tt[] = tagged_text_new('separator', ' ');
351
        }
352
        $extracted_tt[] = $tagged_text[$i];
353
        if ($replace_with_placeholder) {
354
          // text must not be null, see cdm_tagged_text_to_markup()
355
          $tagged_text[$i] = tagged_text_new("PLACEHOLDER_" . $ref_tag_type, "PLACEHOLDER_" . $ref_tag_type);
356
        } else {
357
          unset($tagged_text[$i]);
358
        }
359
        break;
360
      }
361
    }
362
  }
363
  $tagged_text = array_values($tagged_text); // re-index array to make it continuous again
364
  return $extracted_tt;
365
}
366

    
367
/**
368
 * Extracts the tagged text for sec references with separator and citation detail from a tagged text array.
369
 * @param $tagged_text
370
 *    The tagged text to operate on
371
 * @param string $ref_tag_type
372
 *    The tagtype for a secreference is "secReference", but "relSecReference" is also used in case of relationships.
373
 * @param bool $replace_with_placeholder
374
 *    Indicates the method to add a empty placeholder tagged text alement as relpacement for the extrated tagged text
375
 *    elements.
376
 * @param string $ref_detail_tag_type
377
 * @return array
378
 */
379
function tagged_text_extract_reference_and_detail(&$tagged_text, $ref_tag_type = "secReference", $replace_with_placeholder = false) {
380

    
381
  $extracted_tt = array();
382
  if (is_array($tagged_text)) {
383
    $extract_pos = null;
384
    for ($i = 0; $i < count($tagged_text) - 1; $i++) {
385
      if ($tagged_text[$i + 1]->type == $ref_tag_type && $tagged_text[$i]->type == "separator"){
386
        $extracted_tt[0] = $tagged_text[$i];
387
        $extracted_tt[1] = $tagged_text[$i + 1];
388

    
389
        if($replace_with_placeholder){
390
          // text must not be null, see cdm_tagged_text_to_markup()
391
          $tagged_text[$i] = tagged_text_new("PLACEHOLDER_" . $ref_tag_type, "PLACEHOLDER_" . $ref_tag_type);
392
        } else {
393
          unset($tagged_text[$i]);
394
        }
395
        unset($tagged_text[$i + 1]);
396
        // also get the microreference which could be in $tagged_text[$i + 3]
397
        if(isset($tagged_text[$i + 3])  && $tagged_text[$i + 2]->type == "separator" && $tagged_text[$i + 3]->type == "secMicroReference"){
398
          $extracted_tt[2] = $tagged_text[$i + 2];
399
          $extracted_tt[3] = $tagged_text[$i + 3];
400
          unset($tagged_text[$i + 2]);
401
          unset($tagged_text[$i + 3]);
402
        }
403
        break;
404
      }
405
    }
406
  }
407
  $tagged_text = array_values($tagged_text); // re-index array to make it continuous again
408
  return $extracted_tt;
409
}
410

    
411
function tagged_text_extract_nomstatus(&$tagged_text) {
412

    
413
  $extracted_tt = [];
414
  if (is_array($tagged_text)) {
415
    $itemcnt = count($tagged_text); // preserve the count since the array may shrink while processing
416
    for ($i = 0; $i < $itemcnt; $i++) {
417
      if(isset($tagged_text[$i])){ // prevent from accessing removed indices
418
        if ($tagged_text[$i]->type == "nomStatus"){
419
          $extracted_status_items = [];
420
          $extracted_status_items[] = $tagged_text[$i];
421
          if(isset($tagged_text[$i + 1]) && $tagged_text[$i + 1]->type == "postSeparator"){
422
            $extracted_status_items[] = $tagged_text[$i + 1];
423
            unset($tagged_text[$i + 1]);
424
          }
425
          if ($tagged_text[$i - 1]->type == "separator"){
426
            array_unshift($extracted_status_items, $tagged_text[$i - 1]);
427
            unset($tagged_text[$i - 1]);
428
          }
429
          unset($tagged_text[$i]);
430
          $extracted_tt = array_merge($extracted_tt, $extracted_status_items);
431
        }
432
      }
433
    }
434
  }
435
  $tagged_text = array_values($tagged_text); // re-index array to make it continuous again
436
  return $extracted_tt;
437
}
438

    
439
function tagged_text_extract(&$tagged_text, $type, $replace_with_placeholder = false) {
440
  $matching_elements = array();
441
  if (is_array($tagged_text)) {
442
    for ($i = 0; $i < count($tagged_text); $i++) {
443
      if($tagged_text[$i]->type == $type){
444
        $matching_elements[] = $tagged_text[$i];
445
        if($replace_with_placeholder){
446
          // text must not be null, see cdm_tagged_text_to_markup()
447
          $tagged_text[$i] = tagged_text_new("PLACEHOLDER_" . $type, "PLACEHOLDER_" . $type);
448
        } else {
449
          unset($tagged_text[$i]);
450
        }
451
      }
452
    }
453
  }
454
  $tagged_text = array_values($tagged_text); // re-index array to make it continuous again
455
  return $matching_elements;
456
}
457

    
458
function find_tagged_text_elements(&$tagged_text, $type){
459
  $matching_elements = array();
460
  if (is_array($tagged_text)) {
461
    for ($i = 0; $i < count($tagged_text) - 1; $i++) {
462
      if($tagged_text[$i]->type == $type){
463
        $matching_elements[] = $tagged_text[$i];
464
      }
465
    }
466
  }
467
  return $matching_elements;
468
}
(9-9/12)