Passed
Push — pr/75 ( f5cb9f...a14152 )
by Sebastian
03:21
created

Name::render()   B

Complexity

Conditions 8
Paths 54

Size

Total Lines 50
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 24
CRAP Score 8

Importance

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

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
610 79
        if (isset($data->given)) {
611 77
            $given = array_key_exists("given",
0 ignored issues
show
Coding Style introduced by
The opening parenthesis of a multi-line function call should be the last content on the line.
Loading history...
612 77
                $this->nameParts) ? $this->nameParts["given"]->render($data) : $data->given;
0 ignored issues
show
Coding Style introduced by
This line of the multi-line function call does not seem to be indented correctly. Expected 12 spaces, but found 16.
Loading history...
Coding Style introduced by
For multi-line function calls, the closing parenthesis should be on a new line.

If a function call spawns multiple lines, the coding standard suggests to move the closing parenthesis to a new line:

someFunctionCall(
    $firstArgument,
    $secondArgument,
    $thirdArgument
); // Closing parenthesis on a new line.
Loading history...
613
        }
614 79
        return [$family, $given];
615
    }
616
617
618
    /**
619
     * @return string
620
     */
621 5
    public function getForm()
622
    {
623 5
        return $this->form;
624
    }
625
626
    /**
627
     * @return string
628
     */
629
    public function isNameAsSortOrder()
630
    {
631
        return $this->nameAsSortOrder;
632
    }
633
634
    /**
635
     * @return string
636
     */
637
    public function getDelimiter()
638
    {
639
        return $this->delimiter;
640
    }
641
642
    /**
643
     * @param mixed $delimiter
644
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
645 97
    public function setDelimiter($delimiter)
646
    {
647 97
        $this->delimiter = $delimiter;
648 97
    }
649
650
    /**
651
     * @return Names
652
     */
653
    public function getParent()
654
    {
655
        return $this->parent;
656
    }
657
658
}
659