Passed
Pull Request — develop (#121)
by Sebastian
05:37
created

Text   B

Complexity

Total Complexity 46

Size/Duplication

Total Lines 248
Duplicated Lines 0 %

Test Coverage

Coverage 98.29%

Importance

Changes 0
Metric Value
eloc 120
dl 0
loc 248
ccs 115
cts 117
cp 0.9829
rs 8.72
c 0
b 0
f 0
wmc 46

12 Methods

Rating   Name   Duplication   Size   Complexity  
A renderCitationNumber() 0 5 1
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 formatRenderedText() 0 9 2
A __construct() 0 17 4
C render() 0 41 15
A renderMacro() 0 13 3
A normalizeDateRange() 0 6 2
B renderVariable() 0 29 8

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