Completed
Push — develop ( b39607 )
by Raúl
16s
created

PoCompiler   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 278
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Importance

Changes 0
Metric Value
dl 0
loc 278
c 0
b 0
f 0
wmc 44
lcom 1
cbo 3
rs 8.3396

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
B compile() 0 45 6
A eol() 0 4 1
A buildPreviousEntry() 0 9 2
A buildTranslatorComment() 0 13 3
A buildDeveloperComment() 0 13 3
A buildReference() 0 14 4
A buildFlags() 0 9 3
A buildContext() 0 10 3
A buildMsgId() 0 8 2
B buildMsgStr() 0 24 6
A buildMsgIdPlural() 0 9 2
B buildProperty() 0 17 5
A cleanExport() 0 19 1
A wrapString() 0 10 2

How to fix   Complexity   

Complex Class

Complex classes like PoCompiler 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 PoCompiler, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Sepia\PoParser;
4
5
use Sepia\PoParser\Catalog\Catalog;
6
use Sepia\PoParser\Catalog\Entry;
7
use Sepia\PoParser\Catalog\Header;
8
9
class PoCompiler
10
{
11
    const TOKEN_OBSOLETE = '#~ ';
12
    /** @var int */
13
    protected $wrappingColumn;
14
15
    /** @var string */
16
    protected $lineEnding;
17
18
    /**
19
     * PoCompiler constructor.
20
     *
21
     * @param int    $wrappingColumn
22
     * @param string $lineEnding
23
     */
24
    public function __construct($wrappingColumn = 80, $lineEnding = "\n")
25
    {
26
        $this->wrappingColumn = $wrappingColumn;
27
        $this->lineEnding = $lineEnding;
28
    }
29
30
    /**
31
     * Compiles entries into a string
32
     *
33
     * @param Catalog $catalog
34
     *
35
     * @return string
36
     * @throws \Exception
37
     * @todo Write obsolete messages at the end of the file.
38
     */
39
    public function compile(Catalog $catalog)
40
    {
41
        $output = '';
42
43
        if (count($catalog->getHeaders()) > 0) {
44
            $output .= 'msgid ""'.$this->eol();
45
            $output .= 'msgstr ""'.$this->eol();
46
            foreach ($catalog->getHeaders() as $header) {
47
                $output .= $header.$this->eol();
48
            }
49
            $output .= $this->eol();
50
        }
51
52
53
        $entriesCount = count($catalog->getEntries());
54
        $counter = 0;
55
        foreach ($catalog->getEntries() as $entry) {
56
            if ($entry->isObsolete() === false) {
57
                $output .= $this->buildPreviousEntry($entry);
58
                $output .= $this->buildTranslatorComment($entry);
59
                $output .= $this->buildDeveloperComment($entry);
60
                $output .= $this->buildReference($entry);
61
            }
62
63
            $output .= $this->buildFlags($entry);
64
65
//            if (isset($entry['@'])) {
66
//                $output .= "#@ ".$entry['@'].$this->eol();
67
//            }
68
69
            $output .= $this->buildContext($entry);
70
            $output .= $this->buildMsgId($entry);
71
            $output .= $this->buildMsgIdPlural($entry);
72
            $output .= $this->buildMsgStr($entry, $catalog->getHeader());
73
74
75
            $counter++;
76
            // Avoid inserting an extra newline at end of file
77
            if ($counter < $entriesCount) {
78
                $output .= $this->eol();
79
            }
80
        }
81
82
        return $output;
83
    }
84
85
    /**
86
     * @return string
87
     */
88
    protected function eol()
89
    {
90
        return $this->lineEnding;
91
    }
92
93
    /**
94
     * @param $entry
95
     *
96
     * @return string
97
     */
98
    protected function buildPreviousEntry(Entry $entry)
99
    {
100
        $previous = $entry->getPreviousEntry();
101
        if ($previous === null) {
102
            return '';
103
        }
104
105
        return '#| msgid '.$this->cleanExport($previous->getMsgId()).$this->eol();
106
    }
107
108
    /**
109
     * @param $entry
110
     *
111
     * @return string
112
     */
113
    protected function buildTranslatorComment(Entry $entry)
114
    {
115
        if ($entry->getTranslatorComments() === null) {
116
            return '';
117
        }
118
119
        $output = '';
120
        foreach ($entry->getTranslatorComments() as $comment) {
121
            $output .= '# '.$comment.$this->eol();
122
        }
123
124
        return $output;
125
    }
126
127
    protected function buildDeveloperComment(Entry $entry)
128
    {
129
        if ($entry->getDeveloperComments() === null) {
130
            return '';
131
        }
132
133
        $output = '';
134
        foreach ($entry->getDeveloperComments() as $comment) {
135
            $output .= '#. '.$comment.$this->eol();
136
        }
137
138
        return $output;
139
    }
140
141
    protected function buildReference(Entry $entry)
142
    {
143
        $reference = $entry->getReference();
144
        if ($reference === null || count($reference) === 0) {
145
            return '';
146
        }
147
148
        $output = '';
149
        foreach ($reference as $ref) {
150
            $output .= '#: '.$ref.$this->eol();
151
        }
152
153
        return $output;
154
    }
155
156
    protected function buildFlags(Entry $entry)
157
    {
158
        $flags = $entry->getFlags();
159
        if ($flags === null || count($flags) === 0) {
160
            return '';
161
        }
162
163
        return '#, '.implode(', ', $flags).$this->eol();
164
    }
165
166
    protected function buildContext(Entry $entry)
167
    {
168
        if ($entry->getMsgCtxt() === null) {
169
            return '';
170
        }
171
172
        return
173
            ($entry->isObsolete() ? '#~ ' : '').
174
            'msgctxt '.$this->cleanExport($entry->getMsgCtxt()).$this->eol();
175
    }
176
177
    protected function buildMsgId(Entry $entry)
178
    {
179
        if ($entry->getMsgId() === null) {
180
            return '';
181
        }
182
183
        return $this->buildProperty('msgid', $entry->getMsgId(), $entry->isObsolete());
184
    }
185
186
    protected function buildMsgStr(Entry $entry, Header $headers)
187
    {
188
        $value = $entry->getMsgStr();
189
        $plurals = $entry->getMsgStrPlurals();
190
191
        if ($value === null && $plurals === null) {
192
            return '';
193
        }
194
195
        if ($entry->isPlural()) {
196
            $output = '';
197
            $nPlurals = $headers->getPluralFormsCount();
198
            $pluralsFound = count($plurals);
199
            $maxIterations = max($nPlurals, $pluralsFound);
200
            for ($i = 0; $i < $maxIterations; $i++) {
201
                $value = isset($plurals[$i]) ? $plurals[$i] : '';
202
                $output .= 'msgstr['.$i.'] '.$this->cleanExport($value).$this->eol();
203
            }
204
205
            return $output;
206
        }
207
208
        return $this->buildProperty('msgstr', $value, $entry->isObsolete());
209
    }
210
211
    /**
212
     * @param Entry $entry
213
     *
214
     * @return string
215
     */
216
    protected function buildMsgIdPlural(Entry $entry)
217
    {
218
        $value = $entry->getMsgIdPlural();
219
        if ($value === null) {
220
            return '';
221
        }
222
223
        return 'msgid_plural '.$this->cleanExport($value).$this->eol();
224
    }
225
226
    protected function buildProperty($property, $value, $obsolete = false)
227
    {
228
        $tokens = $this->wrapString($value);
229
230
        $output = '';
231
        if (count($tokens) > 1) {
232
            array_unshift($tokens, '');
233
        }
234
235
        foreach ($tokens as $i => $token) {
236
            $output .= $obsolete ? self::TOKEN_OBSOLETE : '';
237
            $output .= ($i === 0) ? $property.' ' : '';
238
            $output .= $this->cleanExport($token).$this->eol();
239
        }
240
241
        return $output;
242
    }
243
244
    /**
245
     * Prepares a string to be outputed into a file.
246
     *
247
     * @param string $string The string to be converted.
248
     *
249
     * @return string
250
     */
251
    protected function cleanExport($string)
252
    {
253
        $quote = '"';
254
        $slash = '\\';
255
        $newline = "\n";
256
257
        $replaces = array(
258
            "$slash" => "$slash$slash",
259
            "$quote" => "$slash$quote",
260
            "\t" => '\t',
261
        );
262
263
        $string = str_replace(array_keys($replaces), array_values($replaces), $string);
264
265
        $po = $quote.implode("${slash}n$quote$newline$quote", explode($newline, $string)).$quote;
266
267
        // remove empty strings
268
        return str_replace("$newline$quote$quote", '', $po);
269
    }
270
271
    /**
272
     * @param string $value
273
     *
274
     * @return array
275
     */
276
    private function wrapString($value)
277
    {
278
        if (strlen($value) > $this->wrappingColumn) {
279
            $tokens = str_split($value, $this->wrappingColumn);
280
        } else {
281
            $tokens = array($value);
282
        }
283
284
        return $tokens;
285
    }
286
}
287