Passed
Push — new-api ( 2a03a6...15a925 )
by Sebastian
04:45
created

Name::getParent()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 0
cts 2
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
 * citeproc-php
4
 *
5
 * @link        http://github.com/seboettg/citeproc-php for the source repository
6
 * @copyright   Copyright (c) 2016 Sebastian Böttger.
7
 * @license     https://opensource.org/licenses/MIT
8
 */
9
10
namespace Seboettg\CiteProc\Rendering\Name;
11
12
use Seboettg\CiteProc\CiteProc;
13
use Seboettg\CiteProc\Exception\CiteProcException;
14
use Seboettg\CiteProc\Exception\InvalidStylesheetException;
15
use Seboettg\CiteProc\Rendering\HasParent;
16
use Seboettg\CiteProc\Style\InheritableNameAttributesTrait;
17
use Seboettg\CiteProc\Style\Options\DemoteNonDroppingParticle;
18
use Seboettg\CiteProc\Style\Options\SubsequentAuthorSubstituteRule;
19
use Seboettg\CiteProc\Styles\AffixesTrait;
20
use Seboettg\CiteProc\Styles\DelimiterTrait;
21
use Seboettg\CiteProc\Styles\FormattingTrait;
22
use Seboettg\CiteProc\Util\CiteProcHelper;
23
use Seboettg\CiteProc\Util\Factory;
24
use Seboettg\CiteProc\Util\NameHelper;
25
use Seboettg\CiteProc\Util\StringHelper;
26
use SimpleXMLElement;
27
use stdClass;
28
29
/**
30
 * Class Name
31
 *
32
 * The cs:name element, an optional child element of cs:names, can be used to describe the formatting of individual
33
 * names, and the separation of names within a name variable.
34
 *
35
 * @package Seboettg\CiteProc\Rendering\Name
36
 *
37
 * @author Sebastian Böttger <[email protected]>
38
 */
39
class Name implements HasParent
40
{
41
    use InheritableNameAttributesTrait,
0 ignored issues
show
Bug introduced by
The trait Seboettg\CiteProc\Styles\AffixesTrait requires the property $single which is not provided by Seboettg\CiteProc\Rendering\Name\Name.
Loading history...
42
        FormattingTrait,
43
        AffixesTrait,
44
        DelimiterTrait;
45
46
    /**
47
     * @var array
48
     */
49
    protected $nameParts;
50
51
    /**
52
     * Specifies the text string used to separate names in a name variable. Default is ”, ” (e.g. “Doe, Smith”).
53
     *
54
     * @var
55
     */
56
    private $delimiter = ", ";
57
58
    /**
59
     * @var Names
60
     */
61
    private $parent;
62
63
    /**
64
     * @var SimpleXMLElement
65
     */
66
    private $node;
67
68
    /**
69
     * @var string
70
     */
71
    private $etAl;
72
73
    /**
74
     * @var string
75
     */
76
    private $variable;
77
78
    /**
79
     * Name constructor.
80
     *
81
     * @param  SimpleXMLElement $node
82
     * @param  Names            $parent
83
     * @throws InvalidStylesheetException
84
     */
85 117
    public function __construct(SimpleXMLElement $node, Names $parent)
86
    {
87 117
        $this->node = $node;
88 117
        $this->parent = $parent;
89
90 117
        $this->nameParts = [];
91
92 117
        foreach ($node->children() as $child) {
93 3
            switch ($child->getName()) {
94 3
                case "name-part":
95
                    /** @var NamePart $namePart */
96 3
                    $namePart = Factory::create($child, $this);
97 3
                    $this->nameParts[$namePart->getName()] = $namePart;
98
            }
99
        }
100
101 117
        foreach ($node->attributes() as $attribute) {
102 100
            switch ($attribute->getName()) {
103 100
                case 'form':
104 61
                    $this->form = (string) $attribute;
105 100
                    break;
106
            }
107
        }
108
109 117
        $this->initFormattingAttributes($node);
110 117
        $this->initAffixesAttributes($node);
111 117
        $this->initDelimiterAttributes($node);
112 117
    }
113
114
    /**
115
     * @param  stdClass     $data
116
     * @param  string       $var
117
     * @param  integer|null $citationNumber
118
     * @return string
119
     * @throws CiteProcException
120
     */
121 104
    public function render($data, $var, $citationNumber = null)
122
    {
123 104
        $this->variable = $var;
124 104
        $name = $data->{$var};
125 104
        if (!$this->attributesInitialized) {
126 104
            $this->initInheritableNameAttributes($this->node);
127
        }
128 104
        if ("text" === $this->and) {
129 23
            $this->and = CiteProc::getContext()->getLocale()->filter('terms', 'and')->single;
130 91
        } elseif ('symbol' === $this->and) {
131 29
            $this->and = '&#38;';
132
        }
133
134 104
        $resultNames = $this->handleSubsequentAuthorSubstitution($name, $citationNumber);
135
136 104
        if (empty($resultNames)) {
137 2
            return CiteProc::getContext()->getCitationData()->getSubsequentAuthorSubstitute();
138
        }
139
140 104
        $resultNames = $this->prepareAbbreviation($resultNames);
141
142
        /* When set to “true” (the default is “false”), name lists truncated by et-al abbreviation are followed by
143
        the name delimiter, the ellipsis character, and the last name of the original name list. This is only
144
        possible when the original name list has at least two more names than the truncated name list (for this
145
        the value of et-al-use-first/et-al-subsequent-min must be at least 2 less than the value of
146
        et-al-min/et-al-subsequent-use-first). */
147 104
        if ($this->etAlUseLast) {
148 4
            $this->and = "…"; // set "and"
149 4
            $this->etAl = null; //reset $etAl;
150
        }
151
152
        /* add "and" */
153 104
        $this->addAnd($resultNames);
154
155 104
        $text = $this->renderDelimiterPrecedesLast($resultNames);
156
157 104
        if (empty($text)) {
158 65
            $text = implode($this->delimiter, $resultNames);
159
        }
160
161 104
        $text = $this->appendEtAl($name, $text, $resultNames);
162
163
        /* A third value, “count”, returns the total number of names that would otherwise be rendered by the use of the
164
        cs:names element (taking into account the effects of et-al abbreviation and editor/translator collapsing),
165
        which allows for advanced sorting. */
166 104
        if ($this->form == 'count') {
167 6
            return (int) count($resultNames);
168
        }
169
170 99
        return $text;
171
    }
172
173
    /**
174
     * @param  stdClass $nameItem
175
     * @param  int      $rank
176
     * @return string
177
     * @throws CiteProcException
178
     */
179 104
    private function formatName($nameItem, $rank)
180
    {
181 104
        $nameObj = $this->cloneNamePOSC($nameItem);
182
183 104
        $useInitials = $this->initialize && !is_null($this->initializeWith) && $this->initializeWith !== false;
184 104
        if ($useInitials && isset($nameItem->given)) {
185 33
            $nameObj->given = StringHelper::initializeBySpaceOrHyphen($nameItem->given, $this->initializeWith);
186
        }
187
188 104
        $renderedResult = $this->getNamesString($nameObj, $rank);
189 104
        CiteProcHelper::applyAdditionMarkupFunction($nameItem, $this->parent->getVariables()[0], $renderedResult);
190 104
        return trim($renderedResult);
191
    }
192
193
    /**
194
     * @param  stdClass $name
195
     * @param  int      $rank
196
     * @return string
197
     * @throws CiteProcException
198
     */
199 104
    private function getNamesString($name, $rank)
200
    {
201 104
        $text = "";
202
203 104
        if (!isset($name->family)) {
204
            return $text;
205
        }
206
207 104
        $text = $this->nameOrder($name, $rank);
208
209
        //contains nbsp prefixed by normal space or followed by normal space?
210 104
        $text = htmlentities($text);
211 104
        if (strpos($text, " &nbsp;") !== false || strpos($text, "&nbsp; ") !== false) {
212
            $text = preg_replace("/[\s]+/", "", $text); //remove normal spaces
213
            return preg_replace("/&nbsp;+/", " ", $text);
214
        }
215 104
        $text = html_entity_decode(preg_replace("/[\s]+/", " ", $text));
216 104
        return $this->format(trim($text));
217
    }
218
219
    /**
220
     * @param  stdClass $name
221
     * @return stdClass
222
     */
223 104
    private function cloneNamePOSC($name)
224
    {
225 104
        $nameObj = new stdClass();
226 104
        if (isset($name->family)) {
227 104
            $nameObj->family = $name->family;
228
        }
229 104
        if (isset($name->given)) {
230 102
            $nameObj->given = $name->given;
231
        }
232 104
        if (isset($name->{'non-dropping-particle'})) {
233 8
            $nameObj->{'non-dropping-particle'} = $name->{'non-dropping-particle'};
234
        }
235 104
        if (isset($name->{'dropping-particle'})) {
236 8
            $nameObj->{'dropping-particle'} = $name->{'dropping-particle'};
237
        }
238 104
        if (isset($name->{'suffix'})) {
239 17
            $nameObj->{'suffix'} = $name->{'suffix'};
240
        }
241 104
        return $nameObj;
242
    }
243
244
    /**
245
     * @param  $data
246
     * @param  $text
247
     * @param  $resultNames
248
     * @return string
249
     */
250 104
    protected function appendEtAl($data, $text, $resultNames)
251
    {
252
        //append et al abbreviation
253 104
        if (count($data) > 1
254 104
            && !empty($resultNames)
255 104
            && !empty($this->etAl)
256 104
            && !empty($this->etAlMin)
257 104
            && !empty($this->etAlUseFirst)
258 104
            && count($data) != count($resultNames)
259
        ) {
260
            /* By default, when a name list is truncated to a single name, the name and the “et-al” (or “and others”)
261
            term are separated by a space (e.g. “Doe et al.”). When a name list is truncated to two or more names, the
262
            name delimiter is used (e.g. “Doe, Smith, et al.”). This behavior can be changed with the
263
            delimiter-precedes-et-al attribute. */
264
265 14
            switch ($this->delimiterPrecedesEtAl) {
266 14
                case 'never':
267 5
                    $text = $text . " " . $this->etAl;
268 5
                    break;
269 9
                case 'always':
270 1
                    $text = $text . $this->delimiter . $this->etAl;
271 1
                    break;
272 9
                case 'contextual':
273
                default:
274 9
                    if (count($resultNames) === 1) {
275 5
                        $text .= " " . $this->etAl;
276
                    } else {
277 4
                        $text .= $this->delimiter . $this->etAl;
278
                    }
279
            }
280
        }
281 104
        return $text;
282
    }
283
284
    /**
285
     * @param  $resultNames
286
     * @return array
287
     */
288 104
    protected function prepareAbbreviation($resultNames)
289
    {
290 104
        $cnt = count($resultNames);
291
        /* Use of et-al-min and et-al-user-first enables et-al abbreviation. If the number of names in a name variable
292
        matches or exceeds the number set on et-al-min, the rendered name list is truncated after reaching the number of
293
        names set on et-al-use-first.  */
294
295 104
        if (isset($this->etAlMin) && isset($this->etAlUseFirst)) {
296 29
            if ($this->etAlMin <= $cnt) {
297 17
                if ($this->etAlUseLast && $this->etAlMin - $this->etAlUseFirst >= 2) {
298
                    /* et-al-use-last: When set to “true” (the default is “false”), name lists truncated by et-al
299
                    abbreviation are followed by the name delimiter, the ellipsis character, and the last name of the
300
                    original name list. This is only possible when the original name list has at least two more names
301
                    than the truncated name list (for this the value of et-al-use-first/et-al-subsequent-min must be at
302
                    least 2 less than the value of et-al-min/et-al-subsequent-use-first).*/
303
304 3
                    $lastName = array_pop($resultNames); //remove last Element and remember in $lastName
305
                }
306 17
                for ($i = $this->etAlUseFirst; $i < $cnt; ++$i) {
307 17
                    unset($resultNames[$i]);
308
                }
309
310 17
                $resultNames = array_values($resultNames);
311
312 17
                if (!empty($lastName)) { // append $lastName if exist
313 3
                    $resultNames[] = $lastName;
314
                }
315
316 17
                if ($this->parent->hasEtAl()) {
317 1
                    $this->etAl = $this->parent->getEtAl()->render(null);
318 1
                    return $resultNames;
319
                } else {
320 16
                    $this->etAl = CiteProc::getContext()->getLocale()->filter('terms', 'et-al')->single;
321 16
                    return $resultNames;
322
                }
323
            }
324 20
            return $resultNames;
325
        }
326 81
        return $resultNames;
327
    }
328
329
    /**
330
     * @param  $data
331
     * @param  stdClass $preceding
332
     * @return array
333
     * @throws CiteProcException
334
     */
335 3
    protected function renderSubsequentSubstitution($data, $preceding)
336
    {
337 3
        $resultNames = [];
338 3
        $subsequentSubstitution = CiteProc::getContext()->getCitationData()->getSubsequentAuthorSubstitute();
339 3
        $subsequentSubstitutionRule = CiteProc::getContext()->getCitationData()->getSubsequentAuthorSubstituteRule();
340
341
        /**
342
         * @var string $type
343
         * @var stdClass $name
344
         */
345 3
        foreach ($data as $rank => $name) {
346
            switch ($subsequentSubstitutionRule) {
347
                /*
348
                 * “partial-each” - when one or more rendered names in the name variable match those in the
349
                 * preceding bibliographic entry, the value of subsequent-author-substitute substitutes for each
350
                 * matching name. Matching starts with the first name, and continues up to the first mismatch.
351
                 */
352 3
                case SubsequentAuthorSubstituteRule::PARTIAL_EACH:
353 1
                    if (NameHelper::precedingHasAuthor($preceding, $name)) {
354 1
                        $resultNames[] = $subsequentSubstitution;
355
                    } else {
356 1
                        $resultNames[] = $this->formatName($name, $rank);
357
                    }
358 1
                    break;
359
360
                /*
361
                 * “partial-first” - as “partial-each”, but substitution is limited to the first name of the name
362
                 * variable.
363
                 */
364 2
                case SubsequentAuthorSubstituteRule::PARTIAL_FIRST:
365 1
                    if ($rank === 0) {
366 1
                        if ($preceding->author[0]->family === $name->family) {
367 1
                            $resultNames[] = $subsequentSubstitution;
368
                        } else {
369 1
                            $resultNames[] = $this->formatName($name, $rank);
370
                        }
371
                    } else {
372 1
                        $resultNames[] = $this->formatName($name, $rank);
373
                    }
374 1
                    break;
375
376
                 /*
377
                  * “complete-each” - requires a complete match like “complete-all”, but now the value of
378
                  * subsequent-author-substitute substitutes for each rendered name.
379
                  */
380 1
                case SubsequentAuthorSubstituteRule::COMPLETE_EACH:
381
                    try {
382 1
                        if (NameHelper::identicalAuthors($preceding, $data)) {
383 1
                            $resultNames[] = $subsequentSubstitution;
384
                        } else {
385 1
                            $resultNames[] = $this->formatName($name, $rank);
386
                        }
387
                    } catch (CiteProcException $e) {
388
                        $resultNames[] = $this->formatName($name, $rank);
389
                    }
390 3
                    break;
391
            }
392
        }
393 3
        return $resultNames;
394
    }
395
396
    /**
397
     * @param  array $data
398
     * @param  int   $citationNumber
399
     * @return array
400
     * @throws CiteProcException
401
     */
402 104
    private function handleSubsequentAuthorSubstitution($data, $citationNumber)
403
    {
404 104
        $hasPreceding = CiteProc::getContext()->getCitationData()->hasKey($citationNumber - 1);
405 104
        $subsequentSubstitution = CiteProc::getContext()->getCitationData()->getSubsequentAuthorSubstitute();
406 104
        $subsequentSubstitutionRule = CiteProc::getContext()->getCitationData()->getSubsequentAuthorSubstituteRule();
407 104
        $preceding = CiteProc::getContext()->getCitationData()->get($citationNumber - 1);
408
409 104
        if ($hasPreceding && !is_null($subsequentSubstitution) && !empty($subsequentSubstitutionRule)) {
410
            /**
411
             * @var stdClass $preceding
412
             */
413 8
            if ($subsequentSubstitutionRule == SubsequentAuthorSubstituteRule::COMPLETE_ALL) {
0 ignored issues
show
introduced by
The condition $subsequentSubstitutionR...ituteRule::COMPLETE_ALL is always false.
Loading history...
414
                try {
415 5
                    if (NameHelper::identicalAuthors($preceding, $data)) {
416 2
                        return [];
417
                    } else {
418 4
                        $resultNames = $this->getFormattedNames($data);
419
                    }
420 1
                } catch (CiteProcException $e) {
421 5
                    $resultNames = $this->getFormattedNames($data);
422
                }
423
            } else {
424 8
                $resultNames = $this->renderSubsequentSubstitution($data, $preceding);
425
            }
426
        } else {
427 104
            $resultNames = $this->getFormattedNames($data);
428
        }
429 104
        return $resultNames;
430
    }
431
432
433
    /**
434
     * @param  array $data
435
     * @return array
436
     * @throws CiteProcException
437
     */
438 104
    protected function getFormattedNames($data)
439
    {
440 104
        $resultNames = [];
441 104
        foreach ($data as $rank => $name) {
442 104
            $formatted = $this->formatName($name, $rank);
443 104
            $resultNames[] = NameHelper::addExtendedMarkup($this->variable, $name, $formatted);
444
        }
445 104
        return $resultNames;
446
    }
447
448
    /**
449
     * @param  $resultNames
450
     * @return string
451
     */
452 15
    protected function renderDelimiterPrecedesLastNever($resultNames)
453
    {
454 15
        $text = "";
455 15
        if (!$this->etAlUseLast) {
456 13
            if (count($resultNames) === 1) {
457 10
                $text = $resultNames[0];
458 10
            } elseif (count($resultNames) === 2) {
459 8
                $text = implode(" ", $resultNames);
460
            } else { // >2
461 7
                $lastName = array_pop($resultNames);
462 7
                $text = implode($this->delimiter, $resultNames) . " " . $lastName;
463
            }
464
        }
465 15
        return $text;
466
    }
467
468
    /**
469
     * @param  $resultNames
470
     * @return string
471
     */
472 14
    protected function renderDelimiterPrecedesLastContextual($resultNames)
473
    {
474 14
        if (count($resultNames) === 1) {
475 9
            $text = $resultNames[0];
476 6
        } elseif (count($resultNames) === 2) {
477 5
            $text = implode(" ", $resultNames);
478
        } else {
479 1
            $text = implode($this->delimiter, $resultNames);
480
        }
481 14
        return $text;
482
    }
483
484
    /**
485
     * @param $resultNames
486
     */
487 104
    protected function addAnd(&$resultNames)
488
    {
489 104
        $count = count($resultNames);
490 104
        if (!empty($this->and) && $count > 1 && empty($this->etAl)) {
491 29
            $new = $this->and . ' ' . end($resultNames); // add and-prefix of the last name if "and" is defined
492
            // set prefixed last name at the last position of $resultNames array
493 29
            $resultNames[count($resultNames) - 1] = $new;
494
        }
495 104
    }
496
497
    /**
498
     * @param  $resultNames
499
     * @return array|string
500
     */
501 104
    protected function renderDelimiterPrecedesLast($resultNames)
502
    {
503 104
        $text = "";
504 104
        if (!empty($this->and) && empty($this->etAl)) {
505 50
            switch ($this->delimiterPrecedesLast) {
506 50
                case 'after-inverted-name':
507
                    //TODO: implement
508
                    break;
509 50
                case 'always':
510 24
                    $text = implode($this->delimiter, $resultNames);
511 24
                    break;
512 29
                case 'never':
513 15
                    $text = $this->renderDelimiterPrecedesLastNever($resultNames);
514 15
                    break;
515 14
                case 'contextual':
516
                default:
517 14
                    $text = $this->renderDelimiterPrecedesLastContextual($resultNames);
518
            }
519
        }
520 104
        return $text;
521
    }
522
523
524
    /**
525
     * @param stdClass $data
526
     * @param integer  $rank
527
     *
528
     * @return string
529
     * @throws CiteProcException
530
     */
531 104
    private function nameOrder($data, $rank)
532
    {
533 104
        $nameAsSortOrder = (($this->nameAsSortOrder === "first" && $rank === 0) || $this->nameAsSortOrder === "all");
534 104
        $demoteNonDroppingParticle = CiteProc::getContext()->getGlobalOptions()->getDemoteNonDroppingParticles();
535 104
        $normalizedName = NameHelper::normalizeName($data);
536 104
        if (StringHelper::isLatinString($normalizedName) || StringHelper::isCyrillicString($normalizedName)) {
537 103
            if ($this->form === "long"
538 103
                && $nameAsSortOrder
539 44
                && ((string) $demoteNonDroppingParticle === DemoteNonDroppingParticle::NEVER
540 103
                || (string) $demoteNonDroppingParticle === DemoteNonDroppingParticle::SORT_ONLY)
541
            ) {
542
                // [La] [Fontaine], [Jean] [de], [III]
543 29
                NameHelper::prependParticleTo($data, "family", "non-dropping-particle");
544 29
                NameHelper::appendParticleTo($data, "given", "dropping-particle");
545
546 29
                list($family, $given) = $this->renderNameParts($data);
547
548 29
                $text = $family . (!empty($given) ? $this->sortSeparator . $given : "");
549 29
                $text .= !empty($data->suffix) ? $this->sortSeparator . $data->suffix : "";
550 79
            } elseif ($this->form === "long"
551 79
                && $nameAsSortOrder
552 15
                && (is_null($demoteNonDroppingParticle)
553 79
                || (string) $demoteNonDroppingParticle === DemoteNonDroppingParticle::DISPLAY_AND_SORT)
554
            ) {
555
                // [Fontaine], [Jean] [de] [La], [III]
556 15
                NameHelper::appendParticleTo($data, "given", "dropping-particle");
557 15
                NameHelper::appendParticleTo($data, "given", "non-dropping-particle");
558 15
                list($family, $given) = $this->renderNameParts($data);
559 15
                $text = $family;
560 15
                $text .= !empty($given) ? $this->sortSeparator . $given : "";
561 15
                $text .= !empty($data->suffix) ? $this->sortSeparator . $data->suffix : "";
562 71
            } elseif ($this->form === "long" && $nameAsSortOrder && empty($demoteNonDroppingParticle)) {
563
                list($family, $given) = $this->renderNameParts($data);
564
                $text = $family;
565
                $text .= !empty($given) ? $this->delimiter . $given : "";
566
                $text .= !empty($data->suffix) ? $this->sortSeparator . $data->suffix : "";
567 71
            } elseif ($this->form === "short") {
568
                // [La] [Fontaine]
569 25
                NameHelper::prependParticleTo($data, "family", "non-dropping-particle");
570 25
                $text = $data->family;
571
            } else {// form "long" (default)
572
                // [Jean] [de] [La] [Fontaine] [III]
573 48
                NameHelper::prependParticleTo($data, "family", "non-dropping-particle");
574 48
                NameHelper::prependParticleTo($data, "family", "dropping-particle");
575 48
                NameHelper::appendParticleTo($data, "family", "suffix");
576 48
                list($family, $given) = $this->renderNameParts($data);
577 103
                $text = !empty($given) ? $given . " " . $family : $family;
578
            }
579 1
        } elseif (StringHelper::isAsianString(NameHelper::normalizeName($data))) {
580 1
            $text = $this->form === "long" ? $data->family . $data->given : $data->family;
581
        } else {
582
            $text = $this->form === "long" ? $data->family . " " . $data->given : $data->family;
583
        }
584 104
        return $text;
585
    }
586
587
    /**
588
     * @param  $data
589
     * @return array
590
     */
591 83
    private function renderNameParts($data)
592
    {
593 83
        $given = "";
594 83
        if (array_key_exists("family", $this->nameParts)) {
595 2
            $family = $this->nameParts["family"]->render($data);
596
        } else {
597 81
            $family = $data->family;
598
        }
599 83
        if (isset($data->given)) {
600 81
            if (array_key_exists("given", $this->nameParts)) {
601 2
                $given = $this->nameParts["given"]->render($data);
602
            } else {
603 79
                $given = $data->given;
604
            }
605
        }
606 83
        return [$family, $given];
607
    }
608
609
610
    /**
611
     * @return string
612
     */
613 6
    public function getForm()
614
    {
615 6
        return $this->form;
616
    }
617
618
    /**
619
     * @return string
620
     */
621
    public function isNameAsSortOrder()
622
    {
623
        return $this->nameAsSortOrder;
624
    }
625
626
    /**
627
     * @return string
628
     */
629
    public function getDelimiter()
630
    {
631
        return $this->delimiter;
632
    }
633
634
    /**
635
     * @param mixed $delimiter
636
     */
637 104
    public function setDelimiter($delimiter)
638
    {
639 104
        $this->delimiter = $delimiter;
640 104
    }
641
642
    /**
643
     * @return Names
644
     */
645
    public function getParent()
646
    {
647
        return $this->parent;
648
    }
649
650
    public function setParent($parent)
651
    {
652
        $this->parent = $parent;
653
    }
654
}
655