Completed
Push — master ( 9b9ca0...f3dbfd )
by Lukas
13:11
created

ControllerMethodReflector::reflect()   D

Complexity

Conditions 10
Paths 28

Size

Total Lines 44
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 27
nc 28
nop 2
dl 0
loc 44
rs 4.8196
c 0
b 0
f 0

How to fix   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
 * @copyright Copyright (c) 2016, ownCloud, Inc.
4
 *
5
 * @author Bernhard Posselt <[email protected]>
6
 * @author Morris Jobke <[email protected]>
7
 * @author Olivier Paroz <[email protected]>
8
 * @author Robin McCorkell <[email protected]>
9
 * @author Thomas Müller <[email protected]>
10
 *
11
 * @license AGPL-3.0
12
 *
13
 * This code is free software: you can redistribute it and/or modify
14
 * it under the terms of the GNU Affero General Public License, version 3,
15
 * as published by the Free Software Foundation.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20
 * GNU Affero General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU Affero General Public License, version 3,
23
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
24
 *
25
 */
26
27
namespace OC\AppFramework\Utility;
28
29
use \OCP\AppFramework\Utility\IControllerMethodReflector;
30
31
/**
32
 * Reads and parses annotations from doc comments
33
 */
34
class ControllerMethodReflector implements IControllerMethodReflector {
35
	public $annotations = [];
36
	private $types = [];
37
	private $parameters = [];
38
39
	/**
40
	 * @param object $object an object or classname
41
	 * @param string $method the method which we want to inspect
42
	 */
43
	public function reflect($object, $method){
44
		$reflection = new \ReflectionMethod($object, $method);
45
		$docs = $reflection->getDocComment();
46
47
		// extract everything prefixed by @ and first letter uppercase
48
		preg_match_all('/^\h+\*\h+@(?P<annotation>[A-Z]\w+)((?P<parameter>.*))?$/m', $docs, $matches);
49
		foreach($matches['annotation'] as $key => $annontation) {
50
			$annotationValue = $matches['parameter'][$key];
51
			if(isset($annotationValue[0]) && $annotationValue[0] === '(' && $annotationValue[strlen($annotationValue) - 1] === ')') {
52
				$cutString = substr($annotationValue, 1, -1);
53
				$cutString = str_replace(' ', '', $cutString);
54
				$splittedArray = explode(',', $cutString);
55
				foreach($splittedArray as $annotationValues) {
56
					list($key, $value) = explode('=', $annotationValues);
57
					$this->annotations[$annontation][$key] = $value;
58
				}
59
				continue;
60
			}
61
62
			$this->annotations[$annontation] = [$annotationValue];
63
		}
64
65
		// extract type parameter information
66
		preg_match_all('/@param\h+(?P<type>\w+)\h+\$(?P<var>\w+)/', $docs, $matches);
67
		$this->types = array_combine($matches['var'], $matches['type']);
68
69
		foreach ($reflection->getParameters() as $param) {
70
			// extract type information from PHP 7 scalar types and prefer them
71
			// over phpdoc annotations
72
			if (method_exists($param, 'getType')) {
73
				$type = $param->getType();
74
				if ($type !== null) {
75
					$this->types[$param->getName()] = (string) $type;
0 ignored issues
show
Bug introduced by
Consider using $param->name. There is an issue with getName() and APC-enabled PHP versions.
Loading history...
76
				}
77
			}
78
79
			if($param->isOptional()) {
80
				$default = $param->getDefaultValue();
81
			} else {
82
				$default = null;
83
			}
84
			$this->parameters[$param->name] = $default;
85
		}
86
	}
87
88
	/**
89
	 * Inspects the PHPDoc parameters for types
90
	 * @param string $parameter the parameter whose type comments should be
91
	 * parsed
92
	 * @return string|null type in the type parameters (@param int $something)
0 ignored issues
show
Bug introduced by
There is no parameter named $something). 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...
93
	 * would return int or null if not existing
94
	 */
95
	public function getType($parameter) {
96
		if(array_key_exists($parameter, $this->types)) {
97
			return $this->types[$parameter];
98
		} else {
99
			return null;
100
		}
101
	}
102
103
	/**
104
	 * @return array the arguments of the method with key => default value
105
	 */
106
	public function getParameters() {
107
		return $this->parameters;
108
	}
109
110
	/**
111
	 * Check if a method contains an annotation
112
	 * @param string $name the name of the annotation
113
	 * @return bool true if the annotation is found
114
	 */
115
	public function hasAnnotation($name) {
116
		return array_key_exists($name, $this->annotations);
117
	}
118
119
	/**
120
	 * Get optional annotation parameter by key
121
	 *
122
	 * @param string $name the name of the annotation
123
	 * @param string $key the string of the annotation
124
	 * @return string
125
	 */
126
	public function getAnnotationParameter($name, $key) {
127
		if(isset($this->annotations[$name][$key])) {
128
			return $this->annotations[$name][$key];
129
		}
130
131
		return '';
132
	}
133
}
134