[TASK] Use name-resolution instead of strings where possible: 3
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Object / Container / ClassInfoFactory.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Object\Container;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16 /**
17 * TYPO3 Dependency Injection container
18 *
19 * @author Daniel Pötzinger
20 */
21 class ClassInfoFactory {
22
23 /**
24 * Factory metod that builds a ClassInfo Object for the given classname - using reflection
25 *
26 * @param string $className The class name to build the class info for
27 * @throws Exception\UnknownObjectException
28 * @return \TYPO3\CMS\Extbase\Object\Container\ClassInfo the class info
29 */
30 public function buildClassInfoFromClassName($className) {
31 if ($className === 'DateTime') {
32 return new \TYPO3\CMS\Extbase\Object\Container\ClassInfo($className, array(), array(), FALSE, FALSE, array());
33 }
34 try {
35 $reflectedClass = new \ReflectionClass($className);
36 } catch (\Exception $e) {
37 throw new \TYPO3\CMS\Extbase\Object\Container\Exception\UnknownObjectException('Could not analyse class:' . $className . ' maybe not loaded or no autoloader?', 1289386765);
38 }
39 $constructorArguments = $this->getConstructorArguments($reflectedClass);
40 $injectMethods = $this->getInjectMethods($reflectedClass);
41 $injectProperties = $this->getInjectProperties($reflectedClass);
42 $isSingleton = $this->getIsSingleton($className);
43 $isInitializeable = $this->getIsInitializeable($className);
44 return new \TYPO3\CMS\Extbase\Object\Container\ClassInfo($className, $constructorArguments, $injectMethods, $isSingleton, $isInitializeable, $injectProperties);
45 }
46
47 /**
48 * Build a list of constructor arguments
49 *
50 * @param \ReflectionClass $reflectedClass
51 * @return array of parameter infos for constructor
52 */
53 private function getConstructorArguments(\ReflectionClass $reflectedClass) {
54 $reflectionMethod = $reflectedClass->getConstructor();
55 if (!is_object($reflectionMethod)) {
56 return array();
57 }
58 $result = array();
59 foreach ($reflectionMethod->getParameters() as $reflectionParameter) {
60 /* @var $reflectionParameter \ReflectionParameter */
61 $info = array();
62 $info['name'] = $reflectionParameter->getName();
63 if ($reflectionParameter->getClass()) {
64 $info['dependency'] = $reflectionParameter->getClass()->getName();
65 }
66
67 try {
68 $info['defaultValue'] = $reflectionParameter->getDefaultValue();
69 } catch (\ReflectionException $e) {}
70
71 $result[] = $info;
72 }
73 return $result;
74 }
75
76 /**
77 * Build a list of inject methods for the given class.
78 *
79 * @param \ReflectionClass $reflectedClass
80 * @throws \Exception
81 * @return array (nameOfInjectMethod => nameOfClassToBeInjected)
82 */
83 private function getInjectMethods(\ReflectionClass $reflectedClass) {
84 $result = array();
85 $reflectionMethods = $reflectedClass->getMethods();
86 if (is_array($reflectionMethods)) {
87 foreach ($reflectionMethods as $reflectionMethod) {
88 if ($reflectionMethod->isPublic() && $this->isNameOfInjectMethod($reflectionMethod->getName())) {
89 $reflectionParameter = $reflectionMethod->getParameters();
90 if (isset($reflectionParameter[0])) {
91 if (!$reflectionParameter[0]->getClass()) {
92 throw new \Exception('Method "' . $reflectionMethod->getName() . '" of class "' . $reflectedClass->getName() . '" is marked as setter for Dependency Injection, but does not have a type annotation');
93 }
94 $result[$reflectionMethod->getName()] = $reflectionParameter[0]->getClass()->getName();
95 }
96 }
97 }
98 }
99 return $result;
100 }
101
102 /**
103 * Build a list of properties to be injected for the given class.
104 *
105 * @param \ReflectionClass $reflectedClass
106 * @return array (nameOfInjectProperty => nameOfClassToBeInjected)
107 */
108 private function getInjectProperties(\ReflectionClass $reflectedClass) {
109 $result = array();
110 $reflectionProperties = $reflectedClass->getProperties();
111 if (is_array($reflectionProperties)) {
112 foreach ($reflectionProperties as $reflectionProperty) {
113 $reflectedProperty = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Reflection\PropertyReflection::class, $reflectedClass->getName(), $reflectionProperty->getName());
114 if ($reflectedProperty->isTaggedWith('inject') && $reflectedProperty->getName() !== 'settings') {
115 $varValues = $reflectedProperty->getTagValues('var');
116 if (count($varValues) == 1) {
117 $result[$reflectedProperty->getName()] = ltrim($varValues[0], '\\');
118 }
119 }
120 }
121 }
122 return $result;
123 }
124
125 /**
126 * This method checks if given method can be used for injection
127 *
128 * @param string $methodName
129 * @return bool
130 */
131 private function isNameOfInjectMethod($methodName) {
132 if (
133 substr($methodName, 0, 6) === 'inject'
134 && $methodName[6] === strtoupper($methodName[6])
135 && $methodName !== 'injectSettings'
136 ) {
137 return TRUE;
138 }
139 return FALSE;
140 }
141
142 /**
143 * This method is used to determine if a class is a singleton or not.
144 *
145 * @param string $classname
146 * @return bool
147 */
148 private function getIsSingleton($classname) {
149 return in_array(\TYPO3\CMS\Core\SingletonInterface::class, class_implements($classname));
150 }
151
152 /**
153 * This method is used to determine of the object is initializeable with the
154 * method initializeObject.
155 *
156 * @param string $classname
157 * @return bool
158 */
159 private function getIsInitializeable($classname) {
160 return method_exists($classname, 'initializeObject');
161 }
162 }