[BUGFIX] PHP 7 Reflection error for default value
[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 /**
18 * TYPO3 Dependency Injection container
19 */
20 class ClassInfoFactory
21 {
22 /**
23 * Factory metod that builds a ClassInfo Object for the given classname - using reflection
24 *
25 * @param string $className The class name to build the class info for
26 * @throws Exception\UnknownObjectException
27 * @return \TYPO3\CMS\Extbase\Object\Container\ClassInfo the class info
28 */
29 public function buildClassInfoFromClassName($className)
30 {
31 if ($className === 'DateTime') {
32 return new \TYPO3\CMS\Extbase\Object\Container\ClassInfo($className, [], [], false, false, []);
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? ' . $e->getMessage(), 1289386765, $e);
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 {
55 $reflectionMethod = $reflectedClass->getConstructor();
56 if (!is_object($reflectionMethod)) {
57 return [];
58 }
59 $result = [];
60 foreach ($reflectionMethod->getParameters() as $reflectionParameter) {
61 /* @var $reflectionParameter \ReflectionParameter */
62 $info = [];
63 $info['name'] = $reflectionParameter->getName();
64 if ($reflectionParameter->getClass()) {
65 $info['dependency'] = $reflectionParameter->getClass()->getName();
66 }
67
68 if ($reflectionParameter->isDefaultValueAvailable()) {
69 $info['defaultValue'] = $reflectionParameter->getDefaultValue();
70 }
71
72 $result[] = $info;
73 }
74 return $result;
75 }
76
77 /**
78 * Build a list of inject methods for the given class.
79 *
80 * @param \ReflectionClass $reflectedClass
81 * @throws \Exception
82 * @return array (nameOfInjectMethod => nameOfClassToBeInjected)
83 */
84 private function getInjectMethods(\ReflectionClass $reflectedClass)
85 {
86 $result = [];
87 $reflectionMethods = $reflectedClass->getMethods();
88 if (is_array($reflectionMethods)) {
89 foreach ($reflectionMethods as $reflectionMethod) {
90 if ($reflectionMethod->isPublic() && $this->isNameOfInjectMethod($reflectionMethod->getName())) {
91 $reflectionParameter = $reflectionMethod->getParameters();
92 if (isset($reflectionParameter[0])) {
93 if (!$reflectionParameter[0]->getClass()) {
94 throw new \Exception(
95 'Method "' . $reflectionMethod->getName() . '" of class "' . $reflectedClass->getName() . '" is marked as setter for Dependency Injection, but does not have a type annotation',
96 1476108030
97 );
98 }
99 $result[$reflectionMethod->getName()] = $reflectionParameter[0]->getClass()->getName();
100 }
101 }
102 }
103 }
104 return $result;
105 }
106
107 /**
108 * Build a list of properties to be injected for the given class.
109 *
110 * @param \ReflectionClass $reflectedClass
111 * @return array (nameOfInjectProperty => nameOfClassToBeInjected)
112 */
113 private function getInjectProperties(\ReflectionClass $reflectedClass)
114 {
115 $result = [];
116 $reflectionProperties = $reflectedClass->getProperties();
117 if (is_array($reflectionProperties)) {
118 foreach ($reflectionProperties as $reflectionProperty) {
119 $reflectedProperty = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Extbase\Reflection\PropertyReflection::class, $reflectedClass->getName(), $reflectionProperty->getName());
120 if ($reflectedProperty->isTaggedWith('inject') && $reflectedProperty->getName() !== 'settings') {
121 $varValues = $reflectedProperty->getTagValues('var');
122 if (count($varValues) === 1) {
123 $result[$reflectedProperty->getName()] = ltrim($varValues[0], '\\');
124 }
125 }
126 }
127 }
128 return $result;
129 }
130
131 /**
132 * This method checks if given method can be used for injection
133 *
134 * @param string $methodName
135 * @return bool
136 */
137 private function isNameOfInjectMethod($methodName)
138 {
139 if (
140 substr($methodName, 0, 6) === 'inject'
141 && $methodName[6] === strtoupper($methodName[6])
142 && $methodName !== 'injectSettings'
143 ) {
144 return true;
145 }
146 return false;
147 }
148
149 /**
150 * This method is used to determine if a class is a singleton or not.
151 *
152 * @param string $classname
153 * @return bool
154 */
155 private function getIsSingleton($classname)
156 {
157 return in_array(\TYPO3\CMS\Core\SingletonInterface::class, class_implements($classname));
158 }
159
160 /**
161 * This method is used to determine of the object is initializeable with the
162 * method initializeObject.
163 *
164 * @param string $classname
165 * @return bool
166 */
167 private function getIsInitializeable($classname)
168 {
169 return method_exists($classname, 'initializeObject');
170 }
171 }