Text   B
last analyzed

Complexity

Total Complexity 50

Size/Duplication

Total Lines 256
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 125
dl 0
loc 256
rs 8.4
c 0
b 0
f 0
wmc 50

12 Methods

Rating   Name   Duplication   Size   Complexity  
B renderVariable() 0 29 8
A getVariable() 0 3 1
A getSource() 0 3 1
A applyAdditionalMarkupFunction() 0 3 1
A renderPage() 0 19 5
A renderLocator() 0 14 3
A __construct() 0 17 4
A normalizeDateRange() 0 6 2
A formatRenderedText() 0 12 3
D render() 0 43 16
A renderMacro() 0 13 3
A renderCitationNumber() 0 7 3

How to fix   Complexity   

Complex Class

Complex classes like Text often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Text, and based on these observations, apply Extract Interface, too.

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\Terms\Locator;
22
use Seboettg\CiteProc\Util\CiteProcHelper;
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
use function Seboettg\CiteProc\ucfirst;
29
30
/**
31
 * Class Term
32
 *
33
 * @package Seboettg\CiteProc\Node\Style
34
 *
35
 * @author Sebastian Böttger <[email protected]>
36
 */
37
class Text implements Rendering
38
{
39
    use FormattingTrait,
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\Text.
Loading history...
Bug introduced by
The trait Seboettg\CiteProc\Styles\QuotesTrait requires the property $single which is not provided by Seboettg\CiteProc\Rendering\Text.
Loading history...
40
        AffixesTrait,
41
        TextCaseTrait,
42
        DisplayTrait,
43
        ConsecutivePunctuationCharacterTrait,
44
        QuotesTrait;
45
46
    /**
47
     * @var string
48
     */
49
    private string $toRenderType;
50
51
    /**
52
     * @var string
53
     */
54
    private string $toRenderTypeValue;
55
56
    /**
57
     * @var string
58
     */
59
    private string $form = "long";
60
61
    /**
62
     * Text constructor.
63
     *
64
     * @param SimpleXMLElement $node
65
     */
66
    public function __construct(SimpleXMLElement $node)
67
    {
68
        foreach ($node->attributes() as $attribute) {
69
            $name = $attribute->getName();
70
            if (in_array($name, ['value', 'variable', 'macro', 'term'])) {
71
                $this->toRenderType = $name;
72
                $this->toRenderTypeValue = (string) $attribute;
73
            }
74
            if ($name === "form") {
75
                $this->form = (string) $attribute;
76
            }
77
        }
78
        $this->initFormattingAttributes($node);
79
        $this->initDisplayAttributes($node);
80
        $this->initTextCaseAttributes($node);
81
        $this->initAffixesAttributes($node);
82
        $this->initQuotesAttributes($node);
83
    }
84
85
    /**
86
     * @param  stdClass $data
87
     * @param  int|null $citationNumber
88
     * @return string
89
     */
90
    public function render($data, $citationNumber = null)
91
    {
92
        $lang = (isset($data->language) && $data->language != 'en') ? $data->language : 'en';
93
94
        $renderedText = "";
95
        switch ($this->toRenderType) {
96
            case 'value':
97
                $renderedText = $this->applyTextCase($this->toRenderTypeValue, $lang);
98
                break;
99
            case 'variable':
100
                if ($this->toRenderTypeValue === "locator" && CiteProc::getContext()->isModeCitation()) {
101
                    $renderedText = $this->renderLocator($data, $citationNumber);
102
                // for test sort_BibliographyCitationNumberDescending.json
103
                } elseif ($this->toRenderTypeValue === "citation-number") {
104
                    $renderedText = $this->renderCitationNumber($data, $citationNumber);
105
                    break;
106
                } elseif (in_array($this->toRenderTypeValue, ["page", "chapter-number", "folio"])) {
107
                    $renderedText = !empty($data->{$this->toRenderTypeValue}) ?
108
                        $this->renderPage($data->{$this->toRenderTypeValue}) : '';
109
                } else {
110
                    $renderedText = $this->renderVariable($data, $lang);
111
                }
112
                if (CiteProc::getContext()->getRenderingState()->getValue() === RenderingState::SUBSTITUTION) {
113
                    unset($data->{$this->toRenderTypeValue});
114
                }
115
                if (!CiteProcHelper::isUsingAffixesByMarkupExtentsion($data, $this->toRenderTypeValue)) {
116
                    $renderedText = $this->applyAdditionalMarkupFunction($data, $renderedText);
117
                }
118
                break;
119
            case 'macro':
120
                $renderedText = $this->renderMacro($data);
121
                break;
122
            case 'term':
123
                $term = CiteProc::getContext()
124
                    ->getLocale()
125
                    ->filter("terms", $this->toRenderTypeValue, $this->form)
126
                    ->single;
127
                $renderedText = !empty($term) ? $this->applyTextCase($term, $lang) : "";
128
        }
129
        if (!empty($renderedText)) {
130
            $renderedText = $this->formatRenderedText($data, $renderedText);
131
        }
132
        return $renderedText;
133
    }
134
135
    /**
136
     * @return string
137
     */
138
    public function getSource()
139
    {
140
        return $this->toRenderType;
141
    }
142
143
    /**
144
     * @return string
145
     */
146
    public function getVariable()
147
    {
148
        return $this->toRenderTypeValue;
149
    }
150
151
    private function renderPage($page)
152
    {
153
        if (preg_match(NumberHelper::PATTERN_COMMA_AMPERSAND_RANGE, $page)) {
154
            $page = $this->normalizeDateRange($page);
155
            $ranges = preg_split("/[-–]/", trim($page));
156
            if (count($ranges) > 1) {
157
                if (!empty(CiteProc::getContext()->getGlobalOptions())
158
                    && !empty(CiteProc::getContext()->getGlobalOptions()->getPageRangeFormat())
159
                ) {
160
                    return PageHelper::processPageRangeFormats(
161
                        $ranges,
162
                        CiteProc::getContext()->getGlobalOptions()->getPageRangeFormat()
163
                    );
164
                }
165
                list($from, $to) = $ranges;
166
                return $from . "–" . $to;
167
            }
168
        }
169
        return $page;
170
    }
171
172
    private function renderLocator($data, $citationNumber)
173
    {
174
        $citationItem = CiteProc::getContext()->getCitationItemById($data->id);
175
        if (!empty($citationItem->label)) {
176
            $locatorData = new stdClass();
177
            $propertyName = Locator::mapLocatorLabelToRenderVariable($citationItem->label);
178
            $locatorData->{$propertyName} = trim($citationItem->locator);
179
            $renderTypeValueTemp = $this->toRenderTypeValue;
180
            $this->toRenderTypeValue = $propertyName;
181
            $result = $this->render($locatorData, $citationNumber);
182
            $this->toRenderTypeValue = $renderTypeValueTemp;
183
            return $result;
184
        }
185
        return isset($citationItem->locator) ? trim($citationItem->locator) : '';
186
    }
187
188
    private function normalizeDateRange($page)
189
    {
190
        if (preg_match("/^(\d+)\s?--?\s?(\d+)$/", trim($page), $matches)) {
191
            return $matches[1]."-".$matches[2];
192
        }
193
        return $page;
194
    }
195
196
    /**
197
     * @param  $data
198
     * @param  $renderedText
199
     * @return mixed
200
     */
201
    private function applyAdditionalMarkupFunction($data, $renderedText)
202
    {
203
        return CiteProcHelper::applyAdditionMarkupFunction($data, $this->toRenderTypeValue, $renderedText);
204
    }
205
206
    /**
207
     * @param  $data
208
     * @param  $lang
209
     * @return string
210
     */
211
    private function renderVariable($data, $lang)
212
    {
213
        // check if there is an attribute with prefix short or long e.g. shortTitle or longAbstract
214
        // test case group_ShortOutputOnly.json
215
        $value = "";
216
        if (in_array($this->form, ["short", "long"])) {
217
            $attrWithPrefix = $this->form . ucfirst($this->toRenderTypeValue);
218
            $attrWithSuffix = $this->toRenderTypeValue . "-" . $this->form;
219
            if (isset($data->{$attrWithPrefix}) && !empty($data->{$attrWithPrefix})) {
220
                $value = $data->{$attrWithPrefix};
221
            } else {
222
                if (isset($data->{$attrWithSuffix}) && !empty($data->{$attrWithSuffix})) {
223
                    $value = $data->{$attrWithSuffix};
224
                } else {
225
                    if (isset($data->{$this->toRenderTypeValue})) {
226
                        $value = $data->{$this->toRenderTypeValue};
227
                    }
228
                }
229
            }
230
        } else {
231
            if (!empty($data->{$this->toRenderTypeValue})) {
232
                $value = $data->{$this->toRenderTypeValue};
233
            }
234
        }
235
        return $this->applyTextCase(
236
            StringHelper::clearApostrophes(
237
                htmlspecialchars($value, ENT_HTML5)
238
            ),
239
            $lang
240
        );
241
    }
242
243
    /**
244
     * @param  $data
245
     * @param  $renderedText
246
     * @return string
247
     */
248
    private function formatRenderedText($data, $renderedText)
249
    {
250
        $text = $this->format($renderedText);
251
        $res = $this->addAffixes($text);
252
        if (CiteProcHelper::isUsingAffixesByMarkupExtentsion($data, $this->toRenderTypeValue)) {
253
            $res = $this->applyAdditionalMarkupFunction($data, $res);
254
        }
255
        if (!empty($res)) {
256
            $res = $this->removeConsecutiveChars($res);
257
        }
258
        $res = $this->addSurroundingQuotes($res);
259
        return $this->wrapDisplayBlock($res);
260
    }
261
262
    /**
263
     * @param  $data
264
     * @param  $citationNumber
265
     * @return int|mixed
266
     */
267
    private function renderCitationNumber($data, $citationNumber)
268
    {
269
        $renderedText = property_exists($data, "citationNumber") ? $data->citationNumber : $citationNumber + 1;
270
        if (!CiteProcHelper::isUsingAffixesByMarkupExtentsion($data, $this->toRenderTypeValue)) {
271
            $renderedText = $this->applyAdditionalMarkupFunction($data, $renderedText);
272
        }
273
        return $renderedText;
274
    }
275
276
    /**
277
     * @param  $data
278
     * @return string
279
     */
280
    private function renderMacro($data)
281
    {
282
        $macro = CiteProc::getContext()->getMacro($this->toRenderTypeValue);
283
        if (is_null($macro)) {
284
            try {
285
                throw new CiteProcException("Macro \"".$this->toRenderTypeValue."\" does not exist.");
286
            } catch (CiteProcException $e) {
287
                $renderedText = "";
288
            }
289
        } else {
290
            $renderedText = $macro->render($data);
291
        }
292
        return $renderedText;
293
    }
294
}
295