Completed
Pull Request — master (#39)
by Sebastian
11:45
created

Layout   A

Complexity

Total Complexity 34

Size/Duplication

Total Lines 227
Duplicated Lines 5.29 %

Coupling/Cohesion

Components 1
Dependencies 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
dl 12
loc 227
rs 9.2
c 2
b 0
f 0
wmc 34
lcom 1
cbo 12

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 12 12 2
D render() 0 44 9
D renderSingle() 0 34 10
A getNumberOfCitedItems() 0 4 1
A wrapBibEntry() 0 4 1
A htmlentities() 0 5 1
A renderCitations() 0 9 2
A filterCitationItems() 0 15 3
A isGroupedCitations() 0 8 2
A renderGroupedCitations() 0 13 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

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\Context;
14
use Seboettg\CiteProc\Data\DataList;
15
use Seboettg\CiteProc\Styles\AffixesTrait;
16
use Seboettg\CiteProc\Styles\ConsecutivePunctuationCharacterTrait;
17
use Seboettg\CiteProc\Styles\FormattingTrait;
18
use Seboettg\CiteProc\Styles\DelimiterTrait;
19
use Seboettg\CiteProc\Util\Factory;
20
use Seboettg\CiteProc\Util\StringHelper;
21
use Seboettg\Collection\ArrayList;
22
23
24
/**
25
 * Class Layout
26
 * @package Seboettg\CiteProc\Rendering
27
 *
28
 * @author Sebastian Böttger <[email protected]>
29
 */
30
class Layout implements Rendering
31
{
32
33
    private static $numberOfCitedItems = 0;
34
35
    use AffixesTrait,
36
        FormattingTrait,
37
        DelimiterTrait,
38
        ConsecutivePunctuationCharacterTrait;
39
40
    /**
41
     * @var ArrayList
42
     */
43
    private $children;
44
45
    /**
46
     * When used within cs:citation, the delimiter attribute may be used to specify a delimiter for cites within a
47
     * citation.
48
     * @var string
49
     */
50
    private $delimiter = "";
51
52
53
    private $parent;
54
55
    /**
56
     * @param \Seboettg\CiteProc\Style\StyleElement $parent
57
     */
58 View Code Duplication
    public function __construct($node, $parent)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
59
    {
60
        $this->parent = $parent;
61
        self::$numberOfCitedItems = 0;
62
        $this->children = new ArrayList();
63
        foreach ($node->children() as $child) {
64
            $this->children->append(Factory::create($child, $this));
65
        }
66
        $this->initDelimiterAttributes($node);
67
        $this->initAffixesAttributes($node);
68
        $this->initFormattingAttributes($node);
69
    }
70
71
    /**
72
     * @param array|DataList $data
73
     * @param array|ArrayList $citationItems
74
     * @return string|array
75
     */
76
    public function render($data, $citationItems = [])
77
    {
78
        $ret = "";
79
        $sorting = CiteProc::getContext()->getSorting();
80
        if (!empty($sorting)) {
81
            CiteProc::getContext()->setRenderingState("sorting");
82
            $sorting->sort($data);
83
            CiteProc::getContext()->setRenderingState("rendering");
84
        }
85
86
        if (CiteProc::getContext()->isModeBibliography()) {
87
            if ($data instanceof DataList) {
88
                foreach ($data as $citationNumber => $item) {
89
                    ++self::$numberOfCitedItems;
90
                    CiteProc::getContext()->getResults()->append($this->wrapBibEntry($this->renderSingle($item, $citationNumber)));
91
                }
92
                $ret .= implode($this->delimiter, CiteProc::getContext()->getResults()->toArray());
93
            } else {
94
                $ret .= $this->wrapBibEntry($this->renderSingle($data, null));
95
            }
96
            $ret = StringHelper::clearApostrophes($ret);
97
            return "<div class=\"csl-bib-body\">" . $ret . "\n</div>";
98
99
        } else if (CiteProc::getContext()->isModeCitation()) {
100
            if ($data instanceof DataList) {
101
                if ($citationItems->count() > 0) { //is there a filter for specific citations?
0 ignored issues
show
Bug introduced by
It seems like $citationItems is not always an object, but can also be of type array. Maybe add an additional type check?

If a variable is not always an object, we recommend to add an additional type check to ensure your method call is safe:

function someFunction(A $objectMaybe = null)
{
    if ($objectMaybe instanceof A) {
        $objectMaybe->doSomething();
    }
}
Loading history...
102
                    if ($this->isGroupedCitations($citationItems)) { //if citation items grouped?
0 ignored issues
show
Bug introduced by
It seems like $citationItems defined by parameter $citationItems on line 76 can also be of type array; however, Seboettg\CiteProc\Render...t::isGroupedCitations() does only seem to accept object<Seboettg\Collection\ArrayList>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
103
                        return $this->renderGroupedCitations($data, $citationItems);
0 ignored issues
show
Bug introduced by
It seems like $citationItems defined by parameter $citationItems on line 76 can also be of type array; however, Seboettg\CiteProc\Render...enderGroupedCitations() does only seem to accept object<Seboettg\Collection\ArrayList>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
104
                    } else {
105
                        $data = $this->filterCitationItems($data, $citationItems);
0 ignored issues
show
Bug introduced by
It seems like $citationItems defined by parameter $citationItems on line 76 can also be of type array; however, Seboettg\CiteProc\Render...::filterCitationItems() does only seem to accept object<Seboettg\Collection\ArrayList>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
106
                        $ret = $this->renderCitations($data, $ret);
107
                    }
108
109
                } else {
110
                    $ret = $this->renderCitations($data, $ret);
111
                }
112
113
            } else {
114
                $ret .= $this->renderSingle($data, null);
115
            }
116
        }
117
        $ret = StringHelper::clearApostrophes($ret);
118
        return $this->addAffixes($ret);
119
    }
120
121
    /**
122
     * @param $data
123
     * @param int|null $citationNumber
124
     * @return string
125
     */
126
    private function renderSingle($data, $citationNumber = null)
127
    {
128
129
        $bibliographyOptions = CiteProc::getContext()->getBibliographySpecificOptions();
130
        $inMargin = [];
131
        $margin = [];
132
        foreach ($this->children as $key => $child) {
133
            $rendered = $child->render($data, $citationNumber);
134
            $this->getChildsAffixesAndDelimiter($child);
135
            if (CiteProc::getContext()->isModeBibliography() && $bibliographyOptions->getSecondFieldAlign() === "flush") {
136
137
                if ($key === 0 && !empty($rendered)) {
138
                    $inMargin[] = $rendered;
139
                } else {
140
                    $margin[] = $rendered;
141
                }
142
            } else {
143
                $inMargin[] = $rendered;
144
            }
145
        }
146
147
148
        if (!empty($inMargin) && !empty($margin) && CiteProc::getContext()->isModeBibliography()) {
149
            $leftMargin = $this->removeConsecutiveChars($this->htmlentities($this->format(implode("", $inMargin))));
150
            $rightInline = $this->removeConsecutiveChars($this->htmlentities($this->format(implode("", $margin))) . $this->suffix);
151
            $res  = '<div class="csl-left-margin">' . $leftMargin . '</div>';
152
            $res .= '<div class="csl-right-inline">' . $rightInline . '</div>';
153
            return $res;
154
        } else if (!empty($inMargin)) {
155
            $res = $this->format(implode("", $inMargin));
156
            return $this->htmlentities($this->removeConsecutiveChars($res));
157
        }
158
        return "";
159
    }
160
161
    /**
162
     * @return int
163
     */
164
    public static function getNumberOfCitedItems()
165
    {
166
        return self::$numberOfCitedItems;
167
    }
168
169
    /**
170
     * @param string $value
171
     * @return string
172
     */
173
    private function wrapBibEntry($value)
174
    {
175
        return "\n  <div class=\"csl-entry\">" . $this->addAffixes($value) . "</div>";
176
    }
177
178
    /**
179
     * @param string $text
180
     * @return string
181
     */
182
    private function htmlentities($text)
183
    {
184
        $text = preg_replace("/(.*)&([^#38;|amp;].*)/u", "$1&#38;$2", $text);
185
        return $text;
186
    }
187
188
    /**
189
     * @param $data
190
     * @param $ret
191
     * @return string
192
     */
193
    private function renderCitations($data, $ret)
194
    {
195
        CiteProc::getContext()->getResults()->replace([]);
196
        foreach ($data as $citationNumber => $item) {
197
            CiteProc::getContext()->getResults()->append($this->renderSingle($item, $citationNumber));
198
        }
199
        $ret .= implode($this->delimiter, CiteProc::getContext()->getResults()->toArray());
200
        return $ret;
201
    }
202
203
    /**
204
     * @param DataList $data
205
     * @param ArrayList $citationItems
206
     * @return mixed
207
     */
208
    private function filterCitationItems($data, $citationItems)
209
    {
210
        $arr = $data->toArray();
211
212
        $arr_ = array_filter($arr, function($dataItem) use ($citationItems) {
213
            foreach ($citationItems as $citationItem) {
214
                if ($dataItem->id === $citationItem->id) {
215
                    return true;
216
                }
217
            }
218
            return false;
219
        });
220
221
        return $data->replace($arr_);
222
    }
223
224
    /**
225
     * @param ArrayList $citationItems
226
     * @return bool
227
     */
228
    private function isGroupedCitations(ArrayList $citationItems)
229
    {
230
        $firstItem = array_values($citationItems->toArray())[0];
231
        if (is_array($firstItem)) {
232
            return true;
233
        }
234
        return false;
235
    }
236
237
    /**
238
     * @param DataList $data
239
     * @param ArrayList $citationItems
240
     * @return array|string
241
     */
242
    private function renderGroupedCitations($data, $citationItems)
243
    {
244
        $group = [];
245
        foreach ($citationItems as $citationItemGroup) {
246
            $data_ = $this->filterCitationItems(clone $data, $citationItemGroup);
247
            CiteProc::getContext()->setCitationItems($data_);
0 ignored issues
show
Compatibility introduced by
$data_ of type object<Seboettg\Collection\ArrayList> is not a sub-type of object<Seboettg\CiteProc\Data\DataList>. It seems like you assume a child class of the class Seboettg\Collection\ArrayList to be always present.

This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.

Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.

Loading history...
248
            $group[] = $this->addAffixes(StringHelper::clearApostrophes($this->renderCitations($data_, "")));
249
        }
250
        if (CiteProc::getContext()->isCitationsAsArray()) {
251
            return $group;
252
        }
253
        return implode("\n", $group);
254
    }
255
256
}