[TASK] Update to phpunit 4.1
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Resources / PHP / TYPO3.Flow / Classes / TYPO3 / Flow / Core / ClassLoader.php
1 <?php
2 namespace TYPO3\Flow\Core;
3
4 /* *
5 * This script belongs to the TYPO3 Flow framework. *
6 * *
7 * It is free software; you can redistribute it and/or modify it under *
8 * the terms of the GNU Lesser General Public License, either version 3 *
9 * of the License, or (at your option) any later version. *
10 * *
11 * The TYPO3 project - inspiring people to share! *
12 * */
13
14 use TYPO3\Flow\Annotations as Flow;
15
16 /**
17 * Class Loader implementation which loads .php files found in the classes
18 * directory of an object.
19 *
20 * @Flow\Proxy(false)
21 * @Flow\Scope("singleton")
22 */
23 class ClassLoader {
24
25 /**
26 * @var \TYPO3\Flow\Cache\Frontend\PhpFrontend
27 */
28 protected $classesCache;
29
30 /**
31 * An array of \TYPO3\Flow\Package\Package objects
32 * @var array
33 */
34 protected $packages = array();
35
36 /**
37 * @var string
38 */
39 protected $packagesPath = FLOW_PATH_PACKAGES;
40
41 /**
42 * A list of namespaces this class loader is definitely responsible for
43 * @var array
44 */
45 protected $packageNamespaces = array(
46 'TYPO3\Flow' => 10
47 );
48
49 /**
50 * @var boolean
51 */
52 protected $considerTestsNamespace = FALSE;
53
54 /**
55 * @var array
56 */
57 protected $ignoredClassNames = array(
58 'integer' => TRUE,
59 'string' => TRUE,
60 'param' => TRUE,
61 'return' => TRUE,
62 'var' => TRUE,
63 'throws' => TRUE,
64 'api' => TRUE,
65 'todo' => TRUE,
66 'fixme' => TRUE,
67 'see' => TRUE,
68 'license' => TRUE,
69 'author' => TRUE,
70 'test' => TRUE,
71 );
72
73 /**
74 * Injects the cache for storing the renamed original classes
75 *
76 * @param \TYPO3\Flow\Cache\Frontend\PhpFrontend $classesCache
77 * @return void
78 */
79 public function injectClassesCache(\TYPO3\Flow\Cache\Frontend\PhpFrontend $classesCache) {
80 $this->classesCache = $classesCache;
81 }
82
83 /**
84 * Loads php files containing classes or interfaces found in the classes directory of
85 * a package and specifically registered classes.
86 *
87 * @param string $className Name of the class/interface to load
88 * @return boolean
89 */
90 public function loadClass($className) {
91 if ($className[0] === '\\') {
92 $className = substr($className, 1);
93 }
94
95 // Loads any known proxied class:
96 if ($this->classesCache !== NULL && $this->classesCache->requireOnce(str_replace('\\', '_', $className)) !== FALSE) {
97 return TRUE;
98 }
99
100 // Workaround for Doctrine's annotation parser which does a class_exists() for annotations like "@param" and so on:
101 if (isset($this->ignoredClassNames[$className]) || isset($this->ignoredClassNames[substr($className, strrpos($className, '\\') + 1)])) {
102 return FALSE;
103 }
104
105 // Load classes from the Flow package at a very early stage where
106 // no packages have been registered yet:
107 if ($this->packages === array() && substr($className, 0, 10) === 'TYPO3\Flow') {
108 require(FLOW_PATH_FLOW . 'Classes/TYPO3/Flow/' . str_replace('\\', '/', substr($className, 11)) . '.php');
109 return TRUE;
110 }
111
112 // Loads any non-proxied class of registered packages:
113 foreach ($this->packageNamespaces as $packageNamespace => $packageData) {
114 // replace underscores in classname with \ to match for packagenamespace
115 if (substr(str_replace('_', '\\', $className), 0, $packageData['namespaceLength']) === $packageNamespace) {
116 if ($this->considerTestsNamespace === TRUE && substr($className, $packageData['namespaceLength'] + 1, 16) === 'Tests\Functional') {
117 $classPathAndFilename = $this->packages[str_replace('\\', '.', $packageNamespace)]->getPackagePath() . str_replace('\\', '/', substr($className, $packageData['namespaceLength'] + 1)) . '.php';
118 } else {
119 // make the classname PSR-0 compliant by replacing underscores only in the classname not in the namespace
120 $fileName = '';
121 $lastNamespacePosition = strrpos($className, '\\');
122 if ($lastNamespacePosition !== FALSE) {
123 $namespace = substr($className, 0, $lastNamespacePosition);
124 $className = substr($className, $lastNamespacePosition + 1);
125 $fileName = str_replace('\\', '/', $namespace) . '/';
126 }
127 $fileName .= str_replace('_', '/', $className) . '.php';
128
129 $classPathAndFilename = $packageData['classesPath'] . $fileName;
130 }
131 try {
132 $result = include($classPathAndFilename);
133 if ($result !== FALSE) {
134 return TRUE;
135 }
136 } catch (\Exception $e) {
137 }
138 }
139 }
140 return FALSE;
141 }
142
143 /**
144 * Sets the available packages
145 *
146 * @param array $packages An array of \TYPO3\Flow\Package\Package objects
147 * @return void
148 */
149 public function setPackages(array $packages) {
150 $this->packages = $packages;
151 foreach ($packages as $package) {
152 $this->packageNamespaces[$package->getNamespace()] = array('namespaceLength' => strlen($package->getNamespace()), 'classesPath' => $package->getClassesPath());
153 }
154
155 // sort longer package namespaces first, to find specific matches before generic ones
156 uksort($this->packageNamespaces, function($a, $b) {
157 if (strlen($a) === strlen($b)) {
158 return strcmp($a, $b);
159 }
160 return (strlen($a) > strlen($b)) ? -1 : 1;
161 });
162 }
163
164 /**
165 * Sets the flag which enables or disables autoloading support for functional
166 * test files.
167 *
168 * @param boolean $flag
169 * @return void
170 */
171 public function setConsiderTestsNamespace($flag) {
172 $this->considerTestsNamespace = $flag;
173 }
174 }