Passed
Branch php-scrutinizer (0ac9d8)
by Jens
09:19
created

ReflectedClass::reflectUseStatements()   C

Complexity

Conditions 12
Paths 8

Size

Total Lines 30
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 0
cts 30
cp 0
rs 5.1612
c 0
b 0
f 0
cc 12
eloc 22
nc 8
nop 0
crap 156

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author @jenschude <[email protected]>
4
 */
5
6
namespace Commercetools\Core\Helper\Annotate;
7
8
/**
9
 * @package Commercetools\Core\Helper\Annotate
10
 */
11
class ReflectedClass
12
{
13
    /**
14
     * @var bool
15
     */
16
    protected $abstract;
17
18
    protected $fileName;
19
20
    protected $className;
21
    protected $shortClassName;
22
23
    protected $namespace;
24
    protected $uses = [];
25
    protected $methods = [];
26
    protected $magicGetSetMethods = [];
27
    protected $docBlockLines = [];
28
29
    protected $constructorArgs = [];
30
31
    public function __construct($className)
32
    {
33
        $this->className = $className;
34
        $this->reflectClass();
35
        $this->reflectUseStatements();
36
        $this->reflectDocBlock();
37
        $this->reflectConstructorArgs();
38
    }
39
40
    public function addMagicGetSetMethod(
41
        $type,
42
        $fieldName,
43
        $args,
44
        $returnTypeHint = null,
45
        $returnsReference = null,
46
        $shortDescription = null
47
    ) {
48
        $name = $type . ucfirst($fieldName);
49
        if ($this->hasMethod($name)) {
50
            return;
51
        }
52
53
        $magicMethod = [
54
            'name' => $name,
55
            'returnTypeHint' => $returnTypeHint,
56
            'returnsReference' => $returnsReference,
57
            'type' => $type,
58
            'fieldName' => $fieldName,
59
            'args' => $args,
60
            'shortDescription' => $shortDescription
61
        ];
62
63
        if (isset($this->magicGetSetMethods[$name])) {
64
            $magicMethod = array_merge($this->magicGetSetMethods[$name], $magicMethod);
65
        }
66
67
        $this->magicGetSetMethods[$name] = $magicMethod;
68
    }
69
70
    public function addMagicMethod(
71
        $methodName,
72
        $args,
73
        $returnTypeHint = null,
74
        $returnsReference = null,
75
        $shortDescription = null,
76
        $static = false,
77
        $force = false
78
    ) {
79
        if (!$force && $this->hasMethod($methodName)) {
80
            return;
81
        }
82
83
        $magicMethod = [
84
            'name' => $methodName,
85
            'returnTypeHint' => $returnTypeHint,
86
            'returnsReference' => $returnsReference,
87
            'args' => $args,
88
            'shortDescription' => $shortDescription,
89
            'static' => $static
90
        ];
91
92
        if (isset($this->magicGetSetMethods[$methodName])) {
93
            $magicMethod = array_merge($this->magicGetSetMethods[$methodName], $magicMethod);
94
        }
95
96
        $this->magicGetSetMethods[$methodName] = $magicMethod;
97
    }
98
99
    public function hasMethod($methodName)
100
    {
101
        return isset($this->methods[$methodName]);
102
    }
103
104
    public function hasMagicGetSetMethod($methodName)
105
    {
106
        return isset($this->magicGetSetMethods[$methodName]);
107
    }
108
109
    public function getMethod($methodName)
110
    {
111
        if ($this->hasMethod($methodName)) {
112
            return $this->methods[$methodName];
113
        }
114
        return false;
115
    }
116
117
    public function getMagicGetSetMethod($methodName)
118
    {
119
        if ($this->hasMethod($methodName)) {
120
            return $this->magicGetSetMethods[$methodName];
121
        }
122
        return false;
123
    }
124
125
    /**
126
     * @return array
127
     */
128
    public function getConstructorArgs()
129
    {
130
        return $this->constructorArgs;
131
    }
132
133
    /**
134
     * @param $className
135
     * @param $alias
136
     */
137
    public function addUse($className, $alias = null)
138
    {
139
        $className = trim($className, '\\');
140
        try {
141
            $reflect = new \ReflectionClass($className);
142
        } catch (\ReflectionException $e) {
143
            return;
144
        }
145
        if ($reflect->getNamespaceName() !== $this->namespace && !isset($this->uses[$className])) {
146
            $this->uses[$className] = [
147
                'class' => $className,
148
                'alias' => $alias
149
            ];
150
        }
151
    }
152
153
    protected function reflectClass()
154
    {
155
        $reflectionClass = new \ReflectionClass($this->getClassName());
156
        $this->shortClassName = $reflectionClass->getShortName();
157
        $this->namespace = $reflectionClass->getNamespaceName();
158
        $this->fileName = $reflectionClass->getFileName();
159
        $this->abstract = $reflectionClass->isAbstract();
160
161
        $methods = [];
162
        foreach ($reflectionClass->getMethods() as $method) {
163
            $methods[$method->name] = $method;
164
        }
165
        $this->methods = $methods;
166
    }
167
168
    protected function reflectUseStatements()
169
    {
170
        $content = file_get_contents($this->getFileName());
171
        $tokens = token_get_all($content);
172
        for ($index = 0; isset($tokens[$index]); $index++) {
173
            if (!isset($tokens[$index][0])) {
174
                continue;
175
            }
176
            if (T_USE == $tokens[$index][0]) {
177
                $use = '';
178
                $index += 2;
179
                while ($tokens[$index][0] != T_AS && isset($tokens[$index]) && is_array($tokens[$index])) {
180
                    if ($tokens[$index][0] == T_WHITESPACE) {
181
                        $index++;
182
                        continue;
183
                    }
184
                    $use .= $tokens[$index++][1];
185
                }
186
                $alias = null;
187
                if ($tokens[$index][0] == T_AS) {
188
                    $alias = '';
189
                    $index += 2;
190
                    while (isset($tokens[$index]) && is_array($tokens[$index])) {
191
                        $alias .= $tokens[$index++][1];
192
                    }
193
                }
194
                $this->addUse($use, $alias);
195
            }
196
            if (T_CLASS == $tokens[$index][0]) {
197
                break;
198
            }
199
        }
200
    }
201
202
    protected function reflectDocBlock()
203
    {
204
        $reflectionClass = new \ReflectionClass($this->getClassName());
205
        $docBlock = $reflectionClass->getDocComment();
206
207
        $docBlockLines = explode(PHP_EOL, $docBlock);
208
209
        $lines = [];
210
        foreach ($docBlockLines as $line) {
211
            if ($this->skipDocBlockLine($line)) {
212
                continue;
213
            } elseif (preg_match($this->getMethodPattern(), $line, $matches)) {
214
                $this->reflectMagicMethods($matches);
215
            } else {
216
                $lines[] = trim(preg_replace('/^ \*/', '', $line));
217
            }
218
        }
219
220
        $this->docBlockLines = $lines;
221
    }
222
223
    protected function reflectConstructorArgs()
224
    {
225
        $reflectionClass = new \ReflectionClass($this->getClassName());
226
        $constructor = $reflectionClass->getConstructor();
227
        $parameters = $constructor->getParameters();
228
229
        $args = [];
230
        foreach ($parameters as $parameter) {
231
            if ($parameter->isOptional()) {
232
                continue;
233
            }
234
            $typeClass = $parameter->getClass();
235
            $typeName = '';
236
            if (!is_null($typeClass)) {
237
                $typeName = $typeClass->getShortName();
238
            }
239
            $args[] = trim($typeName . ' $' . $parameter->getName());
240
        }
241
        $this->constructorArgs = $args;
242
    }
243
244
    /**
245
     * @param $type
246
     * @param $fieldName
247
     * @return string
248
     */
249
    protected function getMethodName($type, $fieldName)
250
    {
251
        return $type . ucfirst($fieldName);
252
    }
253
254
    protected function reflectMagicMethods($matches)
255
    {
256
        list(, $static, $returnTypeHint, $returnsReference, $name, $args, $shortDescription) = $matches;
257
        $type = $fieldName = '';
258
        if (preg_match('~^(set|get)(.*)~', $name, $matches)) {
259
            $type = $matches[1];
260
            $fieldName = $matches[2];
261
        }
262
        $args = array_map('trim', explode(',', $args));
263
        if (empty($type) || !$this->hasMethod($name)) {
264
            $this->magicGetSetMethods[$name] = [
265
                'name' => $name,
266
                'returnTypeHint' => $returnTypeHint,
267
                'returnsReference' => $returnsReference,
268
                'type' => $type,
269
                'fieldName' => $fieldName,
270
                'args' => $args,
271
                'static' => ($static === 'static'),
272
                'shortDescription' => $shortDescription
273
            ];
274
        }
275
    }
276
277
    protected function skipDocBlockLine($line)
278
    {
279
        return (strpos($line, '/**') === 0)
280
            || (strpos($line, ' */') === 0)
281
            || (strpos($line, '@package') > 0)
282
            || (strpos($line, '* Class') > 0);
283
    }
284
285
    /**
286
     * @return string
287
     */
288
    protected function getMethodPattern()
289
    {
290
        return '~@method (?:(static)\\s+)?(?:([\\w\\\\]+(?:\\|[\\w\\\\]+)*)\\s+)?' .
291
            '(&)?\\s*(\\w+)\\s*\\(\\s*(.*)\\s*\\)\\s*(.*|$)~s';
292
    }
293
294
    /**
295
     * @return mixed
296
     */
297
    public function getClassName()
298
    {
299
        return $this->className;
300
    }
301
302
    /**
303
     * @return mixed
304
     */
305
    public function getNamespace()
306
    {
307
        return $this->namespace;
308
    }
309
310
    /**
311
     * @return mixed
312
     */
313
    public function getUses()
314
    {
315
        return $this->uses;
316
    }
317
318
    /**
319
     * @return mixed
320
     */
321
    public function getMethods()
322
    {
323
        return $this->methods;
324
    }
325
326
    /**
327
     * @return mixed
328
     */
329
    public function getMagicGetSetMethods()
330
    {
331
        return $this->magicGetSetMethods;
332
    }
333
334
    /**
335
     * @return array
336
     */
337
    public function getDocBlockLines()
338
    {
339
        return $this->docBlockLines;
340
    }
341
342
    /**
343
     * @return mixed
344
     */
345
    public function getFileName()
346
    {
347
        return $this->fileName;
348
    }
349
350
    /**
351
     * @return bool
352
     */
353
    public function isAbstract()
354
    {
355
        return $this->abstract;
356
    }
357
358
    /**
359
     * @return mixed
360
     */
361
    public function getShortClassName()
362
    {
363
        return $this->shortClassName;
364
    }
365
}
366