Passed
Push — new-api ( 4bfe18...7ec1cc )
by Sebastian
05:06
created

Substitute::setChildren()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 1
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
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\InvalidStylesheetException;
14
use Seboettg\CiteProc\Rendering\Observer\RenderingObserver;
15
use Seboettg\CiteProc\Rendering\Observer\RenderingObserverTrait;
16
use Seboettg\CiteProc\Rendering\Observer\StateChangedEvent;
17
use Seboettg\CiteProc\Rendering\Rendering;
18
use Seboettg\CiteProc\Config\RenderingState;
19
use Seboettg\CiteProc\Util\Factory;
20
use Seboettg\Collection\ArrayList\ArrayListInterface;
21
use Seboettg\Collection\ArrayList as ArrayList;
22
use SimpleXMLElement;
23
use stdClass;
24
25
/**
26
 * Class Substitute
27
 * The optional cs:substitute element, which must be included as the last child element of cs:names, adds substitution
28
 * in case the name variables specified in the parent cs:names element are empty. The substitutions are specified as
29
 * child elements of cs:substitute, and must consist of one or more rendering elements (with the exception of
30
 * cs:layout).
31
 *
32
 * A shorthand version of cs:names without child elements, which inherits the attributes values set on the cs:name and
33
 * cs:et-al child elements of the original cs:names element, may also be used.
34
 *
35
 * If cs:substitute contains multiple child elements, the first element to return a non-empty result is used for
36
 * substitution. Substituted variables are suppressed in the rest of the output to prevent duplication. An example,
37
 * where an empty “author” name variable is substituted by the “editor” name variable, or, when no editors exist, by
38
 * the “title” macro:
39
 *   <macro name="author">
40
 *      <names variable="author">
41
 *        <substitute>
42
 *          <names variable="editor"/>
43
 *          <text macro="title"/>
44
 *        </substitute>
45
 *      </names>
46
 *   </macro>
47
 * @package Seboettg\CiteProc\Rendering\Name
48
 *
49
 * @author Sebastian Böttger <[email protected]>
50
 */
51
class Substitute implements Rendering, RenderingObserver
52
{
53
    use RenderingObserverTrait;
54
55
    /** @var ArrayListInterface  */
56
    private $children;
57
58
    /** @var Names */
59
    private $parent;
0 ignored issues
show
introduced by
The private property $parent is not used, and could be removed.
Loading history...
60
61
    /**
62
     * @param SimpleXMLElement $node
63
     * @param Names $parent
64
     * @return Substitute
65
     * @throws InvalidStylesheetException
66
     */
67 55
    public static function factory(SimpleXMLElement $node, Names $parent): Substitute
68
    {
69 55
        $substitute = new Substitute();
70 55
        $children = new ArrayList();
71 55
        foreach ($node->children() as $child) {
72 55
            if ($child->getName() === "names") {
73
                /** @var Names $names */
74 54
                $names = Factory::create($child, $substitute);
75
76
                /* A shorthand version of cs:names without child elements, which inherits the attributes values set on
77
                the cs:name and cs:et-al child elements of the original cs:names element, may also be used. */
78 54
                if (!$names->hasEtAl()) {
79
                    // inherit et-al
80 54
                    if ($parent->hasEtAl()) {
81 12
                        $names->setEtAl($parent->getEtAl());
82
                    }
83
                }
84 54
                if (!$names->hasName()) {
85
                    // inherit name
86 54
                    if ($parent->hasName()) {
87 54
                        $names->setName($parent->getName());
88
                    }
89
                }
90
                // inherit label
91 54
                if (!$names->hasLabel() && $parent->hasLabel()) {
92 45
                    $names->setLabel($parent->getLabel());
93
                }
94 54
                $children->append($names);
95
            } else {
96 37
                $object = Factory::create($child, $substitute);
97 55
                $children->append($object);
98
            }
99
        }
100 55
        $substitute->setChildren($children);
101 55
        CiteProc::getContext()->addObserver($substitute);
102 55
        return $substitute;
103
    }
104
105
    /**
106
     * Substitute constructor.
107
     */
108 55
    public function __construct()
109
    {
110 55
        $this->children = new ArrayList();
111 55
        $this->initObserver();
112 55
    }
113
114
    /**
115
     * @param stdClass $data
116
     * @param int|null $citationNumber
117
     * @return string
118
     */
119 21
    public function render($data, $citationNumber = null)
120
    {
121 21
        $ret = [];
122 21
        if (!$this->state->equals(RenderingState::SORTING())) {
123 21
            $this->notifyAll(new StateChangedEvent(RenderingState::SUBSTITUTION()));
124
        }
125
126
        /** @var Rendering $child */
127 21
        foreach ($this->children as $child) {
128
            /* If cs:substitute contains multiple child elements, the first element to return a
129
            non-empty result is used for substitution. */
130 21
            $res = $child->render($data, $citationNumber);
131 21
            if (!empty($res)) {
132 17
                $ret[] = $res;
133 21
                break;
134
            }
135
        }
136 21
        if ($this->state->equals(RenderingState::SUBSTITUTION())) {
137 21
            $this->notifyAll(new StateChangedEvent(RenderingState::RENDERING()));
138
        }
139 21
        return implode("", $ret);
140
    }
141
142 55
    private function setChildren(ArrayListInterface $children): void
143
    {
144 55
        $this->children = $children;
145 55
    }
146
}
147