Completed
Push — master ( baeee5...a6123a )
by Peter
04:33
created

Builder::build()   C

Complexity

Conditions 12
Paths 72

Size

Total Lines 68
Code Lines 32

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 33
CRAP Score 12.0268

Importance

Changes 5
Bugs 0 Features 0
Metric Value
c 5
b 0
f 0
dl 0
loc 68
ccs 33
cts 35
cp 0.9429
rs 5.7752
cc 12
eloc 32
nc 72
nop 1
crap 12.0268

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