ReflectionAnnotation::fromReflectionClass()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
eloc 4
dl 0
loc 10
c 0
b 0
f 0
ccs 5
cts 5
cp 1
rs 10
cc 1
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * AppserverIo\Lang\Reflection\ReflectionAnnotation
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author    Tim Wagner <[email protected]>
15
 * @copyright 2015 TechDivision GmbH <[email protected]>
16
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link      https://github.com/appserver-io/lang
18
 * @link      http://www.appserver.io
19
 */
20
21
namespace AppserverIo\Lang\Reflection;
22
23
use AppserverIo\Lang\Objct;
24
use Herrera\Annotations\Tokens;
25
use Herrera\Annotations\Tokenizer;
26
use Herrera\Annotations\Convert\ToArray;
27
28
/**
29
 * A generic and serializable annotation implementation.
30
 *
31
 * @author    Tim Wagner <[email protected]>
32
 * @copyright 2015 TechDivision GmbH <[email protected]>
33
 * @license   http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
34
 * @link      https://github.com/appserver-io/lang
35
 * @link      http://www.appserver.io
36
 */
37
class ReflectionAnnotation extends Objct implements AnnotationInterface, \Serializable
38
{
39
40
    /**
41
     * The annotation name.
42
     *
43
     * @var string
44
     */
45
    protected $annotationName;
46
47
    /**
48
     * The array with the annotation values.
49
     *
50
     * @var array
51
     */
52
    protected $values;
53
54
    /**
55
     * The constructor the initializes the instance with the
56
     * data passed with the token.
57
     *
58
     * @param string $annotationName The annotation name
59
     * @param array  $values         The annotation values
60
     */
61 19
    public function __construct($annotationName, array $values = array())
62
    {
63
        // initialize property default values here, as declarative default values may break thread safety,
64
        // when utilizing static and non-static access on class methods within same thread context!
65 19
        $this->annotationName = '';
66 19
        $this->values = array();
67
68
        // set the annotation name
69 19
        $this->annotationName = $annotationName;
70
71
        // ATTENTION: We need to copy the values, because if not, it would not be
72
        //            possible to pre-initialize them in an annotation implements
73
        //            constructor!
74 19
        foreach ($values as $key => $value) {
75 11
            $this->values[$key] = $value;
76
        }
77 19
    }
78
79
    /**
80
     * This method returns the class name as
81
     * a string.
82
     *
83
     * @return string
84
     */
85 1
    public static function __getClass()
86
    {
87 1
        return __CLASS__;
88
    }
89
90
    /**
91
     * Returns the annation name.
92
     *
93
     * @return string The annotation name
94
     */
95 4
    public function getAnnotationName()
96
    {
97 4
        return $this->annotationName;
98
    }
99
100
    /**
101
     * Returns the annotation values.
102
     *
103
     * @return array The annotation values
104
     */
105 3
    public function getValues()
106
    {
107 3
        return $this->values;
108
    }
109
110
    /**
111
     * Queries whether this annotation instance has a value with the passed key or not.
112
     *
113
     * @param string $key The key we want to query
114
     *
115
     * @return boolean TRUE if the value is available, else FALSE
116
     */
117 7
    public function hasValue($key)
118
    {
119 7
        return isset($this->values[$key]);
120
    }
121
122
    /**
123
     * Returns the value for the passed key, if available.
124
     *
125
     * @param string|null $key The key of the value to return
126
     *
127
     * @return mixed|null The requested value
128
     */
129 7
    public function getValue($key)
130
    {
131 7
        if ($this->hasValue($key)) {
132 6
            return $this->values[$key];
133
        }
134 1
    }
135
136
    /**
137
     * Sets the value with the passed key, existing values
138
     * are overwritten.
139
     *
140
     * @param string $key   The key of the value
141
     * @param string $value The value to set
142
     *
143
     * @return void
144
     */
145 1
    public function setValue($key, $value)
146
    {
147 1
        $this->values[$key] = $value;
148 1
    }
149
150
    /**
151
     * String representation of object.
152
     *
153
     * @return string the string representation of the object or null
154
     * @link http://php.net/manual/en/serializable.serialize.php
155
     */
156 1
    public function serialize()
157
    {
158 1
        return serialize(get_object_vars($this));
159
    }
160
161
    /**
162
     * Constructs the object
163
     *
164
     * @param string $data The string representation of the object
165
     *
166
     * @return void
167
     * @link http://php.net/manual/en/serializable.unserialize.php
168
     */
169 1
    public function unserialize($data)
170
    {
171 1
        foreach (unserialize($data) as $propertyName => $propertyValue) {
172 1
            $this->$propertyName = $propertyValue;
173
        }
174 1
    }
175
176
    /**
177
     * Returns a PHP reflection class representation of this instance.
178
     *
179
     * @return \ReflectionClass The PHP reflection class instance
180
     * @see \AppserverIo\Lang\Reflection\ClassInterface::toPhpReflectionClass()
181
     */
182 3
    public function toPhpReflectionClass()
183
    {
184 3
        return new \ReflectionClass($this->getAnnotationName());
185
    }
186
187
    /**
188
     * Returns a new annotation instance.
189
     *
190
     * You can pass a random number of arguments to this function. These
191
     * arguments will be passed to the constructor of the new instance.
192
     *
193
     * @return object A new annotation instance initialized with the passed arguments
194
     * @link http://de2.php.net/func_get_args
195
     */
196 1
    public function newInstance()
197
    {
198 1
        return $this->newInstanceArgs(func_get_args());
199
    }
200
201
    /**
202
     * Returns a new annotation instance.
203
     *
204
     * @param array $args The arguments that will be passed to the instance constructor
205
     *
206
     * @return object A new annotation instance initialized with the passed arguments
207
     */
208 3
    public function newInstanceArgs(array $args = array())
209
    {
210
        // create a reflection instance of the found annotation name
211 3
        $reflectionClass = $this->toPhpReflectionClass();
212
213
        // create a new instance passing the found arguements to the constructor
214 3
        return $reflectionClass->newInstanceArgs($args);
215
    }
216
217
    /**
218
     * Initializes and returns an array with annotation instances from the
219
     * passed doc comment.
220
     *
221
     * @param string $docComment The doc comment to initialize the annotations from
222
     * @param array  $ignore     Array with annotations we want to ignore
223
     * @param array  $aliases    Array with aliases to create annotation instances with
224
     *
225
     * @return array The array with the ReflectionAnnotation instances loaded from the passed doc comment
226
     */
227 14
    public static function fromDocComment($docComment, array $ignore = array(), array $aliases = array())
228
    {
229
230
        // initialize the array for the annotations
231 14
        $annotations = array();
232
233
        // initialize the annotation tokenizer
234 14
        $tokenizer = new Tokenizer();
235 14
        $tokenizer->ignore($ignore);
236
237
        // parse the doc block
238 14
        $parsed = $tokenizer->parse($docComment, $aliases);
239
240
        // convert tokens and return one
241 14
        $tokens = new Tokens($parsed);
242 14
        $toArray = new ToArray();
243
244
        // register annotations with the real annotation name (not the alias)
245 14
        foreach ($toArray->convert($tokens) as $token) {
246
            // check if we've an annotation that matched an alias
247 14
            if (array_key_exists($token->name, $flipped = array_flip($aliases))) {
0 ignored issues
show
Bug introduced by
It seems like $flipped = array_flip($aliases) can also be of type null; however, parameter $search of array_key_exists() does only seem to accept array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

247
            if (array_key_exists($token->name, /** @scrutinizer ignore-type */ $flipped = array_flip($aliases))) {
Loading history...
248 3
                $annotationName = $flipped[$token->name];
249
            } else {
250 14
                $annotationName = $token->name;
251
            }
252
253
            // register the annotation with the real annotation name (not the alias)
254 14
            $annotations[$annotationName] = ReflectionAnnotation::fromStdClass($token, $aliases);
255
        }
256
257
        // return the list with the annotation instances
258 14
        return $annotations;
259
    }
260
261
    /**
262
     * Initializes and returns a ReflectionAnnotation instance from the passed token.
263
     *
264
     * @param \stdClass $token   The token to initialize and return the ReflectionAnnotation instance from
265
     * @param array     $aliases The class aliases to use
266
     *
267
     * @return \AppserverIo\Lang\Reflection\ReflectionAnnotation The initialized ReflectionAnnotation instance
268
     */
269 14
    private static function fromStdClass(\stdClass $token, array $aliases = array())
270
    {
271
272
        // iterate over the tokens values to process them recursively
273 14
        foreach ($token->values as $name => $value) {
274
            // query whether we've an array
275 11
            if (is_array($value)) {
276
                // iterate over all values of the array an process them recursively
277 4
                foreach ($value as $key => $val) {
278
                    // query whether we've a nested annotation
279 4
                    if (is_object($val)) {
280 4
                        $token->values[$name][$key] = ReflectionAnnotation::fromStdClass($val, $aliases);
281
                    }
282
                }
283
            }
284
285
            // query whether we've a nested annotation
286 11
            if (is_object($value)) {
287 11
                $token->values[$name] = ReflectionAnnotation::fromStdClass($value, $aliases);
288
            }
289
        }
290
291
        // initialize and return the reflection annotation
292 14
        return new ReflectionAnnotation($token->name, $token->values);
293
    }
294
295
    /**
296
     * Initializes and returns an array with annotation instances from the doc comment
297
     * found in the passed reflection property instance.
298
     *
299
     * @param \AppserverIo\Lang\Reflection\PropertyInterface $reflectionProperty The reflection property to load the doc comment from
300
     *
301
     * @return array The array with the ReflectionAnnotation instances loaded from the passed reflection property
302
     * @see \AppserverIo\Lang\Reflection\ReflectionAnnotation::fromDocComment()
303
     */
304 2
    public static function fromReflectionProperty(PropertyInterface $reflectionProperty)
305
    {
306
307
        // load the reflection method data we need to initialize the annotations
308 2
        $aliases = $reflectionProperty->getAnnotationAliases();
309 2
        $ignore = $reflectionProperty->getAnnotationsToIgnore();
310 2
        $docComment = $reflectionProperty->toPhpReflectionProperty()->getDocComment();
311
312
        // load and return the annotations found in the doc comment
313 2
        return ReflectionAnnotation::fromDocComment($docComment, $ignore, $aliases);
314
    }
315
316
    /**
317
     * Initializes and returns an array with annotation instances from the doc comment
318
     * found in the passed reflection method instance.
319
     *
320
     * @param \AppserverIo\Lang\Reflection\MethodInterface $reflectionMethod The reflection method to load the doc comment from
321
     *
322
     * @return array The array with the ReflectionAnnotation instances loaded from the passed reflection method
323
     * @see \AppserverIo\Lang\Reflection\ReflectionAnnotation::fromDocComment()
324
     */
325 7
    public static function fromReflectionMethod(MethodInterface $reflectionMethod)
326
    {
327
328
        // load the reflection method data we need to initialize the annotations
329 7
        $aliases = $reflectionMethod->getAnnotationAliases();
330 7
        $ignore = $reflectionMethod->getAnnotationsToIgnore();
331 7
        $docComment = $reflectionMethod->toPhpReflectionMethod()->getDocComment();
332
333
        // load and return the annotations found in the doc comment
334 7
        return ReflectionAnnotation::fromDocComment($docComment, $ignore, $aliases);
335
    }
336
337
    /**
338
     * Initializes and returns an array with annotation instances from the doc comment
339
     * found in the passed reflection class instance.
340
     *
341
     * @param \AppserverIo\Lang\Reflection\ClassInterface $reflectionClass The reflection class to load the doc comment from
342
     *
343
     * @return array The array with the ReflectionAnnotation instances loaded from the passed reflection class
344
     * @see \AppserverIo\Lang\Reflection\ReflectionAnnotation::fromDocComment()
345
     */
346 5
    public static function fromReflectionClass(ClassInterface $reflectionClass)
347
    {
348
349
        // load the reflection method data we need to initialize the annotations
350 5
        $aliases = $reflectionClass->getAnnotationAliases();
351 5
        $ignore = $reflectionClass->getAnnotationsToIgnore();
352 5
        $docComment = $reflectionClass->toPhpReflectionClass()->getDocComment();
353
354
        // load and return the annotations found in the doc comment
355 5
        return ReflectionAnnotation::fromDocComment($docComment, $ignore, $aliases);
356
    }
357
}
358