Completed
Push — master ( 556a60...b1e8a1 )
by Nikola
02:34
created

getMethodsMetadata()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
dl 0
loc 13
ccs 0
cts 10
cp 0
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 6
nc 3
nop 1
crap 12
1
<?php
2
3
namespace RunOpenCode\AbstractBuilder\Ast\Visitor;
4
5
use PhpParser\Node;
6
use PhpParser\NodeVisitorAbstract;
7
use PhpParser\Node\Stmt;
8
use RunOpenCode\AbstractBuilder\Ast\Metadata\ClassMetadata;
9
use RunOpenCode\AbstractBuilder\Ast\Metadata\FileMetadata;
10
use RunOpenCode\AbstractBuilder\Ast\Metadata\MethodMetadata;
11
use RunOpenCode\AbstractBuilder\Ast\Metadata\TraitMetadata;
12
use RunOpenCode\AbstractBuilder\Ast\MetadataLoader;
13
use RunOpenCode\AbstractBuilder\Utils\MethodUtils;
14
15
/**
16
 * Class FileMetadataIntrospectionVisitor
17
 *
18
 * @package RunOpenCode\AbstractBuilder\Ast\Visitor
19
 */
20
class FileMetadataIntrospectionVisitor extends NodeVisitorAbstract
21
{
22
    /**
23
     * @var string
24
     */
25
    private $filename;
26
27
    /**
28
     * @var array
29
     */
30
    private $uses;
31
32
    /**
33
     * @var ClassMetadata[]
34
     */
35
    private $classes;
36
37
    /**
38
     * @var TraitMetadata[]
39
     */
40
    private $traits;
41
42
    /**
43
     * @var array
44
     */
45
    private $ast;
46
47
    /**
48
     * @var FileMetadata
49
     */
50
    private $metadata;
51
52
    /**
53
     * @var array
54
     */
55
    private $stack = [];
56
57
    public function __construct($filename)
58
    {
59
        $this->filename = $filename;
60
    }
61
62
    /**
63
     * {@inheritDoc}
64
     *
65
     * Cleans up internal state
66
     *
67
     * @param array $nodes
68
     */
69
    public function beforeTraverse(array $nodes)
70
    {
71
        $this->metadata = null;
72
        $this->uses = [];
73
        $this->classes = [];
74
        $this->traits = [];
75
        $this->ast = $nodes;
76
77
        $this->stack = [
78
            'trait_use' => []
79
        ];
80
    }
81
82
    public function enterNode(Node $node)
83
    {
84
        if ($node instanceof Stmt\Class_ && !$node->isAnonymous()) {
85
            $this->stack['trait_use'] = [];
86
        }
87
88
        if ($node instanceof Stmt\Trait_) {
89
            $this->stack['trait_use'] = [];
90
        }
91
92
        if ($node instanceof Stmt\TraitUse) {
93
            $this->processTraitUse($node);
94
        }
95
    }
96
97
    public function leaveNode(Node $node)
98
    {
99
        if ($node instanceof Stmt\Class_ && !$node->isAnonymous()) {
100
            $name = (string) $node->namespacedName;
101
            $this->classes[$name] = new ClassMetadata($name, $this->getClassParentMetadata($node), $this->stack['trait_use'], $node->isFinal(), $node->isAbstract(), $this->getMethodsMetadata($node), $node);
102
        }
103
104
        if ($node instanceof Stmt\Trait_) {
105
            $name = (string) $node->namespacedName;
106
            $this->traits[$name] = new TraitMetadata($name, $this->stack['trait_use'], $this->getMethodsMetadata($node), $node);
107
        }
108
    }
109
110
    public function afterTraverse(array $nodes)
111
    {
112
        $this->metadata = new FileMetadata($this->filename, $this->uses, $this->classes, $this->traits, $this->ast);
113
    }
114
115
    /**
116
     * @return FileMetadata
117
     */
118
    public function getMetadata()
119
    {
120
        return $this->metadata;
121
    }
122
123
    /**
124
     * Load class parent.
125
     *
126
     * @param Stmt\Class_ $class
127
     *
128
     * @return null|ClassMetadata
129
     */
130
    private function getClassParentMetadata(Stmt\Class_ $class)
131
    {
132
        if (null !== $class->extends) {
133
134
            $name = $class->extends->toString();
135
136
            /**
137
             * @var FileMetadata $filemetadata
138
             */
139
            $filemetadata = (new MetadataLoader())->load($name);
140
141
            return $filemetadata->getClasses()[$name];
142
        }
143
144
        return null;
145
    }
146
147
    private function getTraitMetadata($name)
148
    {
149
        $filemetadata = (new MetadataLoader())->load($name);
150
        return $filemetadata->getTraits()[$name];
151
    }
152
153
    /**
154
     * Process class methods
155
     *
156
     * @param Stmt\ClassLike $classLike
157
     *
158
     * @return MethodMetadata[]
159
     */
160
    private function getMethodsMetadata(Stmt\ClassLike $classLike)
161
    {
162
        $methods = [];
163
164
        foreach ($classLike->stmts as $stmt) {
165
166
            if ($stmt instanceof Stmt\ClassMethod) {
167
                $methods[] = MethodMetadata::fromClassMethod($stmt);
168
            }
169
        }
170
171
        return $methods;
172
    }
173
174
    /**
175
     * Process trait use declaration and drop on working stack.
176
     *
177
     * @param Stmt\TraitUse $node
178
     */
179
    private function processTraitUse(Stmt\TraitUse $node)
180
    {
181
        $traitMetadata = $this->getTraitMetadata((string)$node->traits[0]);
182
183
        $methods = [];
184
185
        foreach ($traitMetadata->getMethods() as $method) {
186
            $methods[$method->getName()] = $method;
187
        }
188
189
        /**
190
         * @var Stmt\TraitUseAdaptation\Alias $adaptation
191
         */
192
        foreach ($node->adaptations as $adaptation) {
193
            /**
194
             * @var MethodMetadata $original
195
             */
196
            $original = $methods[$adaptation->method];
197
198
            $methods[$adaptation->newName] = new MethodMetadata(
199
                $adaptation->newName,
200
                $original->isAbstract(),
201
                $original->isFinal(),
202
                MethodUtils::getVisibility($adaptation->newModifier, $original->getVisibility()),
203
                $original->getReturnType(),
204
                $original->byReference(),
205
                $original->isStatic(),
206
                $original->getParameters(),
207
                $original->getAst()
208
            );
209
210
            unset($methods[$original->getName()]);
211
        }
212
213
        $this->stack['trait_use'][] = new TraitMetadata($traitMetadata->getName(), $traitMetadata->getTraits(), $methods, $traitMetadata->getAst());
214
    }
215
}
216
217