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

ClassMetadata::hasMethod()   D

Complexity

Conditions 9
Paths 11

Size

Total Lines 29
Code Lines 11

Duplication

Lines 29
Ratio 100 %

Code Coverage

Tests 0
CRAP Score 90

Importance

Changes 0
Metric Value
dl 29
loc 29
ccs 0
cts 19
cp 0
rs 4.909
c 0
b 0
f 0
cc 9
eloc 11
nc 11
nop 2
crap 90
1
<?php
2
/*
3
 * This file is part of the Abstract builder package, an RunOpenCode project.
4
 *
5
 * (c) 2017 RunOpenCode
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace RunOpenCode\AbstractBuilder\Ast\Metadata;
11
12
use PhpParser\Node\Stmt\Class_;
13
use RunOpenCode\AbstractBuilder\Exception\InvalidArgumentException;
14
use RunOpenCode\AbstractBuilder\Exception\RuntimeException;
15
use RunOpenCode\AbstractBuilder\Utils\ClassUtils;
16
17
/**
18
 * Class ClassMetadata
19
 *
20
 * @package RunOpenCode\AbstractBuilder\Ast\Metadata
21
 */
22
class ClassMetadata
23
{
24
    /**
25
     * @var string
26
     */
27
    private $name;
28
29
    /**
30
     * @var ClassMetadata
31
     */
32
    private $parent;
33
34
    /**
35
     * @var TraitMetadata[]
36
     */
37
    private $traits;
38
39
    /**
40
     * @var bool
41
     */
42
    private $final;
43
44
    /**
45
     * @var bool
46
     */
47
    private $abstract;
48
49
    /**
50
     * @var MethodMetadata[]
51
     */
52
    private $methods;
53
54
    /**
55
     * @var Class_
56
     */
57
    private $ast;
58
59
    /**
60
     * ClassMetadata constructor.
61
     *
62
     * @param string $name
63
     * @param ClassMetadata|null $parent
64
     * @param bool $final
65
     * @param bool $abstract
66
     * @param MethodMetadata[] $methods
67
     * @param Class_ $ast
68
     */
69
    public function __construct($name, ClassMetadata $parent = null, array $traits = [], $final = false, $abstract = false, array $methods = [], Class_ $ast = null)
70
    {
71
        $this->name = trim($name, '\\');
72
73
        if (!ClassUtils::isClassNameValid($this->name)) {
74
            throw new InvalidArgumentException(sprintf('Provided class name "%s" is not valid PHP class name.', $this->name));
75
        }
76
77
        $this->parent = $parent;
78
        $this->traits = $traits;
79
        $this->final = $final;
80
        $this->abstract = $abstract;
81
        $this->methods = $methods;
82
        $this->ast = $ast;
83
    }
84
85
    /**
86
     * @return string
87
     */
88
    public function getName()
89
    {
90
        return $this->name;
91
    }
92
93
    /**
94
     * @return bool
95
     */
96
    public function isAutoloadable()
97
    {
98
        return class_exists($this->getName(), true);
99
    }
100
101
    /**
102
     * Check if class inherits some other class.
103
     *
104
     * @return bool
105
     */
106
    public function hasParent()
107
    {
108
        return null !== $this->parent;
109
    }
110
111
    /**
112
     * @return ClassMetadata|null
113
     */
114
    public function getParent()
115
    {
116
        return $this->parent;
117
    }
118
119
    /**
120
     * @return bool
121
     */
122
    public function hasTraits()
123
    {
124
        return count($this->traits) > 0;
125
    }
126
127
    /**
128
     * @return TraitMetadata[]
129
     */
130
    public function getTraits()
131
    {
132
        return $this->traits;
133
    }
134
135
    /**
136
     * @return bool
137
     */
138
    public function isFinal()
139
    {
140
        return $this->final;
141
    }
142
143
    /**
144
     * @return bool
145
     */
146
    public function isAbstract()
147
    {
148
        return $this->abstract;
149
    }
150
151
    /**
152
     * @return MethodMetadata[]
153
     */
154
    public function getMethods()
155
    {
156
        return $this->methods;
157
    }
158
159
    /**
160
     * Check if class has method, with optional inheritance tree and trait traverse.
161
     *
162
     * @param string $name
163
     * @param bool $traverse
164
     *
165
     * @return bool
166
     */
167 View Code Duplication
    public function hasMethod($name, $traverse = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
168
    {
169
        foreach ($this->methods as $method) {
170
171
            if ($name === $method->getName()) {
172
                return true;
173
            }
174
        }
175
176
        if ($traverse && $this->hasTraits()) {
177
178
            /**
179
             * @var TraitMetadata $trait
180
             */
181
            foreach ($this->traits as $trait) {
182
183
                if ($trait->hasMethod($name, $traverse)) {
184
                    return true;
185
                }
186
            }
187
        }
188
189
190
        if ($traverse && $this->hasParent()) {
191
            return $this->getParent()->hasMethod($name, $traverse);
192
        }
193
194
        return false;
195
    }
196
197
    /**
198
     * Check if class has public method, with optional inheritance tree and trait traverse.
199
     *
200
     * @param string $name
201
     * @param bool $traverse
202
     *
203
     * @return bool
204
     */
205 View Code Duplication
    public function hasPublicMethod($name, $traverse = true)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
206
    {
207
        foreach ($this->methods as $method) {
208
209
            if ($name === $method->getName()) {
210
                return $method->isPublic();
211
            }
212
        }
213
214
        if ($traverse && $this->hasTraits()) {
215
216
            /**
217
             * @var TraitMetadata $trait
218
             */
219
            foreach ($this->traits as $trait) {
220
221
                if ($trait->hasPublicMethod($name, $traverse)) {
222
                    return true;
223
                }
224
            }
225
        }
226
227
        if ($traverse && $this->hasParent()) {
228
            return $this->getParent()->hasPublicMethod($name, $traverse);
229
        }
230
231
        return false;
232
    }
233
234
    /**
235
     * Get public method for class, with optional inheritance tree and trait traverse.
236
     *
237
     * @param string $name
238
     * @param bool $traverse
239
     *
240
     * @return MethodMetadata
241
     *
242
     * @throws \RunOpenCode\AbstractBuilder\Exception\RuntimeException
243
     */
244
    public function getPublicMethod($name, $traverse = true)
245
    {
246 View Code Duplication
        foreach ($this->methods as $method) {
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...
247
248
            if ($name === $method->getName()) {
249
250
                if ($method->isPublic()) {
251
                    return $method;
252
                }
253
254
                throw new RuntimeException(sprintf('Method "%s()" for class "%s" exists, but it is not public.', $name, $this->name));
255
            }
256
        }
257
258 View Code Duplication
        if ($traverse && $this->hasTraits()) {
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...
259
260
            /**
261
             * @var TraitMetadata $trait
262
             */
263
            foreach ($this->traits as $trait) {
264
265
                if ($trait->hasPublicMethod($name, $traverse)) {
266
                    return $trait->getPublicMethod($name, $traverse);
267
                }
268
            }
269
        }
270
271
        if ($traverse && $this->hasParent() && $this->getParent()->hasPublicMethod($name, $traverse)) {
272
            return $this->getParent()->getPublicMethod($name, $traverse);
273
        }
274
275
        throw new RuntimeException(sprintf('Method "%s()" for class "%s" does not exists.', $name, $this->name));
276
    }
277
278
    /**
279
     * @return Class_
280
     */
281
    public function getAst()
282
    {
283
        return $this->ast;
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     */
289
    public function __toString()
290
    {
291
        return $this->getName();
292
    }
293
294
    /**
295
     * Initialize new, non-existing class.
296
     *
297
     * @param string $name
298
     *
299
     * @return ClassMetadata|static $this
300
     */
301
    public static function create($name)
302
    {
303
        return new static($name);
304
    }
305
306
    /**
307
     * Clones original metadata object, with possible values overwrite
308
     *
309
     * @param ClassMetadata $original
310
     * @param array $overwrite
311
     *
312
     * @return ClassMetadata|static $this
313
     */
314
    public static function clone(ClassMetadata $original, array $overwrite = [])
315
    {
316
        $data = [
317
            'name' => $original->getName(),
318
            'parent' => $original->getParent(),
319
            'traits' => $original->getTraits(),
320
            'final' => $original->isFinal(),
321
            'abstract ' => $original->isAbstract(),
322
            'methods' => $original->getMethods(),
323
            'ast' => $original->getAst(),
324
        ];
325
326
        $data = array_merge($data, $overwrite);
327
328
        return (new \ReflectionClass(static::class))->newInstanceArgs(array_values($data));
329
    }
330
}
331