PoEntry   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 291
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 44
lcom 1
cbo 0
dl 0
loc 291
ccs 125
cts 125
cp 1
rs 8.8798
c 0
b 0
f 0

13 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 13 1
A add() 0 8 2
A addQuoted() 0 13 3
A addQuotedAtPosition() 0 17 5
A get() 0 4 1
A getAsString() 0 8 2
A getAsStringArray() 0 13 4
A set() 0 4 1
B dumpEntry() 0 29 6
A dumpEntryComments() 0 26 5
A formatQuotedString() 0 16 6
A hasFlag() 0 16 4
A addFlag() 0 14 4

How to fix   Complexity   

Complex Class

Complex classes like PoEntry 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 PoEntry, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Geekwright\Po;
4
5
/**
6
 * PoEntry represent a single entry in a GNU gettext style PO or POT file.
7
 * An entry consists of an associative array of values, indexed by type. These
8
 * types are based on PO file line recognition tokens from PoTokens.
9
 *
10
 * @category  Entries
11
 * @package   Po
12
 * @author    Richard Griffith <[email protected]>
13
 * @copyright 2015-2018 Richard Griffith
14
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
15
 * @link      https://github.com/geekwright/Po
16
 */
17
class PoEntry
18
{
19
    /**
20
     * @var array $entry
21
     */
22
    protected $entry = array();
23
24
    /**
25
     * establish an empty entry
26
     */
27 32
    public function __construct()
28
    {
29 32
        $this->entry[PoTokens::TRANSLATOR_COMMENTS] = null;
30 32
        $this->entry[PoTokens::EXTRACTED_COMMENTS] = null;
31 32
        $this->entry[PoTokens::REFERENCE] = null;
32 32
        $this->entry[PoTokens::FLAG] = null;
33 32
        $this->entry[PoTokens::PREVIOUS] = null;
34 32
        $this->entry[PoTokens::OBSOLETE] = null;
35 32
        $this->entry[PoTokens::CONTEXT] = null;
36 32
        $this->entry[PoTokens::MESSAGE] = null;
37 32
        $this->entry[PoTokens::PLURAL] = null;
38 32
        $this->entry[PoTokens::TRANSLATED] = null;
39 32
    }
40
41
    /**
42
     * add a value to an array 'type' in the entry
43
     *
44
     * @param string $type  PoToken constant
45
     * @param string $value value to store
46
     * @return void
47
     */
48 25
    public function add(string $type, string $value): void
49
    {
50 25
        if ($this->entry[$type] === null) {
51 16
            $this->entry[$type] = array();
52
        }
53 25
        $this->entry[$type] = (array) $this->entry[$type];
54 25
        $this->entry[$type][] = $value;
55 25
    }
56
57
    /**
58
     * add a quoted value to the array 'type' in the entry
59
     *
60
     * @param string $type  PoToken constant
61
     * @param string $value value to store
62
     * @return void
63
     */
64 7
    public function addQuoted(string $type, string $value): void
65
    {
66 7
        if ($value[0]=='"') {
67 7
            $value = substr($value, 1, -1);
68
        }
69 7
        $value = stripcslashes($value);
70
71 7
        if ($this->entry[$type] === null) {
72 7
            $this->entry[$type] = array();
73
        }
74 7
        $this->entry[$type] = (array) $this->entry[$type];
75 7
        $this->entry[$type][] = $value;
76 7
    }
77
78
    /**
79
     * add a quoted value to the nested array 'type' in the entry
80
     *
81
     * This is mainly useful for translated plurals. Since any plural msgstr can have
82
     * continuation lines, the message is stored as an array of arrays.
83
     *
84
     * @param string  $type     PoToken constant
85
     * @param integer $position array position to store
86
     * @param string  $value    value to store
87
     * @return void
88
     */
89 7
    public function addQuotedAtPosition(string $type, int $position, string $value): void
90
    {
91 7
        if ($value[0]=='"') {
92 6
            $value = substr($value, 1, -1);
93
        }
94 7
        $value = stripcslashes($value);
95
96 7
        if ($this->entry[$type] === null) {
97 7
            $this->entry[$type] = array();
98
        }
99 7
        if (isset($this->entry[$type][$position]) &&
100 7
            is_scalar($this->entry[$type][$position])
101
        ) {
102 1
            $this->entry[$type][$position] = array($this->entry[$type][$position]);
103
        }
104 7
        $this->entry[$type][$position][] = $value;
105 7
    }
106
107
    /**
108
     * get the value for a specified type
109
     *
110
     * @param string $type PoToken constant
111
     *
112
     * @return string|string[]|null
113
     */
114 10
    public function get(string $type)
115
    {
116 10
        return $this->entry[$type];
117
    }
118
119
    /**
120
     * get the value of a specified type as a string
121
     *
122
     * @param string $type PoToken constant
123
     * @return string|null
124
     */
125 18
    public function getAsString(string $type): ?string
126
    {
127 18
        $ret = $this->entry[$type];
128 18
        if (is_array($ret)) {
129 6
            $ret = implode('', $ret);
130
        }
131 18
        return $ret;
132
    }
133
134
    /**
135
     * Get the value of a specified type as an array of strings. This is
136
     * mainly for plural TRANSLATED messages.
137
     *
138
     * @param string $type PoToken constant
139
     *
140
     * @return string[]|null
141
     */
142 2
    public function getAsStringArray(string $type): ?array
143
    {
144 2
        $plurals = $this->entry[$type];
145 2
        $plurals = is_array($plurals) ? $plurals : array('', '');
146 2
        $ret = array();
147 2
        foreach ($plurals as $i => $value) {
148 2
            if (is_array($value)) {
149 2
                $value = implode('', $value);
150
            }
151 2
            $ret[$i] = $value;
152
        }
153 2
        return $ret;
154
    }
155
156
    /**
157
     * set the value of a specified type
158
     *
159
     * @param string               $type  PoToken constant
160
     * @param string|string[]|null $value value to set
161
     * @return void
162
     */
163 28
    public function set(string $type, $value): void
164
    {
165 28
        $this->entry[$type] = $value;
166 28
    }
167
168
    /**
169
     * Dump this entry as a po/pot file fragment
170
     *
171
     * @return string
172
     */
173 7
    public function dumpEntry(): string
174
    {
175 7
        $output = $this->dumpEntryComments();
176
177 7
        $key = PoTokens::CONTEXT;
178 7
        if (!($this->entry[$key] === null)) {
179 1
            $output .= $key . $this->formatQuotedString($this->entry[$key]);
180
        }
181 7
        $key = PoTokens::MESSAGE;
182 7
        if (!($this->entry[$key] === null)) {
183 7
            $output .= $key . $this->formatQuotedString($this->entry[$key]);
184 7
            $key = PoTokens::PLURAL;
185 7
            if (!($this->entry[$key] === null)) {
186 4
                $output .= $key . $this->formatQuotedString($this->entry[$key]);
187 4
                $key = PoTokens::TRANSLATED;
188 4
                $plurals = $this->entry[$key];
189 4
                $plurals = is_array($plurals) ? $plurals : array('', '');
190 4
                foreach ($plurals as $i => $value) {
191 4
                    $output .= "{$key}[{$i}]" . $this->formatQuotedString($value);
192
                }
193
            } else {
194 7
                $key = PoTokens::TRANSLATED;
195 7
                $output .= $key . $this->formatQuotedString($this->entry[$key]);
196
            }
197
        }
198
199 7
        $output .= "\n";
200 7
        return $output;
201
    }
202
203
    /**
204
     * Dump the comments for this entry as a po/pot file fragment
205
     *
206
     * @return string
207
     */
208 7
    protected function dumpEntryComments(): string
209
    {
210
        $commentKeys = array(
211 7
            PoTokens::TRANSLATOR_COMMENTS,
212 7
            PoTokens::EXTRACTED_COMMENTS,
213 7
            PoTokens::REFERENCE,
214 7
            PoTokens::FLAG,
215 7
            PoTokens::PREVIOUS,
216 7
            PoTokens::OBSOLETE,
217
        );
218
219 7
        $output = '';
220
221 7
        foreach ($commentKeys as $type) {
222 7
            $section = $this->entry[$type];
223 7
            if (is_array($section)) {
224 7
                foreach ($section as $comment) {
225 7
                    $output .= $type . ' ' . $comment . "\n";
226
                }
227 7
            } elseif (!($section === null)) {
228 7
                $output .= $type . ' ' . $section . "\n";
229
            }
230
        }
231
232 7
        return $output;
233
    }
234
235
    /**
236
     * format a string for output by escaping control and double quote
237
     * characters, then surrounding with double quotes
238
     *
239
     * @param string|string[]|null $value string to prepare
240
     * @param boolean              $bare  true for bare output, default false adds leading
241
     *                                    space and trailing newline
242
     *
243
     * @return string
244
     */
245 7
    protected function formatQuotedString($value, bool $bare = false): string
246
    {
247 7
        if (is_array($value)) {
248 7
            $string = '';
249 7
            foreach ($value as $partial) {
250 7
                $string .= $this->formatQuotedString($partial, true) . "\n";
251
            }
252 7
            return $bare ? $string : ' ' . $string;
253
        } else {
254 7
            $string = ($value === null) ? '' : $value;
255 7
            $string = stripcslashes($string);
256 7
            $string = addcslashes($string, "\0..\37\"");
257 7
            $string = '"' . $string . '"';
258 7
            return $bare ? $string : ' ' . $string . "\n";
259
        }
260
    }
261
262
    /**
263
     * check for presence of a flag
264
     *
265
     * @param string $name flag to check
266
     *
267
     * @return boolean true if flag is set, otherwise false
268
     */
269 4
    public function hasFlag(string $name): bool
270
    {
271 4
        $flags = array();
272 4
        $flagEntry = $this->entry[PoTokens::FLAG];
273 4
        if (!empty($flagEntry)) {
274 4
            foreach ((array) $flagEntry as $csv) {
275 4
                $temp = str_getcsv($csv, ',');
276 4
                foreach ($temp as $flag) {
277 4
                    $flag = strtolower(trim($flag));
278 4
                    $flags[$flag] = $flag;
279
                }
280
            }
281 4
            return isset($flags[strtolower(trim($name))]);
282
        }
283 4
        return false;
284
    }
285
286
    /**
287
     * add a flag to the entry
288
     *
289
     * @param string $name flag to check
290
     *
291
     * @return void
292
     */
293 4
    public function addFlag(string $name): void
294
    {
295 4
        if (!$this->hasFlag($name)) {
296 4
            $flagEntry = $this->entry[PoTokens::FLAG];
297 4
            if ($flagEntry === null) {
298 4
                $this->set(PoTokens::FLAG, $name);
299 1
            } elseif (is_array($flagEntry)) {
300 1
                $flagEntry[] = $name;
301 1
                $this->set(PoTokens::FLAG, implode(',', $flagEntry));
302
            } else {
303 1
                $this->set(PoTokens::FLAG, $flagEntry . ',' . $name);
304
            }
305
        }
306 4
    }
307
}
308