[FEATURE] Support @Flow\Inject annotations in Extbase
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Object / Container / ClassInfoFactory.php
1 <?php
2 namespace TYPO3\CMS\Extbase\Object\Container;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2010-2013 Extbase Team (http://forge.typo3.org/projects/typo3v4-mvc)
8 * Extbase is a backport of TYPO3 Flow. All credits go to the TYPO3 Flow team.
9 * All rights reserved
10 *
11 * This script is part of the TYPO3 project. The TYPO3 project is
12 * free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * The GNU General Public License can be found at
18 * http://www.gnu.org/copyleft/gpl.html.
19 * A copy is found in the textfile GPL.txt and important notices to the license
20 * from the author is found in LICENSE.txt distributed with these scripts.
21 *
22 *
23 * This script is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * This copyright notice MUST APPEAR in all copies of the script!
29 ***************************************************************/
30 /**
31 * TYPO3 Dependency Injection container
32 *
33 * @author Daniel Pötzinger
34 */
35 class ClassInfoFactory {
36
37 /**
38 * Factory metod that builds a ClassInfo Object for the given classname - using reflection
39 *
40 * @param string $className The class name to build the class info for
41 * @throws Exception\UnknownObjectException
42 * @return \TYPO3\CMS\Extbase\Object\Container\ClassInfo the class info
43 */
44 public function buildClassInfoFromClassName($className) {
45 if ($className === 'DateTime') {
46 return new \TYPO3\CMS\Extbase\Object\Container\ClassInfo($className, array(), array(), FALSE, FALSE, array());
47 }
48 try {
49 $reflectedClass = new \ReflectionClass($className);
50 } catch (\Exception $e) {
51 throw new \TYPO3\CMS\Extbase\Object\Container\Exception\UnknownObjectException('Could not analyse class:' . $className . ' maybe not loaded or no autoloader?', 1289386765);
52 }
53 $constructorArguments = $this->getConstructorArguments($reflectedClass);
54 $injectMethods = $this->getInjectMethods($reflectedClass);
55 $injectProperties = $this->getInjectProperties($reflectedClass);
56 $isSingleton = $this->getIsSingleton($className);
57 $isInitializeable = $this->getIsInitializeable($className);
58 return new \TYPO3\CMS\Extbase\Object\Container\ClassInfo($className, $constructorArguments, $injectMethods, $isSingleton, $isInitializeable, $injectProperties);
59 }
60
61 /**
62 * Build a list of constructor arguments
63 *
64 * @param \ReflectionClass $reflectedClass
65 * @return array of parameter infos for constructor
66 */
67 private function getConstructorArguments(\ReflectionClass $reflectedClass) {
68 $reflectionMethod = $reflectedClass->getConstructor();
69 if (!is_object($reflectionMethod)) {
70 return array();
71 }
72 $result = array();
73 foreach ($reflectionMethod->getParameters() as $reflectionParameter) {
74 /* @var $reflectionParameter \ReflectionParameter */
75 $info = array();
76 $info['name'] = $reflectionParameter->getName();
77 if ($reflectionParameter->getClass()) {
78 $info['dependency'] = $reflectionParameter->getClass()->getName();
79 }
80 if ($reflectionParameter->isOptional()) {
81 $info['defaultValue'] = $reflectionParameter->getDefaultValue();
82 }
83 $result[] = $info;
84 }
85 return $result;
86 }
87
88 /**
89 * Build a list of inject methods for the given class.
90 *
91 * @param \ReflectionClass $reflectedClass
92 * @throws \Exception
93 * @return array (nameOfInjectMethod => nameOfClassToBeInjected)
94 */
95 private function getInjectMethods(\ReflectionClass $reflectedClass) {
96 $result = array();
97 $reflectionMethods = $reflectedClass->getMethods();
98 if (is_array($reflectionMethods)) {
99 foreach ($reflectionMethods as $reflectionMethod) {
100 if ($reflectionMethod->isPublic() && $this->isNameOfInjectMethod($reflectionMethod->getName())) {
101 $reflectionParameter = $reflectionMethod->getParameters();
102 if (isset($reflectionParameter[0])) {
103 if (!$reflectionParameter[0]->getClass()) {
104 throw new \Exception('Method "' . $reflectionMethod->getName() . '" of class "' . $reflectedClass->getName() . '" is marked as setter for Dependency Injection, but does not have a type annotation');
105 }
106 $result[$reflectionMethod->getName()] = $reflectionParameter[0]->getClass()->getName();
107 }
108 }
109 }
110 }
111 return $result;
112 }
113
114 /**
115 * Build a list of properties to be injected for the given class.
116 *
117 * @param \ReflectionClass $reflectedClass
118 * @return array (nameOfInjectProperty => nameOfClassToBeInjected)
119 */
120 private function getInjectProperties(\ReflectionClass $reflectedClass) {
121 $result = array();
122 $reflectionProperties = $reflectedClass->getProperties();
123 if (is_array($reflectionProperties)) {
124 foreach ($reflectionProperties as $reflectionProperty) {
125 $reflectedProperty = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Reflection\\PropertyReflection', $reflectedClass->getName(), $reflectionProperty->getName());
126 if (($reflectedProperty->isTaggedWith('inject') || $reflectedProperty->isTaggedWith('Flow\Inject')) && $reflectedProperty->getName() !== 'settings') {
127 $varValues = $reflectedProperty->getTagValues('var');
128 if (count($varValues) == 1) {
129 $result[$reflectedProperty->getName()] = ltrim($varValues[0], '\\');
130 }
131 }
132 }
133 }
134 return $result;
135 }
136
137 /**
138 * This method checks if given method can be used for injection
139 *
140 * @param string $methodName
141 * @return boolean
142 */
143 private function isNameOfInjectMethod($methodName) {
144 if (
145 substr($methodName, 0, 6) === 'inject'
146 && $methodName[6] === strtoupper($methodName[6])
147 && $methodName !== 'injectSettings'
148 ) {
149 return TRUE;
150 }
151 return FALSE;
152 }
153
154 /**
155 * This method is used to determine if a class is a singleton or not.
156 *
157 * @param string $classname
158 * @return boolean
159 */
160 private function getIsSingleton($classname) {
161 return in_array('TYPO3\\CMS\\Core\\SingletonInterface', class_implements($classname));
162 }
163
164 /**
165 * This method is used to determine of the object is initializeable with the
166 * method initializeObject.
167 *
168 * @param string $classname
169 * @return boolean
170 */
171 private function getIsInitializeable($classname) {
172 return method_exists($classname, 'initializeObject');
173 }
174 }
175
176 ?>