Passed
Push — feature/locators-issue-82 ( cd9965...0ff576 )
by Sebastian
04:35
created

Text::renderLocator()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 12
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 11
nc 2
nop 2
dl 0
loc 14
ccs 12
cts 12
cp 1
crap 2
rs 9.9
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;
11
12
use Seboettg\CiteProc\CiteProc;
13
use Seboettg\CiteProc\Exception\CiteProcException;
14
use Seboettg\CiteProc\RenderingState;
15
use Seboettg\CiteProc\Styles\AffixesTrait;
16
use Seboettg\CiteProc\Styles\ConsecutivePunctuationCharacterTrait;
17
use Seboettg\CiteProc\Styles\DisplayTrait;
18
use Seboettg\CiteProc\Styles\FormattingTrait;
19
use Seboettg\CiteProc\Styles\QuotesTrait;
20
use Seboettg\CiteProc\Styles\TextCaseTrait;
21
use Seboettg\CiteProc\Util\CiteProcHelper;
22
use Seboettg\CiteProc\Util\LocatorHelper;
23
use Seboettg\CiteProc\Util\NumberHelper;
24
use Seboettg\CiteProc\Util\PageHelper;
25
use Seboettg\CiteProc\Util\StringHelper;
26
use SimpleXMLElement;
27
use stdClass;
28
29
/**
30
 * Class Term
31
 *
32
 * @package Seboettg\CiteProc\Node\Style
33
 *
34
 * @author Sebastian Böttger <[email protected]>
35
 */
36
class Text implements Rendering
37
{
38
    use FormattingTrait,
0 ignored issues
show
Bug introduced by
The trait Seboettg\CiteProc\Styles\QuotesTrait requires the property $single which is not provided by Seboettg\CiteProc\Rendering\Text.
Loading history...
Bug introduced by
The trait Seboettg\CiteProc\Styles\AffixesTrait requires the property $single which is not provided by Seboettg\CiteProc\Rendering\Text.
Loading history...
39
        AffixesTrait,
40
        TextCaseTrait,
41
        DisplayTrait,
42
        ConsecutivePunctuationCharacterTrait,
43
        QuotesTrait;
44
45
    /**
46
     * @var string
47
     */
48
    private $toRenderType;
49
50
    /**
51
     * @var string
52
     */
53
    private $toRenderTypeValue;
54
55
    /**
56
     * @var string
57
     */
58
    private $form = "long";
59
60
    /**
61
     * Text constructor.
62
     *
63
     * @param SimpleXMLElement $node
64
     */
65 104
    public function __construct(SimpleXMLElement $node)
66
    {
67 104
        foreach ($node->attributes() as $attribute) {
68 104
            $name = $attribute->getName();
69 104
            if (in_array($name, ['value', 'variable', 'macro', 'term'])) {
70 104
                $this->toRenderType = $name;
71 104
                $this->toRenderTypeValue = (string) $attribute;
72
            }
73 104
            if ($name === "form") {
74 104
                $this->form = (string) $attribute;
75
            }
76
        }
77 104
        $this->initFormattingAttributes($node);
78 104
        $this->initDisplayAttributes($node);
79 104
        $this->initTextCaseAttributes($node);
80 104
        $this->initAffixesAttributes($node);
81 104
        $this->initQuotesAttributes($node);
82 104
    }
83
84
    /**
85
     * @param  stdClass $data
86
     * @param  int|null $citationNumber
87
     * @return string
88
     */
89 88
    public function render($data, $citationNumber = null)
0 ignored issues
show
Coding Style introduced by
Incorrect spacing between argument "$citationNumber" and equals sign; expected 0 but found 1
Loading history...
Coding Style introduced by
Incorrect spacing between default value and equals sign for argument "$citationNumber"; expected 0 but found 1
Loading history...
90
    {
91 88
        $lang = (isset($data->language) && $data->language != 'en') ? $data->language : 'en';
92
93 88
        $renderedText = "";
94 88
        switch ($this->toRenderType) {
95 88
            case 'value':
96 22
                $renderedText = $this->applyTextCase($this->toRenderTypeValue, $lang);
97 22
                break;
98 81
            case 'variable':
99 71
                if ($this->toRenderTypeValue === "locator" && CiteProc::getContext()->isModeCitation()) {
100 3
                    $renderedText = $this->renderLocator($data, $citationNumber);
101
                // for test sort_BibliographyCitationNumberDescending.json
102 71
                } elseif ($this->toRenderTypeValue === "citation-number") {
103 12
                    $renderedText = $this->renderCitationNumber($data, $citationNumber);
104 12
                    break;
105 68
                } elseif ($this->toRenderTypeValue === "page" || $this->toRenderTypeValue === "chapter-number") {
106 26
                    $renderedText = !empty($data->{$this->toRenderTypeValue}) ? $this->renderPage($data->{$this->toRenderTypeValue}) : '';
107
                } else {
108 65
                    $renderedText = $this->renderVariable($data, $lang);
109
                }
110 69
                if (CiteProc::getContext()->getRenderingState()->getValue() === RenderingState::SUBSTITUTION) {
111 7
                    unset($data->{$this->toRenderTypeValue});
112
                }
113 69
                $renderedText = $this->applyAdditionalMarkupFunction($data, $renderedText);
114 69
                break;
115 59
            case 'macro':
116 52
                $renderedText = $this->renderMacro($data);
117 52
                break;
118 26
            case 'term':
119 26
                $term = CiteProc::getContext()
120 26
                    ->getLocale()
121 26
                    ->filter("terms", $this->toRenderTypeValue, $this->form)
122 26
                    ->single;
123 26
                $renderedText = !empty($term) ? $this->applyTextCase($term, $lang) : "";
124
        }
125 88
        if (!empty($renderedText)) {
126 88
            $renderedText = $this->formatRenderedText($renderedText);
127
        }
128 88
        return $renderedText;
129
    }
130
131
    /**
132
     * @return string
133
     */
134 56
    public function getSource()
135
    {
136 56
        return $this->toRenderType;
137
    }
138
139
    /**
140
     * @return string
141
     */
142 56
    public function getVariable()
143
    {
144 56
        return $this->toRenderTypeValue;
145
    }
146
147 15
    private function renderPage($page)
148
    {
149 15
        if (preg_match(NumberHelper::PATTERN_COMMA_AMPERSAND_RANGE, $page)) {
150 14
            $page = $this->normalizeDateRange($page);
151 14
            $ranges = preg_split("/[-–]/", trim($page));
152 14
            if (count($ranges) > 1) {
0 ignored issues
show
Bug introduced by
It seems like $ranges can also be of type false; however, parameter $var of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

152
            if (count(/** @scrutinizer ignore-type */ $ranges) > 1) {
Loading history...
153 13
                if (!empty(CiteProc::getContext()->getGlobalOptions())
154 13
                    && !empty(CiteProc::getContext()->getGlobalOptions()->getPageRangeFormat())
155
                ) {
156 7
                    return PageHelper::processPageRangeFormats(
157 7
                        $ranges,
0 ignored issues
show
Bug introduced by
It seems like $ranges can also be of type false; however, parameter $ranges of Seboettg\CiteProc\Util\P...ocessPageRangeFormats() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

157
                        /** @scrutinizer ignore-type */ $ranges,
Loading history...
158 7
                        CiteProc::getContext()->getGlobalOptions()->getPageRangeFormat()
159
                    );
160
                }
161 6
                list($from, $to) = $ranges;
162 6
                return $from . "–" . $to;
163
            }
164
        }
165 2
        return $page;
166
    }
167
168 3
    private function renderLocator($data, $citationNumber)
169
    {
170 3
        $citationItem = CiteProc::getContext()->getCitationItemById($data->id);
171 3
        if (!empty($citationItem->label)) {
172 1
            $locatorData = new stdClass();
173 1
            $propertyName = LocatorHelper::mapLocatorLabelToRenderVariable($citationItem->label);
174 1
            $locatorData->{$propertyName} = $citationItem->locator;
175 1
            $renderTypeValueTemp = $this->toRenderTypeValue;
176 1
            $this->toRenderTypeValue = $propertyName;
177 1
            $result = $this->render($locatorData, $citationNumber);
178 1
            $this->toRenderTypeValue = $renderTypeValueTemp;
179 1
            return $result;
180
        }
181 2
        return $citationItem->locator ?? '';
182
    }
183
184 14
    private function normalizeDateRange($page)
185
    {
186 14
        if (preg_match("/^(\d+)\s?--?\s?(\d+)$/", trim($page), $matches)) {
187 13
            return $matches[1]."-".$matches[2];
188
        }
189 1
        return $page;
190
    }
191
192
    /**
193
     * @param  $data
194
     * @param  $renderedText
195
     * @return mixed
196
     */
197 71
    private function applyAdditionalMarkupFunction($data, $renderedText)
198
    {
199 71
        return CiteProcHelper::applyAdditionMarkupFunction($data, $this->toRenderTypeValue, $renderedText);
200
    }
201
202
    /**
203
     * @param  $data
204
     * @param  $lang
205
     * @return string
206
     */
207 65
    private function renderVariable($data, $lang)
208
    {
209
        // check if there is an attribute with prefix short or long e.g. shortTitle or longAbstract
210
        // test case group_ShortOutputOnly.json
211 65
        $renderedText = "";
212 65
        if (in_array($this->form, ["short", "long"])) {
213 65
            $attrWithPrefix = $this->form.ucfirst($this->toRenderTypeValue);
214 65
            $attrWithSuffix = $this->toRenderTypeValue."-".$this->form;
215 65
            if (isset($data->{$attrWithPrefix}) && !empty($data->{$attrWithPrefix})) {
216 1
                $renderedText = $this->applyTextCase(
217 1
                    StringHelper::clearApostrophes(
218 1
                        str_replace(" & ", " &#38; ", $data->{$attrWithPrefix})
219
                    ),
220 1
                    $lang
221
                );
222
            } else {
223 64
                if (isset($data->{$attrWithSuffix}) && !empty($data->{$attrWithSuffix})) {
224 3
                    $renderedText = $this->applyTextCase(
225 3
                        StringHelper::clearApostrophes(
226 3
                            str_replace(" & ", " &#38; ", $data->{$attrWithSuffix})
227
                        ),
228 3
                        $lang
229
                    );
230
                } else {
231 64
                    if (isset($data->{$this->toRenderTypeValue})) {
232 64
                        $renderedText = $this->applyTextCase(
233 64
                            StringHelper::clearApostrophes(
234 64
                                str_replace(" & ", " &#38; ", $data->{$this->toRenderTypeValue})
235
                            ),
236 65
                            $lang
237
                        );
238
                    }
239
                }
240
            }
241
        } else {
242
            if (!empty($data->{$this->toRenderTypeValue})) {
243
                $renderedText = $this->applyTextCase(
244
                    StringHelper::clearApostrophes(
245
                        str_replace(" & ", " &#38; ", $data->{$this->toRenderTypeValue})
246
                    ),
247
                    $lang
248
                );
249
            }
250
        }
251 65
        return $renderedText;
252
    }
253
254
    /**
255
     * @param  $renderedText
256
     * @return string
257
     */
258 88
    private function formatRenderedText($renderedText)
259
    {
260 88
        $text = $this->format($renderedText);
261 88
        $res = $this->addAffixes($text);
262 88
        if (!empty($res)) {
263 88
            $res = $this->removeConsecutiveChars($res);
264
        }
265 88
        $res = $this->addSurroundingQuotes($res);
266 88
        return $this->wrapDisplayBlock($res);
267
    }
268
269
    /**
270
     * @param  $data
271
     * @param  $citationNumber
272
     * @return int|mixed
273
     */
274 12
    private function renderCitationNumber($data, $citationNumber)
275
    {
276 12
        $renderedText = $citationNumber + 1;
277 12
        $renderedText = $this->applyAdditionalMarkupFunction($data, $renderedText);
278 12
        return $renderedText;
279
    }
280
281
    /**
282
     * @param  $data
283
     * @return string
284
     */
285 52
    private function renderMacro($data)
286
    {
287 52
        $macro = CiteProc::getContext()->getMacro($this->toRenderTypeValue);
288 52
        if (is_null($macro)) {
289
            try {
290 1
                throw new CiteProcException("Macro \"".$this->toRenderTypeValue."\" does not exist.");
291 1
            } catch (CiteProcException $e) {
292 1
                $renderedText = "";
293
            }
294
        } else {
295 52
            $renderedText = $macro->render($data);
296
        }
297 52
        return $renderedText;
298
    }
299
}
300