Completed
Push — develop ( 02e98a...1a0fb7 )
by Mikaël
02:04
created

AbstractElement   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 335
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 57
lcom 2
cbo 0
dl 0
loc 335
ccs 123
cts 123
cp 1
rs 6.433
c 0
b 0
f 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 6 1
A getName() 0 4 1
A nameIsValid() 0 8 2
A stringIsValid() 0 4 4
A objectIsValid() 0 4 3
A toString() 0 12 3
A getToStringDeclaration() 0 8 2
A getToStringBeforeChildren() 0 8 2
A getToStringAfterChildren() 0 8 2
A cleanArrayToString() 0 10 3
A getChildContent() 0 10 4
A getPhpName() 0 4 1
A addChild() 0 13 4
A childIsValid() 0 11 4
A getChildren() 0 4 1
getPhpDeclaration() 0 1 ?
getChildrenTypes() 0 1 ?
A getContextualLineBeforeChildren() 0 9 2
A getContextualLineAfterChildren() 0 9 2
A getLineBeforeChildren() 0 4 1
A getLineAfterChildren() 0 4 1
A useBracketsForChildren() 0 4 1
A getBracketBeforeChildren() 0 6 2
A getBracketAfterChildren() 0 5 2
A setIndentation() 0 5 1
A getIndentation() 0 4 1
A getIndentationString() 0 4 2
A getIndentedString() 0 8 2
A setName() 0 8 2
A getCalledClass() 0 4 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace WsdlToPhp\PhpGenerator\Element;
4
5
abstract class AbstractElement implements GenerableInterface
6
{
7
    /**
8
     * @var string
9
     */
10
    protected $name;
11
    /**
12
     * @var AbstractElement[]|mixed[]
13
     */
14
    protected $children;
15
    /**
16
     * @var int
17
     */
18
    protected $indentation;
19
    /**
20
     * @param string $name
21
     */
22 616
    public function __construct($name)
23
    {
24 616
        $this->setName($name);
25 576
        $this->children = array();
26 576
        $this->indentation = 0;
27 576
    }
28
    /**
29
     * @param string $name
30
     * @return AbstractElement
31
     */
32 616
    public function setName($name)
33
    {
34 616
        if (!self::nameIsValid($name)) {
35 40
            throw new \InvalidArgumentException(sprintf('Name "%s" is invalid when instantiating %s object', $name, $this->getCalledClass()));
36
        }
37 576
        $this->name = $name;
38 576
        return $this;
39
    }
40
    /**
41
     * @return string
42
     */
43 404
    public function getName()
44
    {
45 404
        return $this->name;
46
    }
47
    /**
48
     * @param string $name
49
     * @param bool $allowBackslash
50
     * @return bool
51
     */
52 624
    public static function nameIsValid($name, $allowBackslash = false)
53
    {
54 624
        $pattern = '/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/';
55 624
        if ($allowBackslash === true) {
56 88
            $pattern = '/[a-zA-Z_\x7f-\xff\\\][a-zA-Z0-9_\x7f-\xff\\\]*/';
57 88
        }
58 624
        return preg_match($pattern, $name);
59
    }
60
    /**
61
     * @param mixed $string
62
     * @param bool $checkName
63
     * @param bool $allowBackslash
64
     * @return bool
65
     */
66 224
    public static function stringIsValid($string, $checkName = true, $allowBackslash = false)
67
    {
68 224
        return (is_string($string) && !empty($string) && (!$checkName || self::nameIsValid($string, $allowBackslash)));
69
    }
70
    /**
71
     * @param mixed $object
72
     * @return bool
73
     */
74 172
    public static function objectIsValid($object, $checkClass = null)
75
    {
76 172
        return (is_object($object) && ($checkClass === null || get_class($object) === $checkClass));
77
    }
78
    /**
79
     * @see \WsdlToPhp\PhpGenerator\Element\GenerableInterface::toString()
80
     * @param int $indentation
81
     * @return string
82
     */
83 156
    public function toString($indentation = null)
84
    {
85
        $lines = array(
86 156
            $this->getToStringDeclaration($indentation),
87 156
            $this->getToStringBeforeChildren($indentation),
88 156
        );
89 156
        foreach ($this->getChildren() as $child) {
90 100
            $lines[] = $this->getChildContent($child, $indentation + ($this->useBracketsForChildren() ? 1 : 0));
91 156
        }
92 156
        $lines[] = $this->getToStringAfterChildren($indentation);
93 156
        return implode(self::BREAK_LINE_CHAR, self::cleanArrayToString($lines));
94
    }
95
    /**
96
     * @param int $indentation
97
     * @return string|null
98
     */
99 156
    private function getToStringDeclaration($indentation = null)
100
    {
101 156
        $declaration = $this->getPhpDeclaration();
102 156
        if (!empty($declaration)) {
103 156
            return $this->getIndentedString($declaration, $indentation);
104
        }
105 52
        return null;
106
    }
107
    /**
108
     * @param string $indentation
109
     * @return string|null
110
     */
111 156
    private function getToStringBeforeChildren($indentation = null)
112
    {
113 156
        $before = $this->getContextualLineBeforeChildren($indentation);
114 156
        if (!empty($before)) {
115 104
            return $before;
116
        }
117 128
        return null;
118
    }
119
    /**
120
     * @param string $indentation
121
     * @return string|null
122
     */
123 156
    private function getToStringAfterChildren($indentation = null)
124
    {
125 156
        $after = $this->getContextualLineAfterChildren($indentation);
126 156
        if (!empty($after)) {
127 104
            return $after;
128
        }
129 128
        return null;
130
    }
131
    /**
132
     * @param array $array
133
     * @return array
134
     */
135 156
    private static function cleanArrayToString($array)
136
    {
137 156
        $newArray = array();
138 156
        foreach ($array as $line) {
139 156
            if ($line !== null) {
140 156
                $newArray[] = $line;
141 156
            }
142 156
        }
143 156
        return $newArray;
144
    }
145
    /**
146
     * @throws \InvalidArgumentException
147
     * @param string|AbstractElement $child
148
     * @param int $indentation
149
     * @return string
150
     */
151 100
    protected function getChildContent($child, $indentation = null)
152
    {
153 100
        $content = '';
154 100
        if (is_string($child)) {
155 16
            $content = $this->getIndentedString($child, $indentation);
156 100
        } elseif ($child instanceof AbstractElement) {
157 100
            $content = $child->toString($indentation === null ? $this->getIndentation() : $indentation);
158 100
        }
159 100
        return $content;
160
    }
161
    /**
162
     * @return string
163
     */
164 380
    public function getPhpName()
165
    {
166 380
        return sprintf('%s', $this->getName());
167
    }
168
    /**
169
     * @throws \InvalidArgumentException
170
     * @param mixed $child
171
     * @return AbstractElement
172
     */
173 164
    public function addChild($child)
174
    {
175 164
        if (!$this->childIsValid($child)) {
176 40
            $types = $this->getChildrenTypes();
177 40
            if (empty($types)) {
178 16
                throw new \InvalidArgumentException('This element does not accept any child element');
179
            } else {
180 24
                throw new \InvalidArgumentException(sprintf('Element of type "%s:%s" is not authorized, please provide one of these types: %s', gettype($child), is_object($child) ? get_class($child) : 'unknown', implode(', ', $this->getChildrenTypes())));
181
            }
182
        }
183 124
        $this->children[] = $child;
184 124
        return $this;
185
    }
186
    /**
187
     * @param mixed $child
188
     * @return bool
189
     */
190 188
    protected function childIsValid($child)
191
    {
192 188
        $valid = false;
193 188
        $authorizedTypes = $this->getChildrenTypes();
194 188
        if (!empty($authorizedTypes)) {
195 172
            foreach ($authorizedTypes as $authorizedType) {
196 172
                $valid |= (gettype($child) === $authorizedType) || self::objectIsValid($child, $authorizedType);
197 172
            }
198 172
        }
199 188
        return (bool) $valid;
200
    }
201
    /**
202
     * @return AbstractElement[]|mixed[]
203
     */
204 220
    public function getChildren()
205
    {
206 220
        return $this->children;
207
    }
208
    /**
209
     * @return string
210
     */
211
    abstract public function getPhpDeclaration();
212
    /**
213
     * defines authorized children element types
214
     * @return string[]
215
     */
216
    abstract public function getChildrenTypes();
217
    /**
218
     * @param int $indentation
219
     * @return string
220
     */
221 156
    private function getContextualLineBeforeChildren($indentation = null)
222
    {
223 156
        if ($this->useBracketsForChildren()) {
224 72
            $line = $this->getBracketBeforeChildren($indentation);
225 72
        } else {
226 128
            $line = $this->getLineBeforeChildren($indentation);
227
        }
228 156
        return $line;
229
    }
230
    /**
231
     * @param int $indentation
232
     * @return string
233
     */
234 156
    private function getContextualLineAfterChildren($indentation = null)
235
    {
236 156
        if ($this->useBracketsForChildren()) {
237 72
            $line = $this->getBracketAfterChildren($indentation);
238 72
        } else {
239 128
            $line = $this->getLineAfterChildren($indentation);
240
        }
241 156
        return $line;
242
    }
243
    /**
244
     * Allows to generate content before children content is generated
245
     * @param int $indentation
246
     * @return string
247
     */
248 128
    public function getLineBeforeChildren($indentation = null)
249
    {
250 128
        return '';
251
    }
252
    /**
253
     * Allows to generate content after children content is generated
254
     * @param int $indentation
255
     * @return string
256
     */
257 128
    public function getLineAfterChildren($indentation = null)
258
    {
259 128
        return '';
260
    }
261
    /**
262
     * Allows to indicate that children are contained by brackets,
263
     * in the case the method returns true, getBracketBeforeChildren
264
     * is called instead of getLineBeforeChildren and getBracketAfterChildren
265
     * is called instead of getLineAfterChildren, but be aware that these methods
266
     * call the two others
267
     * @return boolean
268
     */
269 124
    public function useBracketsForChildren()
270
    {
271 124
        return false;
272
    }
273
    /**
274
     * Allows to generate content before children content is generated
275
     * @param int $indentation
276
     * @return string
277
     */
278 72
    public function getBracketBeforeChildren($indentation = null)
279
    {
280 72
        $line = $this->getIndentedString(self::OPEN_BRACKET, $indentation);
281 72
        $this->setIndentation(($indentation === null ? $this->getIndentation() : $indentation) + 1);
282 72
        return $line;
283
    }
284
    /**
285
     * Allows to generate content after children content is generated
286
     * @param int $indentation
287
     * @return string
288
     */
289 72
    public function getBracketAfterChildren($indentation = null)
290
    {
291 72
        $this->setIndentation(($indentation === null ? $this->getIndentation() : $indentation) - 1);
292 72
        return $this->getIndentedString(self::CLOSE_BRACKET, $indentation);
293
    }
294
    /**
295
     * @param int $indentation
296
     * @return AbstractElement
297
     */
298 72
    public function setIndentation($indentation)
299
    {
300 72
        $this->indentation = $indentation;
301 72
        return $this;
302
    }
303
    /**
304
     * @return int
305
     */
306 156
    public function getIndentation()
307
    {
308 156
        return $this->indentation;
309
    }
310
    /**
311
     * @see \WsdlToPhp\PhpGenerator\Element\GenerableInterface::getIndentationString()
312
     * @param int $indentation
313
     * @return string
314
     */
315 156
    public function getIndentationString($indentation = null)
316
    {
317 156
        return str_repeat(self::INDENTATION_CHAR, $indentation === null ? $this->getIndentation() : $indentation);
318
    }
319
    /**
320
     * @param string $string
321
     * @param int $indentation
322
     * @return string
323
     */
324 156
    public function getIndentedString($string, $indentation = null)
325
    {
326 156
        $strings = explode(self::BREAK_LINE_CHAR, $string);
327 156
        foreach ($strings as $i => $s) {
328 156
            $strings[$i] = sprintf('%s%s', $this->getIndentationString($indentation), $s);
329 156
        }
330 156
        return implode(self::BREAK_LINE_CHAR, $strings);
331
    }
332
    /**
333
     * @return string
334
     */
335 48
    final public function getCalledClass()
336
    {
337 48
        return substr(get_called_class(), strrpos(get_called_class(), '\\') + 1);
338
    }
339
}
340