Passed
Push — master ( 279db1...661b73 )
by Sebastian
18:02 queued 11:37
created

Names::setEtAl()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 4
cp 0
crap 2
rs 10
c 0
b 0
f 0
1
<?php
2
/*
1 ignored issue
show
Coding Style introduced by
You must use "/**" style comments for a file comment
Loading history...
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\Rendering\Label;
17
use Seboettg\CiteProc\Rendering\Rendering;
18
use Seboettg\CiteProc\RenderingState;
19
use Seboettg\CiteProc\Style\InheritableNameAttributesTrait;
20
use Seboettg\CiteProc\Styles\AffixesTrait;
21
use Seboettg\CiteProc\Styles\DelimiterTrait;
22
use Seboettg\CiteProc\Styles\FormattingTrait;
23
use Seboettg\CiteProc\Util\Factory;
24
use Seboettg\CiteProc\Util\NameHelper;
25
use Seboettg\Collection\ArrayList;
26
use SimpleXMLElement;
27
use stdClass;
28
29
/**
30
 * Class Names
31
 * @package Seboettg\CiteProc\Rendering\Name
1 ignored issue
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
32
 *
33
 * @author Sebastian Böttger <[email protected]>
34
 */
3 ignored issues
show
Coding Style introduced by
Missing @category tag in class comment
Loading history...
Coding Style introduced by
Missing @license tag in class comment
Loading history...
Coding Style introduced by
Missing @link tag in class comment
Loading history...
35
class Names implements Rendering, HasParent
36
{
37
    use DelimiterTrait,
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\Names.
Loading history...
38
        AffixesTrait,
39
        FormattingTrait,
40
        InheritableNameAttributesTrait;
41
42
    /**
43
     * Variables (selected with the required variable attribute), each of which can contain multiple names (e.g. the
44
     * “author” variable contains all the author names of the cited item). If multiple variables are selected
45
     * (separated by single spaces, see example below), each variable is independently rendered in the order specified.
46
     *
47
     * @var ArrayList
48
     */
49
    private $variables;
0 ignored issues
show
Coding Style introduced by
Private member variable "variables" must be prefixed with an underscore
Loading history...
50
51
    /**
52
     * The Name element, an optional child element of Names, can be used to describe the formatting of individual
53
     * names, and the separation of names within a name variable.
54
     *
55
     * @var Name
56
     */
57
    private $name;
0 ignored issues
show
Coding Style introduced by
Private member variable "name" must be prefixed with an underscore
Loading history...
58
59
    /**
60
     * The optional Label element must be included after the Name and EtAl elements, but before
61
     * the Substitute element. When used as a child element of Names, Label does not carry the variable
62
     * attribute; it uses the variable(s) set on the parent Names element instead.
63
     *
64
     * @var Label
65
     */
66
    private $label;
0 ignored issues
show
Coding Style introduced by
Private member variable "label" must be prefixed with an underscore
Loading history...
67
68
    /**
69
     * The optional Substitute element, which must be included as the last child element of Names, adds
70
     * substitution in case the name variables specified in the parent cs:names element are empty. The substitutions
71
     * are specified as child elements of Substitute, and must consist of one or more rendering elements (with the
72
     * exception of Layout). A shorthand version of Names without child elements, which inherits the attributes
73
     * values set on the cs:name and EtAl child elements of the original Names element, may also be used. If
74
     * Substitute contains multiple child elements, the first element to return a non-empty result is used for
75
     * substitution. Substituted variables are suppressed in the rest of the output to prevent duplication. An example,
76
     * where an empty “author” name variable is substituted by the “editor” name variable, or, when no editors exist,
77
     * by the “title” macro:
78
     *
79
     * <macro name="author">
80
     *     <names variable="author">
81
     *         <substitute>
82
     *             <names variable="editor"/>
83
     *             <text macro="title"/>
84
     *         </substitute>
85
     *     </names>
86
     * </macro>
87
     *
88
     * @var Substitute
89
     */
90
    private $substitute;
0 ignored issues
show
Coding Style introduced by
Private member variable "substitute" must be prefixed with an underscore
Loading history...
91
92
    /**
93
     * Et-al abbreviation, controlled via the et-al-... attributes (see Name), can be further customized with the
94
     * optional cs:et-al element, which must follow the cs:name element (if present). The term attribute may be set to
95
     * either “et-al” (the default) or to “and others” to use either term. The formatting attributes may also be used,
96
     * for example to italicize the “et-al” term:
97
     *
98
     * @var EtAl
99
     */
100
    private $etAl;
0 ignored issues
show
Coding Style introduced by
Private member variable "etAl" must be prefixed with an underscore
Loading history...
101
102
    /**
103
     * The delimiter attribute may be set on cs:names to separate the names of the different name variables (e.g. the
104
     * semicolon in “Doe, Smith (editors); Johnson (translator)”).
105
     *
106
     * @var string
107
     */
108
    private $delimiter = ", ";
0 ignored issues
show
Coding Style introduced by
Private member variable "delimiter" must be prefixed with an underscore
Loading history...
109
110
    private $parent;
0 ignored issues
show
Coding Style introduced by
Private member variable "parent" must be prefixed with an underscore
Loading history...
111
112
    /**
0 ignored issues
show
Coding Style introduced by
Parameter $parent should have a doc-comment as per coding-style.
Loading history...
113
     * Names constructor.
114
     * @param SimpleXMLElement $node
3 ignored issues
show
Coding Style introduced by
There must be exactly one blank line before the tags in a doc comment
Loading history...
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
115
     * @param $parent
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
116
     * @throws InvalidStylesheetException
1 ignored issue
show
Coding Style introduced by
Tag @throws cannot be grouped with parameter tags in a doc comment
Loading history...
117
     */
118
    public function __construct(SimpleXMLElement $node, $parent)
119
    {
120
        $this->initInheritableNameAttributes($node);
121
        $this->parent = $parent;
122
        /** @var SimpleXMLElement $child */
3 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
123
        foreach ($node->children() as $child) {
124
125
            switch ($child->getName()) {
126
                case "name":
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
127
                    $this->name = Factory::create($child, $this);
128
                    break;
129
                case "label":
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
130
                    $this->label = Factory::create($child);
131
                    break;
132
                case "substitute":
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
133
                    $this->substitute = new Substitute($child, $this);
134
                    break;
135
                case "et-al":
0 ignored issues
show
Coding Style introduced by
Line indented incorrectly; expected 12 spaces, found 16
Loading history...
136
                    $this->etAl = Factory::create($child);
137
            }
138
        }
139
140
        /** @var SimpleXMLElement $attribute */
3 ignored issues
show
Coding Style introduced by
The open comment tag must be the only content on the line
Loading history...
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
The close comment tag must be the only content on the line
Loading history...
141
        foreach ($node->attributes() as $attribute) {
142
            if ("variable" === $attribute->getName()) {
143
                $this->variables = new ArrayList(explode(" ", (string) $attribute));
144
                break;
145
            }
146
        }
147
148
        $this->initDelimiterAttributes($node);
149
        $this->initAffixesAttributes($node);
150
        $this->initFormattingAttributes($node);
151
    }
152
153
    /**
154
     * This outputs the contents of one or more name variables (selected with the required variable attribute), each
155
     * of which can contain multiple names (e.g. the “author” variable contains all the author names of the cited item).
156
     * If multiple variables are selected (separated by single spaces), each variable is independently rendered in the
157
     * order specified, with one exception: when the selection consists of “editor” and “translator”, and when the
158
     * contents of these two name variables is identical, then the contents of only one name variable is rendered. In
159
     * addition, the “editortranslator” term is used if the Names element contains a Label element, replacing the
160
     * default “editor” and “translator” terms (e.g. resulting in “Doe (editor & translator)”).
161
     *
162
     * @param stdClass $data
2 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
163
     * @param int|null $citationNumber
2 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
164
     * @return string
1 ignored issue
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
165
     * @throws CiteProcException
1 ignored issue
show
Coding Style introduced by
Tag @throws cannot be grouped with parameter tags in a doc comment
Loading history...
166
     */
167
    public function render($data, $citationNumber = null)
168
    {
169
        $str = "";
170
171
        /* when the selection consists of “editor” and “translator”, and when the contents of these two name variables
172
        is identical, then the contents of only one name variable is rendered. In addition, the “editortranslator”
173
        term is used if the cs:names element contains a cs:label element, replacing the default “editor” and
174
        “translator” terms (e.g. resulting in “Doe (editor & translator)”) */
175
        if ($this->variables->hasValue("editor") && $this->variables->hasValue("translator")) {
176
            if (isset($data->editor) && isset($data->translator) && NameHelper::sameNames($data->editor, $data->translator)) {
177
                if (isset($this->name)) {
178
                    $str .= $this->name->render($data, 'editor');
179
                } else {
180
                    $arr = [];
181
                    foreach ($data->editor as $editor) {
182
                        $edt = $this->format($editor->family . ", " . $editor->given);
183
                        $results[] = NameHelper::addExtendedMarkup('editor', $editor, $edt);
184
                    }
185
                    $str .= implode($this->delimiter, $arr);
186
                }
187
                if (isset($this->label)) {
188
                    $this->label->setVariable("editortranslator");
189
                    $str .= $this->label->render($data);
190
                }
191
                $vars = $this->variables->toArray();
192
                $vars = array_filter($vars, function($value) {
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...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
193
                    return !($value === "editor" || $value === "translator");
194
                });
0 ignored issues
show
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...
195
                $this->variables->setArray($vars);
196
            }
197
        }
198
199
        $results = [];
200
        foreach ($this->variables as $var) {
201
202
            if (!empty($data->{$var})) {
203
                if (!empty($this->name)) {
204
                    $res = $this->name->render($data, $var, $citationNumber);
205
                    $name = $res;
206
                    if (!empty($this->label)) {
207
                        $name = $this->appendLabel($data, $var, $name);
208
                    }
209
                    //add multiple counting values
210
                    if (is_numeric($name) && $this->name->getForm() === "count") {
211
                        $results = $this->addCountValues($res, $results);
212
                    } else {
213
                        $results[] = $this->format($name);
214
                    }
215
                } else {
216
                    foreach ($data->{$var} as $name) {
217
                        $formatted = $this->format($name->given . " " . $name->family);
218
                        $results[] = NameHelper::addExtendedMarkup($var, $name, $formatted);
219
                    }
220
                }
221
                // suppress substituted variables
222
                if (CiteProc::getContext()->getRenderingState()->getValue() === RenderingState::SUBSTITUTION) {
223
                    unset($data->{$var});
224
                }
225
            } else {
226
                if (!empty($this->substitute)) {
227
                    $results[] = $this->substitute->render($data);
228
                }
229
            }
230
        }
231
        $results = $this->filterEmpty($results);
232
        $str .= implode($this->delimiter, $results);
233
        return !empty($str) ? $this->addAffixes($str) : "";
234
    }
235
236
237
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $data should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $var should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $name should have a doc-comment as per coding-style.
Loading history...
238
     * @param $data
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
239
     * @param $var
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
240
     * @param $name
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
241
     * @return string
1 ignored issue
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
242
     */
243
    private function appendLabel($data, $var, $name)
1 ignored issue
show
Coding Style introduced by
Private method name "Names::appendLabel" must be prefixed with an underscore
Loading history...
244
    {
245
        $this->label->setVariable($var);
246
        if (in_array($this->label->getForm(), ["verb", "verb-short"])) {
247
            $name = $this->label->render($data) . $name;
248
        } else {
249
            $name .= $this->label->render($data);
250
        }
251
        return $name;
252
    }
253
254
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
Coding Style introduced by
Parameter $res should have a doc-comment as per coding-style.
Loading history...
Coding Style introduced by
Parameter $results should have a doc-comment as per coding-style.
Loading history...
255
     * @param $res
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
256
     * @param $results
1 ignored issue
show
Coding Style Documentation introduced by
Missing parameter name
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
257
     * @return array
1 ignored issue
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
258
     */
259
    private function addCountValues($res, $results)
1 ignored issue
show
Coding Style introduced by
Private method name "Names::addCountValues" must be prefixed with an underscore
Loading history...
260
    {
261
        $lastElement = current($results);
262
        $key = key($results);
263
        if (!empty($lastElement)) {
264
            $lastElement += $res;
265
            $results[$key] = $lastElement;
266
        } else {
267
            $results[] = $res;
268
        }
269
        return $results;
270
    }
271
272
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
273
     * @return bool
274
     */
275
    public function hasEtAl()
276
    {
277
        return !empty($this->etAl);
278
    }
279
280
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
281
     * @return EtAl
282
     */
283
    public function getEtAl()
284
    {
285
        return $this->etAl;
286
    }
287
288
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
289
     * @param EtAl $etAl
2 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
290
     * @return $this
1 ignored issue
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
291
     */
292
    public function setEtAl(EtAl $etAl)
293
    {
294
        $this->etAl = $etAl;
295
        return $this;
296
    }
297
298
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
299
     * @return bool
300
     */
301
    public function hasName()
302
    {
303
        return !empty($this->name);
304
    }
305
306
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
307
     * @return Name
308
     */
309
    public function getName()
310
    {
311
        return $this->name;
312
    }
313
314
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
315
     * @param Name $name
2 ignored issues
show
Coding Style introduced by
Missing parameter comment
Loading history...
Coding Style introduced by
Tag value for @param tag indented incorrectly; expected 2 spaces but found 1
Loading history...
316
     * @return $this
1 ignored issue
show
Coding Style introduced by
Tag @return cannot be grouped with parameter tags in a doc comment
Loading history...
317
     */
318
    public function setName(Name $name)
319
    {
320
        $this->name = $name;
321
        return $this;
322
    }
323
324
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
325
     * @return string
326
     */
327
    public function getDelimiter()
328
    {
329
        return $this->delimiter;
330
    }
331
332
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
333
     * @return ArrayList
334
     */
335
    public function getVariables()
336
    {
337
        return $this->variables;
338
    }
339
340
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
341
     * @return bool
342
     */
343
    public function hasLabel()
344
    {
345
        return !empty($this->label);
346
    }
347
348
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
349
     * @return Label
350
     */
351
    public function getLabel()
352
    {
353
        return $this->label;
354
    }
355
356
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
357
     * @param Label $label
1 ignored issue
show
Coding Style introduced by
Missing parameter comment
Loading history...
358
     */
0 ignored issues
show
Coding Style introduced by
Missing @return tag in function comment
Loading history...
359
    public function setLabel($label)
360
    {
361
        $this->label = $label;
362
    }
363
364
    /**
1 ignored issue
show
Coding Style introduced by
Missing short description in doc comment
Loading history...
365
     * @return mixed
366
     */
367
    public function getParent()
368
    {
369
        return $this->parent;
370
    }
371
372
    private function filterEmpty(array $results)
1 ignored issue
show
Coding Style introduced by
Missing doc comment for function filterEmpty()
Loading history...
Coding Style introduced by
Private method name "Names::filterEmpty" must be prefixed with an underscore
Loading history...
373
    {
374
        return array_filter($results, function($item) {
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...
Coding Style introduced by
Expected 1 space after FUNCTION keyword; 0 found
Loading history...
375
            return !empty($item);
376
        });
0 ignored issues
show
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...
377
    }
378
379
}
380