Test Failed
Pull Request — master (#97)
by Gildonei
03:38
created

DiControllerParser::getInjection()   B

Complexity

Conditions 7
Paths 7

Size

Total Lines 20
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 8.8142

Importance

Changes 0
Metric Value
eloc 16
dl 0
loc 20
ccs 10
cts 15
cp 0.6667
rs 8.8333
c 0
b 0
f 0
cc 7
nc 7
nop 4
crap 8.8142
1
<?php
2
3
namespace Ubiquity\controllers\di;
4
5
use Ubiquity\orm\parser\Reflexion;
6
use Ubiquity\utils\base\UArray;
7
use Ubiquity\utils\base\UString;
8
use Ubiquity\cache\ClassUtils;
9
use Ubiquity\exceptions\DiException;
10
11
/**
12
 * Parse the controllers for dependency injections.
13
 *
14
 * Ubiquity\controllers\di$DiControllerParser
15
 * This class is part of Ubiquity
16
 *
17
 * @author jcheron <[email protected]>
18
 * @version 1.0.0
19
 * @since Ubiquity 2.1.0
20
 *
21
 */
22
class DiControllerParser {
23
	protected $injections = [ ];
24
25 8
	public function parse($controllerClass, $config) {
26 8
		$properties = Reflexion::getProperties ( $controllerClass );
27 8
		foreach ( $properties as $property ) {
28 8
			$propName = $property->getName ();
29 8
			$annot = Reflexion::getAnnotationMember ( $controllerClass, $propName, "@injected" );
30 8
			if ($annot !== false) {
31 8
				$name = $annot->name;
32 8
				if ($this->isInjectable ( $controllerClass, $name ?? $propName, false )) {
33 8
					$this->injections [$propName] = $this->getInjection ( $name ?? $propName, $config, $controllerClass, $annot->code ?? null);
34
				}
35
			} else {
36 8
				$annot = Reflexion::getAnnotationMember ( $controllerClass, $propName, "@autowired" );
37 8
				if ($annot !== false) {
38 8
					$type = Reflexion::getPropertyType ( $controllerClass, $propName );
39 8
					if ($type !== false) {
40 8
						if ($this->isInjectable ( $controllerClass, $propName, false )) {
41 8
							$this->getInjectableAutowired ( $type, $propName );
42
						}
43
					} else {
44
						throw new DiException ( sprintf ( '%s property has no type and cannot be autowired!', $propName ) );
45
					}
46
				}
47
			}
48
		}
49 8
		$this->scanGlobalDi ( $config ['di'] ?? [ ], $controllerClass );
50 8
	}
51
52 8
	protected function getInjectableAutowired($type, $propName) {
53 8
		$typeR = new \ReflectionClass ( $type );
54 8
		if ($typeR->isInstantiable ()) {
55 8
			$constructor = $typeR->getConstructor ();
56 8
			$nbParams = $constructor == null ? 0 : $typeR->getConstructor ()->getNumberOfRequiredParameters ();
57 8
			if ($nbParams == 0) {
58 8
				$this->injections [$propName] = "function(){return new " . $type . "();}";
59
			} elseif ($nbParams == 1) {
60
				$this->injections [$propName] = "function(\$controller){return new " . $type . "(\$controller);}";
61
			} else {
62 8
				throw new DiException ( sprintf ( 'Service %s constructor has too many mandatory arguments for %s injection!', $type, $propName ) );
63
			}
64
		} else {
65
			$namespace = $typeR->getNamespaceName ();
66
			$oClass = $namespace . "\\" . ucfirst ( $propName );
67
			if (class_exists ( $oClass )) {
68
				if (is_subclass_of ( $oClass, $type )) {
69
					$this->getInjectableAutowired ( $oClass, $propName );
70
				} else {
71
					throw new DiException ( sprintf ( 'Class %s is not a subclass of %s!', $oClass, $type ) );
72
				}
73
			} else {
74
				throw new DiException ( sprintf ( 'Class %s does not exists!', $oClass ) );
75
			}
76
		}
77 8
	}
78
79 8
	protected function scanGlobalDi($diConfig, $controller) {
80 8
		$classname = ClassUtils::getClassSimpleName ( $controller );
81 8
		foreach ( $diConfig as $k => $v ) {
82 8
			if (UString::startswith ( $k, "*." ) || UString::startswith ( $k, $classname . "." )) {
83 8
				$dis = explode ( '.', $k );
84 8
				$nkey = end ( $dis );
85 8
				if (property_exists ( $controller, $nkey ) === false) {
86 8
					$this->injections [$nkey] = $v;
87
				}
88
			}
89
		}
90 8
	}
91
92 8
	protected function isInjectable($classname, $member, $silent = true) {
93 8
		$prop = new \ReflectionProperty ( $classname, $member );
94 8
		if ($prop->isPublic ()) {
95 8
			return true;
96
		}
97 8
		$setter = 'set' . ucfirst ( $member );
98 8
		if (method_exists ( $classname, $setter )) {
99 8
			return true;
100
		}
101
		if (! $silent) {
102
			throw new DiException ( sprintf ( '%s member must be public or have a setter to be injected in the class %s!', $member, $classname ) );
103
		}
104
		return false;
105
	}
106
107 8
	protected function getInjection($name, $config, $controller, $code = null) {
108 8
		if ($code != null) {
109
			return "function(\$controller){return " . $code . ";}";
110
		}
111 8
		if (isset ( $config ["di"] )) {
112 8
			$di = $config ['di'];
113 8
			if ($name != null) {
114 8
				$classname = ClassUtils::getClassSimpleName ( $controller );
115 8
				if (isset ( $di [$name] )) {
116
					return $di [$name];
117 8
				} elseif (isset ( $di [$classname . '.' . $name] )) {
118
					return $di [$classname . '.' . $name];
119 8
				} elseif (isset ( $di ['*.' . $name] )) {
120 8
					return $di ['*.' . $name];
121
				} else {
122
					throw new \Exception ( "key " . $name . " is not present in config di array" );
123
				}
124
			}
125
		} else {
126
			throw new \Exception ( "key di is not present in config array" );
127
		}
128
	}
129
130 8
	public function __toString() {
131 8
		return "return " . UArray::asPhpArray ( $this->injections, "array" ) . ";";
132
	}
133
134
	/**
135
	 *
136
	 * @return array
137
	 */
138 8
	public function getInjections() {
139 8
		return $this->injections;
140
	}
141
}
142
143