AnnotationScanner::finalize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 3
rs 10
cc 1
eloc 1
nc 1
nop 0
1
<?php
2
/**
3
 * Scabbia2 Scanners Component
4
 * https://github.com/eserozvataf/scabbia2
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 *
9
 * @link        https://github.com/eserozvataf/scabbia2-scanners for the canonical source repository
10
 * @copyright   2010-2016 Eser Ozvataf. (http://eser.ozvataf.com/)
11
 * @license     http://www.apache.org/licenses/LICENSE-2.0 - Apache License, Version 2.0
12
 */
13
14
namespace Scabbia\Scanners;
15
16
use Scabbia\Scanners\ScannerInterface;
17
use Scabbia\Scanners\TokenStream;
18
use LogicException;
19
use ReflectionClass;
20
21
/**
22
 * canner
23
 *
24
 * @package     Scabbia\Scanners
25
 * @author      Eser Ozvataf <[email protected]>
26
 * @since       2.0.0
27
 */
28
class AnnotationScanner implements ScannerInterface
29
{
30
    /** @type array       $result      result of scanning task */
31
    public $result = [];
32
    /** @type array       $ignoreList  annotations to be ignored */
33
    public $ignoreList = [
34
        "link",
35
        "copyright",
36
        "license",
37
        "package",
38
        "author",
39
        "since",
40
        "type",
41
        "param",
42
        "return",
43
        "throws",
44
        "todo",
45
        "see",
46
        "ignore"
47
    ];
48
49
50
    /**
51
     * Scans a file
52
     *
53
     * @param string           $uFile             file path
54
     * @param string           $uFileContents     contents of file
55
     *
56
     * @return void
57
     */
58
    public function processFile($uFile, $uFileContents)
59
    {
60
    }
61
62
    /**
63
     * Scans a token stream
64
     *
65
     * @param TokenStream      $uTokenStream      extracted tokens wrapped with tokenstream
66
     *
67
     * @return void
68
     */
69
    public function processTokenStream(TokenStream $uTokenStream)
70
    {
71
    }
72
73
    /**
74
     * Processes classes using reflection
75
     *
76
     * @param string           $uClass            class name
77
     * @param ReflectionClass  $uReflection       reflection information for the class
78
     *
79
     * @return void
80
     */
81
    public function processClass($uClass, ReflectionClass $uReflection)
82
    {
83
        $tClassAnnotations = [];
84
85
        $tDocComment = $uReflection->getDocComment();
86
        if (strlen($tDocComment) > 0) {
87
            $tParsedAnnotations = $this->parseAnnotations($tDocComment);
88
            if (count($tParsedAnnotations) > 0) {
89
                $tClassAnnotations["class"] = ["self" => $tParsedAnnotations];
90
            }
91
        }
92
93
        // methods
94 View Code Duplication
        foreach ($uReflection->getMethods() as $tMethodReflection) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
95
            // TODO check the correctness of logic
96
            if ($tMethodReflection->class !== $uClass) {
97
                continue;
98
            }
99
100
            $tDocComment = $tMethodReflection->getDocComment();
101
            if (strlen($tDocComment) > 0) {
102
                $tParsedAnnotations = $this->parseAnnotations($tDocComment);
103
104
                if (count($tParsedAnnotations) === 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
105
                    // nothing
106
                } elseif ($tMethodReflection->isStatic()) {
107
                    if (!isset($tClassAnnotations["staticMethods"])) {
108
                        $tClassAnnotations["staticMethods"] = [];
109
                    }
110
111
                    $tClassAnnotations["staticMethods"][$tMethodReflection->name] = $tParsedAnnotations;
112
                } else {
113
                    if (!isset($tClassAnnotations["methods"])) {
114
                        $tClassAnnotations["methods"] = [];
115
                    }
116
117
                    $tClassAnnotations["methods"][$tMethodReflection->name] = $tParsedAnnotations;
118
                }
119
            }
120
        }
121
122
        // properties
123 View Code Duplication
        foreach ($uReflection->getProperties() as $tPropertyReflection) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across 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...
124
            // TODO check the correctness of logic
125
            if ($tPropertyReflection->class !== $uClass) {
126
                continue;
127
            }
128
129
            $tDocComment = $tPropertyReflection->getDocComment();
130
            if (strlen($tDocComment) > 0) {
131
                $tParsedAnnotations = $this->parseAnnotations($tDocComment);
132
133
                if (count($tParsedAnnotations) === 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
134
                    // nothing
135
                } elseif ($tPropertyReflection->isStatic()) {
136
                    if (!isset($tClassAnnotations["staticProperties"])) {
137
                        $tClassAnnotations["staticProperties"] = [];
138
                    }
139
140
                    $tClassAnnotations["staticProperties"][$tPropertyReflection->name] = $tParsedAnnotations;
141
                } else {
142
                    if (!isset($tClassAnnotations["properties"])) {
143
                        $tClassAnnotations["properties"] = [];
144
                    }
145
146
                    $tClassAnnotations["properties"][$tPropertyReflection->name] = $tParsedAnnotations;
147
                }
148
            }
149
        }
150
151
        if (count($tClassAnnotations) > 0) {
152
            $this->result[$uClass] = $tClassAnnotations;
153
        } else {
154
            $this->result[$uClass] = null;
155
        }
156
    }
157
158
    /**
159
     * Finalizes the task
160
     *
161
     * @return void
162
     */
163
    public function finalize()
164
    {
165
    }
166
167
    /**
168
     * Parses the docblock and returns annotations in an array
169
     *
170
     * @param string $uDocComment docblock which contains annotations
171
     *
172
     * @return array set of annotations
173
     */
174
    protected function parseAnnotations($uDocComment)
175
    {
176
        preg_match_all(
177
            "/\\*[\\t| ]\\@([^\\n|\\t| ]+)(?:[\\t| ]([^\\n]+))*/",
178
            $uDocComment,
179
            $tDocCommentLines,
180
            PREG_SET_ORDER
181
        );
182
183
        $tParsedAnnotations = [];
184
185
        foreach ($tDocCommentLines as $tDocCommentLine) {
0 ignored issues
show
Bug introduced by
The expression $tDocCommentLines of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
186
            if (in_array($tDocCommentLine[1], $this->ignoreList)) {
187
                continue;
188
            }
189
190
            if (!isset($tParsedAnnotations[$tDocCommentLine[1]])) {
191
                $tParsedAnnotations[$tDocCommentLine[1]] = [];
192
            }
193
194
            if (isset($tDocCommentLine[2])) {
195
                $tParsedAnnotations[$tDocCommentLine[1]][] = trim($tDocCommentLine[2]);
196
            }
197
        }
198
199
        return $tParsedAnnotations;
200
    }
201
}
202