Completed
Push — master ( 93dd0d...2e24e7 )
by Tim
02:24
created

ReflectionUtility::getPropertyNames()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 5
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
/**
4
 * Reflection helper.
5
 */
6
declare(strict_types=1);
7
8
namespace HDNET\Autoloader\Utility;
9
10
use HDNET\Autoloader\Hooks\ClearCache;
11
use TYPO3\CMS\Core\Utility\GeneralUtility;
12
use TYPO3\CMS\Core\Utility\VersionNumberUtility;
13
use TYPO3\CMS\Extbase\Reflection\ClassReflection;
14
use TYPO3\CMS\Extbase\Reflection\MethodReflection;
15
use TYPO3\CMS\Extbase\Reflection\ReflectionService;
16
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
17
18
/**
19
 * Reflection helper.
20
 */
21
class ReflectionUtility
22
{
23
    /**
24
     * Create a new class reflection. Do not use the makeInstance or objectManager
25
     * because the reflection API is also used in front of the caching framework.
26
     *
27
     * @param string $className
28
     *
29
     * @return ClassReflection
30
     */
31
    public static function createReflectionClass($className)
32
    {
33
        return new ClassReflection($className);
34
    }
35
36
    /**
37
     * Check if the given class is instantiable.
38
     *
39
     * @param string $className
40
     *
41
     * @return bool
42
     */
43
    public static function isInstantiable($className):bool
44
    {
45
        if(self::is9orHigher()) {
46
            $reflectionClass = new \ReflectionClass($className);
47
            return (bool)$reflectionClass->isInstantiable();
48
        }
49
50
        return (bool)self::createReflectionClass($className)
51
            ->isInstantiable();
52
    }
53
54
    /**
55
     * Get the name of the parent class.
56
     *
57
     * @param string $className
58
     *
59
     * @return string
60
     */
61
    public static function getParentClassName($className)
62
    {
63
        if(self::is9orHigher()) {
64
            $reflectionClass = new \ReflectionClass($className);
65
            return $reflectionClass->getParentClass()->getName();
66
        }
67
        return self::createReflectionClass($className)
68
            ->getParentClass()
69
            ->getName();
70
    }
71
72
    /**
73
     * Get all properties that are tagged with the given tag.
74
     *
75
     * @param string $className
76
     * @param string $tag
77
     *
78
     * @return array
79
     */
80
    public static function getPropertiesTaggedWith($className, $tag)
81
    {
82
        $classReflection = self::createReflectionClass($className);
83
        $properties = [];
84
        foreach ($classReflection->getProperties() as $property) {
85
            /** @var \TYPO3\CMS\Extbase\Reflection\PropertyReflection $property */
86
            if ($property->isTaggedWith($tag)) {
87
                $properties[] = $property;
88
            }
89
        }
90
91
        return $properties;
92
    }
93
94
    /**
95
     * Get all properties that are tagged with the given tag.
96
     *
97
     * @param string $className
98
     * @param string $tag
99
     *
100
     * @return array
101
     */
102
    public static function getPropertyNamesTaggedWith($className, $tag):array
103
    {
104
        $properties = self::getPropertyNames($className);
105
        $return = [];
106
        foreach ($properties as $property) {
107
            $config = self::getTagConfigurationForProperty($className, $property, [$tag]);
108
            if(!empty($config[$tag])) {
109
                $return[] = $property;
110
            }
111
        }
112
        return $return;
113
    }
114
115
    /**
116
     * Get all public methods of the given class.
117
     *
118
     * @param string $className
119
     *
120
     * @return MethodReflection[]
121
     */
122
    public static function getPublicMethods($className)
123
    {
124
        return self::createReflectionClass($className)
125
            ->getMethods(\ReflectionMethod::IS_PUBLIC);
126
    }
127
128
    /**
129
     * Get first class tag information.
130
     * The trimmed value if the tag exists and FALSE if the tag do not exists.
131
     *
132
     * @param string $className
133
     * @param string $tag
134
     *
135
     * @return string|bool
136
     */
137
    public static function getFirstTagValue(string $className, string $tag)
138
    {
139
        if(self::is9orHigher()) {
140
            $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
141
            $values = $reflectionService->getClassTagValues($className, $tag);
142
        } else {
143
            $classReflection = self::createReflectionClass($className);
144
            if (!$classReflection->isTaggedWith($tag)) {
145
                return false;
146
            }
147
            $values = $classReflection->getTagValues($tag);
148
        }
149
150
        if (\is_array($values)) {
151
            return \trim((string) $values[0]);
152
        }
153
154
        return false;
155
    }
156
157
    /**
158
     * Get the tag configuration from this method and respect multiple line and space configuration.
159
     *
160
     * @param MethodReflection|ClassReflection $reflectionObject
161
     * @param array                            $tagNames
162
     *
163
     * @return array
164
     */
165
    public static function getTagConfiguration($reflectionObject, array $tagNames): array
166
    {
167
        $tags = $reflectionObject->getTagsValues();
168
        $configuration = [];
169
        foreach ($tagNames as $tagName) {
170
            $configuration[$tagName] = [];
171
            if (!\is_array($tags[$tagName])) {
172
                continue;
173
            }
174
            foreach ($tags[$tagName] as $c) {
175
                $configuration[$tagName] = \array_merge(
176
                    $configuration[$tagName],
177
                    GeneralUtility::trimExplode(' ', $c, true)
178
                );
179
            }
180
        }
181
182
        return $configuration;
183
    }
184
185
186
    /**
187
     * Get the tag configuration from this method and respect multiple line and space configuration.
188
     *
189
     * @param string $className
190
     * @param array                            $tagNames
191
     *
192
     * @return array
193
     */
194
    public static function getTagConfigurationForMethod($className, $methodName, array $tagNames): array
195
    {
196
        $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
197
        $tags = $reflectionService->getMethodTagsValues($className, $methodName);
198
199
        $configuration = [];
200
        foreach ($tagNames as $tagName) {
201
            $configuration[$tagName] = [];
202
            if (!\is_array($tags[$tagName])) {
203
                continue;
204
            }
205
            foreach ($tags[$tagName] as $c) {
206
                $configuration[$tagName] = \array_merge(
207
                    $configuration[$tagName],
208
                    GeneralUtility::trimExplode(' ', $c, true)
209
                );
210
            }
211
        }
212
213
        return $configuration;
214
    }
215
216
217
    /**
218
     * Get the tag configuration from this method and respect multiple line and space configuration.
219
     *
220
     * @param MethodReflection|ClassReflection $reflectionObject
0 ignored issues
show
Bug introduced by
There is no parameter named $reflectionObject. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
221
     * @param array                            $tagNames
222
     *
223
     * @return array
224
     */
225
    public static function getTagConfigurationForClass($className, array $tagNames): array
226
    {
227
        $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
228
        $tags = $reflectionService->getClassTagsValues($className);
229
230
        $configuration = [];
231
        foreach ($tagNames as $tagName) {
232
            $configuration[$tagName] = [];
233
            if (!\is_array($tags[$tagName])) {
234
                continue;
235
            }
236
            foreach ($tags[$tagName] as $c) {
237
                $configuration[$tagName] = \array_merge(
238
                    $configuration[$tagName],
239
                    GeneralUtility::trimExplode(' ', $c, true)
240
                );
241
            }
242
        }
243
244
        return $configuration;
245
    }
246
    /**
247
     * Get the tag configuration from this method and respect multiple line and space configuration.
248
     *
249
     * @param MethodReflection|ClassReflection $reflectionObject
0 ignored issues
show
Bug introduced by
There is no parameter named $reflectionObject. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
250
     * @param array                            $tagNames
251
     *
252
     * @return array
253
     */
254
    public static function getTagConfigurationForProperty($className, $property, array $tagNames): array
255
    {
256
        $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
257
        $tags = $reflectionService->getClassSchema($className)->getProperty($property)['tags'];
258
259
        $configuration = [];
260
        foreach ($tagNames as $tagName) {
261
            $configuration[$tagName] = [];
262
            if (!\is_array($tags[$tagName])) {
263
                continue;
264
            }
265
            foreach ($tags[$tagName] as $c) {
266
                $configuration[$tagName] = \array_merge(
267
                    $configuration[$tagName],
268
                    GeneralUtility::trimExplode(' ', $c, true)
269
                );
270
            }
271
        }
272
273
        return $configuration;
274
    }
275
276
277
278
    /**
279
     * Get public method names
280
     *
281
     * @param string $className
282
     * @return array
283
     */
284
    public static function getPropertyNames(string $className): array
285
    {
286
        $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
287
        return array_keys($reflectionService->getClassSchema($className)->getProperties());
288
    }
289
290
    /**
291
     * Get public method names
292
     *
293
     * @param string $className
294
     * @return array
295
     */
296
    public static function getPublicMethodNames(string $className): array
297
    {
298
        $methodNames = [];
299
300
        if (self::is9orHigher()) {
301
            $reflectionService = GeneralUtility::makeInstance(ReflectionService::class);
302
            $schema = $reflectionService->getClassSchema($className);
303
            $methods = $schema->getMethods();
304
            foreach ($methods as $key => $method) {
305
                if ($method['public']) {
306
                    $methodNames[] = $key;
307
                }
308
            }
309
        } else {
310
            $methods = self::getPublicMethods($className);
311
            foreach ($methods as $method) {
312
                $methodNames[] = $method->getName();
313
            }
314
        }
315
        return $methodNames;
316
    }
317
318
    /**
319
     * Get properties of the given class, that are als declared in the given class.
320
     *
321
     * @param string $className
322
     *
323
     * @return array
324
     */
325
    public static function getDeclaringProperties($className)
326
    {
327
        $classReflection = new \ReflectionClass($className);
328
        $own = array_filter($classReflection->getProperties(), function ($property) use ($className) {
329
            return $property->class == $className;
330
        });
331
        return array_map(function($item){
332
            return $item->name;
333
        }, $own);
334
    }
335
336
    /**
337
     * Is 9 or higher
338
     *
339
     * @return bool
340
     */
341
    public static function is9orHigher(): bool
342
    {
343
        return VersionNumberUtility::convertVersionNumberToInteger(TYPO3_branch) >= VersionNumberUtility::convertVersionNumberToInteger('9.0');
344
    }
345
}
346