Completed
Push — master ( ed922a...ce73d9 )
by Nikola
03:26
created

ClassMetadata::getConstructor()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 15
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 0
cts 12
cp 0
rs 9.2
c 0
b 0
f 0
cc 4
eloc 7
nc 5
nop 0
crap 20
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;
11
12
use RunOpenCode\AbstractBuilder\Exception\InvalidArgumentException;
13
14
/**
15
 * Class ClassMetadata
16
 *
17
 * @package RunOpenCode\AbstractBuilder\Ast
18
 */
19
class ClassMetadata
20
{
21
    /**
22
     * @var array
23
     */
24
    private $ast;
25
26
    /**
27
     * @var string
28
     */
29
    private $namespace;
30
31
    /**
32
     * @var string
33
     */
34
    private $class;
35
36
    /**
37
     * @var string
38
     */
39
    private $fqcn;
40
41
    /**
42
     * @var string
43
     */
44
    private $filename;
45
46
    /**
47
     * @var bool
48
     */
49
    private $final;
50
51
    /**
52
     * @var bool
53
     */
54
    private $abstract;
55
56
    /**
57
     * @var MethodMetadata[]
58
     */
59
    private $methods;
60
61
    /**
62
     * @var ClassMetadata
63
     */
64
    private $parent;
65
66
    /**
67
     * ClassMetadata constructor.
68
     *
69
     * @param $ast
70
     * @param string $namespace
71
     * @param string $class
72
     * @param null|string $filename
73
     * @param bool $final
74
     * @param bool $abstract
75
     * @param MethodMetadata[] $methods
76
     *
77
     * @throws \RunOpenCode\AbstractBuilder\Exception\InvalidArgumentException
78
     */
79
    public function __construct($ast, $namespace, $class, $filename = null, $final = false, $abstract = false, array $methods = [], ClassMetadata $parent = null)
80
    {
81
        $this->ast = $ast;
82
        $this->namespace = trim($namespace, '\\');
83
        $this->class = trim($class, '\\');
84
        $this->filename = $filename;
85
        $this->final = $final;
86
        $this->abstract = $abstract;
87
        $this->methods = $methods;
88
        $this->parent = $parent;
89
90
        $this->fqcn = '\\'.$this->class;
91
92
        if ($this->namespace) {
93
            $this->fqcn = '\\'.$this->namespace.'\\'.$this->class;
94
        }
95
96
97
        foreach (explode('\\', ltrim($this->fqcn, '\\')) as $part) {
98
99
            if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $part)) {
100
                throw new InvalidArgumentException(sprintf('Provided full qualified class name "%s" is not valid PHP class name.', $this->fqcn));
101
            }
102
        }
103
    }
104
105
    /**
106
     * @return
107
     */
108
    public function getAst()
109
    {
110
        return $this->ast;
111
    }
112
113
    /**
114
     * @return string
115
     */
116
    public function getNamespace()
117
    {
118
        return $this->namespace;
119
    }
120
121
    /**
122
     * @return string
123
     */
124
    public function getClass()
125
    {
126
        return $this->class;
127
    }
128
129
    /**
130
     * @return string
131
     */
132
    public function getFqcn()
133
    {
134
        return $this->fqcn;
135
    }
136
137
    /**
138
     * @return string
139
     */
140
    public function getFilename()
141
    {
142
        return $this->filename;
143
    }
144
145
    /**
146
     * @return bool
147
     */
148
    public function isFinal()
149
    {
150
        return $this->final;
151
    }
152
153
    /**
154
     * @return bool
155
     */
156
    public function isAbstract()
157
    {
158
        return $this->abstract;
159
    }
160
161
    /**
162
     * @return MethodMetadata[]
163
     */
164
    public function getMethods()
165
    {
166
        return $this->methods;
167
    }
168
169
    /**
170
     * @return MethodMetadata|null
171
     */
172
    public function getConstructor()
173
    {
174
        foreach ($this->methods as $method) {
175
176
            if ('__construct' === $method->getName()) {
177
                return $method;
178
            }
179
        }
180
181
        if (null !== $this->parent) {
182
            return $this->parent->getConstructor();
183
        }
184
185
        return null;
186
    }
187
188
    /**
189
     * Check if class inherits some other class.
190
     *
191
     * @return bool
192
     */
193
    public function hasParent()
194
    {
195
        return null !== $this->parent;
196
    }
197
198
    /**
199
     * @return ClassMetadata|null
200
     */
201
    public function getParent()
202
    {
203
        return $this->parent;
204
    }
205
206
    /**
207
     * Check if class has public method, with optional tree traverse.
208
     *
209
     * @param string $name
210
     * @param bool $traverse
211
     *
212
     * @return bool
213
     */
214
    public function hasPublicMethod($name, $traverse = true)
215
    {
216
        foreach ($this->methods as $method) {
217
218
            if ($method->isPublic() && $name === $method->getName()) {
219
                return true;
220
            }
221
        }
222
223
        if ($traverse && $this->hasParent()) {
224
            return $this->getParent()->hasPublicMethod($name, $traverse);
225
        }
226
227
        return false;
228
    }
229
230
    /**
231
     * @return bool
232
     */
233
    public function isAutoloadable()
234
    {
235
        return class_exists($this->getFqcn(), true);
236
    }
237
238
    /**
239
     * {@inheritdoc}
240
     */
241
    public function __toString()
242
    {
243
        return $this->getFqcn();
244
    }
245
246
    /**
247
     * Initialize new, non-existing class.
248
     *
249
     * @param string $fqcn
250
     *
251
     * @return ClassMetadata|static $this
252
     */
253
    public static function create($fqcn)
254
    {
255
        $parts = explode('\\', trim($fqcn, '\\'));
256
        $class = array_pop($parts);
257
        $namespace = implode('\\', $parts);
258
259
        return new static([], $namespace, $class);
260
    }
261
262
    /**
263
     * Clones original metadata object, with possible values overwrite
264
     *
265
     * @param ClassMetadata $original
266
     * @param array $overwrite
267
     *
268
     * @return ClassMetadata|static $this
269
     */
270
    public static function clone(ClassMetadata $original, array $overwrite = [])
271
    {
272
        $data = [
273
            'ast' => $original->getAst(),
274
            'namespace' => $original->getNamespace(),
275
            'class' => $original->getClass(),
276
            'filename' => $original->getFilename(),
277
            'final' => $original->isFinal(),
278
            'abstract ' => $original->isAbstract(),
279
            'methods' => $original->getMethods(),
280
            'parent' => $original->getParent()
281
        ];
282
283
        $data = array_merge($data, $overwrite);
284
285
        return (new \ReflectionClass(static::class))->newInstanceArgs(array_values($data));
286
    }
287
}
288