Completed
Push — master ( 0a636a...80871c )
by Peter
15:13
created

Builder::instantiateAnnotation()   C

Complexity

Conditions 10
Paths 42

Size

Total Lines 59
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 25
CRAP Score 10.7245

Importance

Changes 12
Bugs 2 Features 1
Metric Value
c 12
b 2
f 1
dl 0
loc 59
ccs 25
cts 31
cp 0.8065
rs 6.5919
cc 10
eloc 27
nc 42
nop 3
crap 10.7245

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
/**
4
 * This software package is licensed under AGPL, Commercial license.
5
 *
6
 * @package maslosoft/addendum
7
 * @licence AGPL, Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]> (Meta container, further improvements, bugfixes)
9
 * @copyright Copyright (c) Maslosoft (Meta container, further improvements, bugfixes)
10
 * @copyright Copyright (c) Jan Suchal (Original version, builder, parser)
11
 * @link http://maslosoft.com/addendum/ - maslosoft addendum
12
 * @link https://code.google.com/p/addendum/ - original addendum project
13
 */
14
15
namespace Maslosoft\Addendum\Builder;
16
17
use Exception;
18
use Maslosoft\Addendum\Addendum;
19
use Maslosoft\Addendum\Collections\AnnotationsCollection;
20
use Maslosoft\Addendum\Collections\MatcherConfig;
21
use Maslosoft\Addendum\Interfaces\AnnotationInterface;
22
use Maslosoft\Addendum\Matcher\AnnotationsMatcher;
23
use Maslosoft\Addendum\Reflection\ReflectionAnnotatedClass;
24
use Maslosoft\Addendum\Reflection\ReflectionAnnotatedMethod;
25
use Maslosoft\Addendum\Reflection\ReflectionAnnotatedProperty;
26
use Maslosoft\Addendum\Utilities\Blacklister;
27
use Maslosoft\Addendum\Utilities\ReflectionName;
28
use ReflectionClass;
29
30
/**
31
 * @Label("Annotations builder")
32
 */
33
class Builder
34
{
35
36
	/**
37
	 * Cached values of parsing
38
	 * @var string[][][]
39
	 */
40
	private static $_cache = [];
41
42
	/**
43
	 * Addendum instance
44
	 * @var Addendum
45
	 */
46
	private $addendum = null;
47
48 32
	public function __construct(Addendum $addendum = null)
49
	{
50 32
		$this->addendum = $addendum? : new Addendum();
51 32
	}
52
53
	/**
54
	 * Build annotations collection
55
	 * @param ReflectionAnnotatedClass|ReflectionAnnotatedMethod|ReflectionAnnotatedProperty $targetReflection
56
	 * @return AnnotationsCollection
57
	 */
58 32
	public function build($targetReflection)
59
	{
60 32
		$annotations = [];
61 32
		$t = [];
0 ignored issues
show
Unused Code introduced by
$t is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
62
63
64
65
		// Decide where from take traits
66 32
		if ($targetReflection instanceof ReflectionClass)
67 32
		{
68 32
			$t = $targetReflection->getTraits();
69 32
		}
70
		else
71
		{
72 17
			$t = $targetReflection->getDeclaringClass()->getTraits();
73
		}
74
75
		// Get annotations from traits
76 32
		$traitsData = [];
77 32
		foreach ($t as $trait)
78
		{
79 2
			$targetTrait = new ReflectionAnnotatedClass($trait->name, $this->addendum);
80 2
			$annotationsTrait = null;
81
82
			// Try to get annotations from entity, be it method, property or trait itself
83 2
			switch (true)
84
			{
85 2
				case $targetReflection instanceof \ReflectionProperty && $targetTrait->hasProperty($targetReflection->name):
86 2
					$annotationsTrait = new ReflectionAnnotatedProperty($targetTrait->name, $targetReflection->name, $this->addendum);
87 2
					break;
88 2
				case $targetReflection instanceof \ReflectionMethod && $targetTrait->hasMethod($targetReflection->name):
89
					$annotationsTrait = new ReflectionAnnotatedMethod($targetTrait->name, $targetReflection->name, $this->addendum);
90
					break;
91 2
				case $targetReflection instanceof \ReflectionClass:
92 2
					$annotationsTrait = $targetTrait;
93 2
					break;
94
			}
95
96
			// Does not have property or method
97 2
			if (null === $annotationsTrait)
98 2
			{
99
				continue;
100
			}
101
102
			// Data from traits
103 2
			$traitsData = $this->_parse($annotationsTrait);
104 32
		}
105
106
		// Data from class
107 32
		$data = $this->_parse($targetReflection);
108
109
		// Merge data from traits
110 32
		$data = array_merge($traitsData, $data);
111
112
		// Get annotations from current entity
113 32
		foreach ($data as $class => $parameters)
114
		{
115 30
			foreach ($parameters as $params)
116
			{
117 30
				$annotation = $this->instantiateAnnotation($class, $params, $targetReflection);
118 30
				if ($annotation !== false)
119 30
				{
120 30
					$annotations[$class][] = $annotation;
121 30
				}
122 30
			}
123 32
		}
124 32
		return new AnnotationsCollection($annotations);
125
	}
126
127
	/**
128
	 * Create new instance of annotation
129
	 * @param string $class
130
	 * @param mixed[] $parameters
131
	 * @param ReflectionAnnotatedClass|ReflectionAnnotatedMethod|ReflectionAnnotatedProperty|bool $targetReflection
132
	 * @return boolean|object
133
	 */
134 30
	public function instantiateAnnotation($class, $parameters, $targetReflection = false)
135
	{
136 30
		$class = ucfirst($class) . "Annotation";
137
138
		// If namespaces are empty assume global namespace
139 30
		$fqn = $this->_normalizeFqn('\\', $class);
140 30
		foreach ($this->addendum->namespaces as $ns)
141
		{
142 30
			$fqn = $this->_normalizeFqn($ns, $class);
143 30
			if (Blacklister::ignores($fqn))
144 30
			{
145 22
				continue;
146
			}
147
			try
148
			{
149
				// NOTE: @ need to be used here or php might complain
150 30
				if (@!class_exists($fqn))
151 30
				{
152
					//$this->addendum->getLogger()->debug('Annotation class `{fqn}` not found, ignoring', ['fqn' => $fqn]);
153 27
					Blacklister::ignore($fqn);
154 27
				}
155
				else
156
				{
157
					// Class exists, exit loop
158 30
					break;
159
				}
160
			}
161 27
			catch (Exception $e)
162
			{
163
				// Ignore class autoloading errors
164
			}
165 30
		}
166 30
		if (Blacklister::ignores($fqn))
167 30
		{
168 1
			return false;
169
		}
170
		try
171
		{
172
			// NOTE: @ need to be used here or php might complain
173 30
			if (@!class_exists($fqn))
174 30
			{
175
				$this->addendum->getLogger()->debug('Annotation class `{fqn}` not found, ignoring', ['fqn' => $fqn]);
176
				Blacklister::ignore($fqn);
177
				return false;
178
			}
179
		}
180 30
		catch (Exception $e)
181
		{
182
			// Ignore autoload errors and return false
183
			Blacklister::ignore($fqn);
184
			return false;
185
		}
186 30
		$resolvedClass = Addendum::resolveClassName($fqn);
187 30
		if ((new ReflectionClass($resolvedClass))->implementsInterface(AnnotationInterface::class) || $resolvedClass == AnnotationInterface::class)
188 30
		{
189 30
			return new $resolvedClass($parameters, $targetReflection);
190
		}
191
		return false;
192
	}
193
194
	/**
195
	 * Normalize class name and namespace to proper fully qualified name
196
	 * @param string $ns
197
	 * @param string $class
198
	 * @return string
199
	 */
200 30
	private function _normalizeFqn($ns, $class)
201
	{
202 30
		return preg_replace('~\\\+~', '\\', "\\$ns\\$class");
203
	}
204
205
	/**
206
	 * Get doc comment
207
	 * @param ReflectionAnnotatedClass|ReflectionAnnotatedMethod|ReflectionAnnotatedProperty $reflection
208
	 * @return mixed[]
209
	 */
210 32
	private function _parse($reflection)
211
	{
212 32
		$key = ReflectionName::createName($reflection);
213 32
		if (!isset(self::$_cache[$key]))
214 32
		{
215 32
			$parser = new AnnotationsMatcher;
216 32
			$data = [];
217 32
			$parser->setPlugins(new MatcherConfig([
218 32
				'addendum' => $this->addendum,
219
				'reflection' => $reflection
220 32
			]));
221 32
			$parser->matches($this->getDocComment($reflection), $data);
222 32
			self::$_cache[$key] = $data;
223 32
		}
224 32
		return self::$_cache[$key];
225
	}
226
227
	/**
228
	 * Get doc comment
229
	 * @param ReflectionAnnotatedClass|ReflectionAnnotatedMethod|ReflectionAnnotatedProperty $reflection
230
	 * @return mixed[]
231
	 */
232 32
	protected function getDocComment($reflection)
233
	{
234 32
		return Addendum::getDocComment($reflection);
235
	}
236
237
	/**
238
	 * Clear local parsing cache
239
	 */
240 3
	public static function clearCache()
241
	{
242 3
		self::$_cache = [];
243 3
	}
244
245
}
246