Completed
Push — version2.0 ( af5a57...2f739c )
by Sebastian
06:52
created

Names::getVariables()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
rs 10
c 0
b 0
f 0
1
<?php
2
3
namespace Seboettg\CiteProc\Rendering\Name;
4
5
use Seboettg\CiteProc\Rendering\Label;
6
use Seboettg\CiteProc\Rendering\RenderingInterface;
7
use Seboettg\CiteProc\Styles\AffixesTrait;
8
use Seboettg\CiteProc\Styles\DelimiterTrait;
9
use Seboettg\CiteProc\Styles\FormattingTrait;
10
use Seboettg\CiteProc\Util\Factory;
11
use Seboettg\Collection\ArrayList;
12
13
14
/**
15
 * Class Group
16
 * @package Seboettg\CiteProc\Rendering
17
 *
18
 * @author Sebastian Böttger <[email protected]>
19
 */
20
class Names implements RenderingInterface
21
{
22
    use DelimiterTrait;
23
    use AffixesTrait;
24
    use FormattingTrait;
25
26
    /**
27
     * Variables (selected with the required variable attribute), each of which can contain multiple names (e.g. the
28
     * “author” variable contains all the author names of the cited item). If multiple variables are selected
29
     * (separated by single spaces, see example below), each variable is independently rendered in the order specified.
30
     *
31
     * @var ArrayList
32
     */
33
    private $variables;
34
35
    /**
36
     * The Name element, an optional child element of Names, can be used to describe the formatting of individual
37
     * names, and the separation of names within a name variable.
38
     *
39
     * @var Name
40
     */
41
    private $name;
42
43
    /**
44
     * The optional Label element must be included after the Name and EtAl elements, but before
45
     * the Substitute element. When used as a child element of Names, Label does not carry the variable
46
     * attribute; it uses the variable(s) set on the parent Names element instead.
47
     *
48
     * @var Label
49
     */
50
    private $label;
51
52
    /**
53
     * The optional Substitute element, which must be included as the last child element of Names, adds
54
     * substitution in case the name variables specified in the parent cs:names element are empty. The substitutions
55
     * are specified as child elements of Substitute, and must consist of one or more rendering elements (with the
56
     * exception of Layout). A shorthand version of Names without child elements, which inherits the attributes
57
     * values set on the cs:name and EtAl child elements of the original Names element, may also be used. If
58
     * Substitute contains multiple child elements, the first element to return a non-empty result is used for
59
     * substitution. Substituted variables are suppressed in the rest of the output to prevent duplication. An example,
60
     * where an empty “author” name variable is substituted by the “editor” name variable, or, when no editors exist,
61
     * by the “title” macro:
62
     *
63
     * <macro name="author">
64
     *     <names variable="author">
65
     *         <substitute>
66
     *             <names variable="editor"/>
67
     *             <text macro="title"/>
68
     *         </substitute>
69
     *     </names>
70
     * </macro>
71
     *
72
     * @var Substitute
73
     */
74
    private $substitute;
75
76
    /**
77
     * Et-al abbreviation, controlled via the et-al-... attributes (see Name), can be further customized with the
78
     * optional cs:et-al element, which must follow the cs:name element (if present). The term attribute may be set to
79
     * either “et-al” (the default) or to “and others” to use either term. The formatting attributes may also be used,
80
     * for example to italicize the “et-al” term:
81
     *
82
     * @var EtAl
83
     */
84
    private $etAl;
85
86
    /**
87
     * The delimiter attribute may be set on cs:names to separate the names of the different name variables (e.g. the
88
     * semicolon in “Doe, Smith (editors); Johnson (translator)”).
89
     *
90
     * @var string
91
     */
92
    private $delimiter = ", ";
93
94
    /**
95
     * Names constructor.
96
     * @param \SimpleXMLElement $node
97
     */
98
    public function __construct(\SimpleXMLElement $node)
99
    {
100
101
        /** @var \SimpleXMLElement $child */
102
        foreach ($node->children() as $child) {
103
104
            switch ($child->getName()) {
105
                case "name":
106
                    $this->name = Factory::create($child, $this);
107
                    break;
108
                case "label":
109
                    $this->label = Factory::create($child);
110
                    break;
111
                case "substitute":
112
                    $this->substitute = Factory::create($child);
113
                    break;
114
                case "et-al":
115
                    $this->etAl = Factory::create($child);
116
            }
117
        }
118
119
        /** @var \SimpleXMLElement $attribute */
120
        foreach ($node->attributes() as $attribute) {
121
            if ("variable" === $attribute->getName()) {
122
                $this->variables = new ArrayList(explode(" ", (string)$attribute));
123
                break;
124
            }
125
        }
126
127
        $this->initDelimiterAttributes($node);
128
        $this->initAffixesAttributes($node);
129
        $this->initFormattingAttributes($node);
130
    }
131
132
    /**
133
     * This outputs the contents of one or more name variables (selected with the required variable attribute), each
134
     * of which can contain multiple names (e.g. the “author” variable contains all the author names of the cited item).
135
     * If multiple variables are selected (separated by single spaces), each variable is independently rendered in the
136
     * order specified, with one exception: when the selection consists of “editor” and “translator”, and when the
137
     * contents of these two name variables is identical, then the contents of only one name variable is rendered. In
138
     * addition, the “editortranslator” term is used if the Names element contains a Label element, replacing the
139
     * default “editor” and “translator” terms (e.g. resulting in “Doe (editor & translator)”).
140
     *
141
     * @param $data
142
     * @return string
143
     */
144
    public function render($data)
145
    {
146
        $str = "";
147
        $matches = [];
148
149
        /* when the selection consists of “editor” and “translator”, and when the contents of these two name variables
150
        is identical, then the contents of only one name variable is rendered. In addition, the “editortranslator”
151
        term is used if the cs:names element contains a cs:label element, replacing the default “editor” and
152
        “translator” terms (e.g. resulting in “Doe (editor & translator)”) */
153
        if ($this->variables->hasValue("editor") && $this->variables->hasValue("translator")) {
154
            if (isset($data->editor) && isset($data->translator)) {
155
                if (isset($name)) {
0 ignored issues
show
Bug introduced by
The variable $name seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
156
                    $str .= $this->name->render($data->editor);
157
                } else {
158
                    $arr = [];
159
                    foreach ($data->editor as $editor) {
160
                        $arr[] = $this->format($editor->family . ", " . $editor->given);
161
                    }
162
                    $str .= implode($this->delimiter, $arr);
163
                }
164
                if (isset($this->label)) {
165
                    $this->label->setVariable("editortranslator");
166
                    $str .= $this->label->render("");
167
                }
168
                $vars = $this->variables->toArray();
169
                $vars = array_filter($vars, function($value) {
170
                    return !($value === "editor" || $value === "translator");
171
                });
172
                $this->variables->setArray($vars);
173
            }
174
        }
175
176
        foreach ($this->variables as $variable) {
177
            if (isset($data->{$variable}) && (!empty($data->{$variable}))) {
178
                $matches[] = $variable;
179
            }
180
        }
181
182
183
184
        $results = [];
185
        foreach ($matches as $var) {
186
187
            if (!empty($data->{$var})) {
188
                if (!empty($this->name)) {
189
                    $name = $this->name->render($data->{$var});
190
                    if (!empty($this->label)) {
191
                        $this->label->setVariable($var);
192
                        $name .= $this->label->render($data);
193
                    }
194
                    $results[] = $this->format($name);
195
                } else {
196
                    foreach ($data->{$var} as $name) {
197
                        $results[] = $name->given . " " . $name->family;
198
                    }
199
                }
200
            }
201
        }
202
        $str  .= implode($this->delimiter, $results);
203
        return $this->addAffixes($str);
204
    }
205
206
    public function hasEtAl()
207
    {
208
        return !empty($this->etAl);
209
    }
210
211
    public function getEtAl()
212
    {
213
        return $this->etAl;
214
    }
215
216
    public function getDelimiter()
217
    {
218
        return $this->delimiter;
219
    }
220
221
    public function getVariables()
222
    {
223
        return $this->variables;
224
    }
225
}