[BUGFIX] Exception in Locker if typo3temp does not exist
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Core / ClassLoader.php
1 <?php
2 namespace TYPO3\CMS\Core\Core;
3
4 /***************************************************************
5 * Copyright notice
6 *
7 * (c) 2013 Thomas Maroschik <tmaroschik@dfau.de>
8 * All rights reserved
9 *
10 * This script is part of the TYPO3 project. The TYPO3 project is
11 * free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * The GNU General Public License can be found at
17 * http://www.gnu.org/copyleft/gpl.html.
18 * A copy is found in the text file GPL.txt and important notices to the license
19 * from the author is found in LICENSE.txt distributed with these scripts.
20 *
21 *
22 * This script is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * This copyright notice MUST APPEAR in all copies of the script!
28 ***************************************************************/
29
30 use TYPO3\CMS\Core\Locking\Locker;
31 use TYPO3\CMS\Core\Package\PackageInterface;
32 use TYPO3\CMS\Core\Utility\GeneralUtility;
33 use TYPO3\CMS\Core\Cache;
34
35 /**
36 * Class Loader implementation which loads .php files found in the classes
37 * directory of an object.
38 */
39 class ClassLoader {
40
41 /**
42 * @var ClassAliasMap
43 */
44 protected $classAliasMap;
45
46 /**
47 * @var ClassAliasMap
48 */
49 static protected $staticAliasMap;
50
51 /**
52 * @var \TYPO3\CMS\Core\Cache\Frontend\StringFrontend
53 */
54 protected $classesCache;
55
56 /**
57 * @var \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend
58 */
59 protected $coreCache;
60
61 /**
62 * @var string
63 */
64 protected $cacheIdentifier;
65
66 /**
67 * @var \TYPO3\Flow\Package\Package[]
68 */
69 protected $packages = array();
70
71 /**
72 * @var bool
73 */
74 protected $isEarlyCache = TRUE;
75
76 /**
77 * @var array
78 */
79 protected $runtimeClassLoadingInformationCache = array();
80
81 /**
82 * @var array A list of namespaces this class loader is definitely responsible for
83 */
84 protected $packageNamespaces = array();
85
86 /**
87 * @var array A list of packages and their replaces pointing to class paths
88 */
89 protected $packageClassesPaths = array();
90
91 /**
92 * @var bool Is TRUE while loading the Locker class to prevent a deadlock in the implicit call to loadClass
93 */
94 protected $isLoadingLocker = FALSE;
95
96 /**
97 * @var \TYPO3\CMS\Core\Locking\Locker
98 */
99 protected $lockObject = NULL;
100
101 /**
102 * Constructor
103 *
104 * @param ApplicationContext $context
105 */
106 public function __construct(ApplicationContext $context) {
107 $this->classesCache = new Cache\Frontend\StringFrontend('cache_classes', new Cache\Backend\TransientMemoryBackend($context));
108 }
109
110 /**
111 * Get class alias map list injected
112 *
113 * @param ClassAliasMap
114 */
115 public function injectClassAliasMap(ClassAliasMap $classAliasMap) {
116 $this->classAliasMap = $classAliasMap;
117 static::$staticAliasMap = $classAliasMap;
118 }
119
120 /**
121 * Get core cache injected
122 *
123 * @param \TYPO3\CMS\Core\Cache\Frontend\PhpFrontend $coreCache
124 */
125 public function injectCoreCache(Cache\Frontend\PhpFrontend $coreCache) {
126 $this->coreCache = $coreCache;
127 $this->classAliasMap->injectCoreCache($coreCache);
128 }
129
130 /**
131 * Get classes cache injected
132 *
133 * @param \TYPO3\CMS\Core\Cache\Frontend\StringFrontend $classesCache
134 */
135 public function injectClassesCache(Cache\Frontend\StringFrontend $classesCache) {
136 $earlyClassesCache = $this->classesCache;
137 $this->classesCache = $classesCache;
138 $this->isEarlyCache = FALSE;
139 $this->classAliasMap->injectClassesCache($classesCache);
140 foreach ($earlyClassesCache->getByTag('early') as $originalClassLoadingInformation) {
141 $classLoadingInformation = explode("\xff", $originalClassLoadingInformation);
142 $cacheEntryIdentifier = strtolower(str_replace('\\', '_', $classLoadingInformation[1]));
143 if (!$this->classesCache->has($cacheEntryIdentifier)) {
144 $this->classesCache->set($cacheEntryIdentifier, $originalClassLoadingInformation);
145 }
146 }
147 }
148
149 /**
150 * Loads php files containing classes or interfaces found in the classes directory of
151 * a package and specifically registered classes.
152 *
153 * Caution: This function may be called "recursively" by the spl_autoloader if a class depends on another classes.
154 *
155 * @param string $className Name of the class/interface to load
156 * @return bool
157 */
158 public function loadClass($className) {
159 if ($className[0] === '\\') {
160 $className = substr($className, 1);
161 }
162
163 if (!$this->isValidClassName($className)) {
164 return FALSE;
165 }
166
167 $cacheEntryIdentifier = strtolower(str_replace('\\', '_', $className));
168 $classLoadingInformation = $this->getClassLoadingInformationFromCache($cacheEntryIdentifier);
169
170 if ($classLoadingInformation === NULL) {
171 $classLoadingInformation = $this->buildCachedClassLoadingInformation($cacheEntryIdentifier, $className);
172 }
173
174 // Class loading information structure
175 // array(
176 // 0 => class file path
177 // 1 => original class name
178 // 2 and following => alias class names
179 // )
180 $loadingSuccessful = FALSE;
181 if ($classLoadingInformation !== NULL) {
182 // The call to class_exists fixes a rare case when early instances need to be aliased
183 // but PHP fails to recognize the real path of the class. See #55904
184 $loadingSuccessful = class_exists($classLoadingInformation[1], FALSE) || (bool)require_once $classLoadingInformation[0];
185 }
186 if ($loadingSuccessful && count($classLoadingInformation) > 2) {
187 $originalClassName = $classLoadingInformation[1];
188 foreach (array_slice($classLoadingInformation, 2) as $aliasClassName) {
189 $this->setAliasForClassName($aliasClassName, $originalClassName);
190 }
191 }
192
193 return $loadingSuccessful;
194 }
195
196 /**
197 * Get class loading information for the given identifier for cache
198 *
199 * @param string $cacheEntryIdentifier The identifier to fetch entry from cache
200 * @return array|null The class information or NULL if class information was not found in cache
201 */
202 public function getClassLoadingInformationFromCache($cacheEntryIdentifier) {
203 try {
204 $rawClassLoadingInformation = $this->classesCache->get($cacheEntryIdentifier);
205 } catch (\InvalidArgumentException $exception) {
206 return NULL;
207 }
208
209 if ($rawClassLoadingInformation !== FALSE && $rawClassLoadingInformation !== '') {
210 return explode("\xff", $rawClassLoadingInformation);
211 }
212 return NULL;
213 }
214
215 /**
216 * Builds the class loading information and writes it to the cache. It handles Locking for this cache.
217 *
218 * Caution: The function loadClass can be called "recursively" by spl_autoloader. This needs to be observed when
219 * locking for cache access. Only the first call to loadClass may acquire and release the lock!
220 *
221 * @param string $cacheEntryIdentifier Cache identifier for this class
222 * @param string $className Name of class this information is for
223 *
224 * @return array|null The class information or NULL if class was not found
225 */
226 protected function buildCachedClassLoadingInformation($cacheEntryIdentifier, $className) {
227 // We do not need locking if we are in earlyCache mode
228 $didLock = FALSE;
229 if (!$this->isEarlyCache) {
230 $didLock = $this->acquireLock();
231 }
232
233 // Look again into the cache after we got the lock, data might have been generated meanwhile
234 $classLoadingInformation = $this->getClassLoadingInformationFromCache($cacheEntryIdentifier);
235 if ($classLoadingInformation === NULL) {
236 $classLoadingInformation = $this->buildClassLoadingInformation($className);
237
238 if ($classLoadingInformation !== NULL) {
239 $this->classesCache->set(
240 $cacheEntryIdentifier,
241 implode("\xff", $classLoadingInformation),
242 $this->isEarlyCache ? array('early') : array()
243 );
244 } elseif (!$this->isEarlyCache) {
245 $this->classesCache->set($cacheEntryIdentifier, '');
246 }
247 }
248
249 $this->releaseLock($didLock);
250
251 return $classLoadingInformation;
252 }
253
254 /**
255 * Builds the class loading information
256 *
257 * @param string $className Name of class this information is for
258 *
259 * @return array|null The class information or NULL if class was not found
260 */
261 public function buildClassLoadingInformation($className) {
262 $classLoadingInformation = $this->buildClassLoadingInformationForClassFromCorePackage($className);
263
264 if ($classLoadingInformation === NULL) {
265 $classLoadingInformation = $this->fetchClassLoadingInformationFromRuntimeCache($className);
266 }
267
268 if ($classLoadingInformation === NULL) {
269 $classLoadingInformation = $this->buildClassLoadingInformationForClassFromRegisteredPackages($className);
270 }
271
272 if ($classLoadingInformation === NULL) {
273 $classLoadingInformation = $this->buildClassLoadingInformationForClassByNamingConvention($className);
274 }
275
276 return $classLoadingInformation;
277 }
278
279 /**
280 * Find out if a class name is valid
281 *
282 * @param string $className
283 * @return bool
284 */
285 protected function isValidClassName($className) {
286 return strpos($className, ' ') === FALSE;
287 }
288
289 /**
290 * Retrieve class loading information for class from core package
291 *
292 * @param string $className
293 * @return array|null
294 */
295 protected function buildClassLoadingInformationForClassFromCorePackage($className) {
296 if (substr($className, 0, 14) === 'TYPO3\\CMS\\Core') {
297 $classesFolder = substr($className, 15, 5) === 'Tests' ? '' : 'Classes/';
298 $classFilePath = PATH_typo3 . 'sysext/core/' . $classesFolder . str_replace('\\', '/', substr($className, 15)) . '.php';
299 if (@file_exists($classFilePath)) {
300 return array($classFilePath, $className);
301 }
302 }
303 return NULL;
304 }
305
306 /**
307 * Retrieve class loading information from early class name autoload registry cache
308 *
309 * @param string $className
310 * @return array|null
311 */
312 protected function fetchClassLoadingInformationFromRuntimeCache($className) {
313 $lowercasedClassName = strtolower($className);
314 if (!isset($this->runtimeClassLoadingInformationCache[$lowercasedClassName])) {
315 return NULL;
316 }
317 $classInformation = $this->runtimeClassLoadingInformationCache[$lowercasedClassName];
318 return @file_exists($classInformation[0]) ? $classInformation : NULL;
319 }
320
321 /**
322 * Retrieve class loading information from registered packages
323 *
324 * @param string $className
325 * @return array|null
326 */
327 protected function buildClassLoadingInformationForClassFromRegisteredPackages($className) {;
328 foreach ($this->packageNamespaces as $packageNamespace => $packageData) {
329 if (substr(str_replace('_', '\\', $className), 0, $packageData['namespaceLength']) === $packageNamespace) {
330 if ($packageData['substituteNamespaceInPath']) {
331 // If it's a TYPO3 package, classes don't comply to PSR-0.
332 // The namespace part is substituted.
333 $classPathAndFilename = '/' . str_replace('\\', '/', ltrim(substr($className, $packageData['namespaceLength']), '\\')) . '.php';
334 } else {
335 // Make the classname PSR-0 compliant by replacing underscores only in the classname not in the namespace
336 $classPathAndFilename = '';
337 $lastNamespacePosition = strrpos($className, '\\');
338 if ($lastNamespacePosition !== FALSE) {
339 $namespace = substr($className, 0, $lastNamespacePosition);
340 $className = substr($className, $lastNamespacePosition + 1);
341 $classPathAndFilename = str_replace('\\', '/', $namespace) . '/';
342 }
343 $classPathAndFilename .= str_replace('_', '/', $className) . '.php';
344 }
345 if (strtolower(substr($className, $packageData['namespaceLength'], 5)) === 'tests') {
346 $classPathAndFilename = $packageData['packagePath'] . $classPathAndFilename;
347 } else {
348 $classPathAndFilename = $packageData['classesPath'] . $classPathAndFilename;
349 }
350 if (@file_exists($classPathAndFilename)) {
351 return array($classPathAndFilename, $className);
352 }
353 }
354 }
355 return NULL;
356 }
357
358 /**
359 * Retrieve class loading information based on 'extbase' naming convention into the registry.
360 *
361 * @param string $className Class name to find source file of
362 * @return array|null
363 */
364 protected function buildClassLoadingInformationForClassByNamingConvention($className) {
365 $delimiter = '_';
366 // To handle namespaced class names, split the class name at the
367 // namespace delimiters.
368 if (strpos($className, '\\') !== FALSE) {
369 $delimiter = '\\';
370 }
371
372 $classNameParts = explode($delimiter, $className, 4);
373
374 // We only handle classes that follow the convention Vendor\Product\Classname or is longer
375 // so we won't deal with class names that only have one or two parts
376 if (count($classNameParts) <= 2) {
377 return NULL;
378 }
379
380 if (
381 isset($classNameParts[0])
382 && isset($classNameParts[1])
383 && $classNameParts[0] === 'TYPO3'
384 && $classNameParts[1] === 'CMS'
385 ) {
386 $extensionKey = GeneralUtility::camelCaseToLowerCaseUnderscored($classNameParts[2]);
387 $classNameWithoutVendorAndProduct = $classNameParts[3];
388 } else {
389 $extensionKey = GeneralUtility::camelCaseToLowerCaseUnderscored($classNameParts[1]);
390 $classNameWithoutVendorAndProduct = $classNameParts[2];
391
392 if (isset($classNameParts[3])) {
393 $classNameWithoutVendorAndProduct .= $delimiter . $classNameParts[3];
394 }
395 }
396
397 if ($extensionKey && isset($this->packageClassesPaths[$extensionKey])) {
398 if (substr(strtolower($classNameWithoutVendorAndProduct), 0, 5) === 'tests') {
399 $classesPath = $this->packages[$extensionKey]->getPackagePath();
400 } else {
401 $classesPath = $this->packageClassesPaths[$extensionKey];
402 }
403 $classFilePath = $classesPath . strtr($classNameWithoutVendorAndProduct, $delimiter, '/') . '.php';
404 if (@file_exists($classFilePath)) {
405 return array($classFilePath, $className);
406 }
407 }
408
409 return NULL;
410 }
411
412 /**
413 * Get cache entry identifier for the package namespaces cache
414 *
415 * @return string|null identifier
416 */
417 protected function getCacheEntryIdentifier() {
418 return $this->cacheIdentifier !== NULL
419 ? 'ClassLoader_' . $this->cacheIdentifier
420 : NULL;
421 }
422
423 /**
424 * Set cache identifier
425 *
426 * @param string $cacheIdentifier Cache identifier for package namespaces cache
427 * @return ClassLoader
428 */
429 public function setCacheIdentifier($cacheIdentifier) {
430 $this->cacheIdentifier = $cacheIdentifier;
431 return $this;
432 }
433
434 /**
435 * Sets the available packages
436 *
437 * @param array $packages An array of \TYPO3\Flow\Package\Package objects
438 * @return ClassLoader
439 */
440 public function setPackages(array $packages) {
441 $this->packages = $packages;
442
443 if (!$this->loadPackageNamespacesFromCache()) {
444 $this->buildPackageNamespacesAndClassesPaths();
445 } else {
446 $this->classAliasMap->setPackages($packages);
447 }
448 // Clear the runtime cache for runtime activated packages
449 $this->runtimeClassLoadingInformationCache = array();
450 return $this;
451 }
452
453 /**
454 * Add a package to class loader just during runtime, so classes can be loaded without the need for a new request
455 *
456 * @param \TYPO3\Flow\Package\PackageInterface $package
457 * @return ClassLoader
458 */
459 public function addActivePackage(\TYPO3\Flow\Package\PackageInterface $package) {
460 $packageKey = $package->getPackageKey();
461 if (!isset($this->packages[$packageKey])) {
462 $this->packages[$packageKey] = $package;
463 $this->buildPackageNamespaceAndClassesPath($package);
464 $this->sortPackageNamespaces();
465 $this->loadClassFilesFromAutoloadRegistryIntoRuntimeClassInformationCache(array($package));
466 }
467 return $this;
468 }
469
470 /**
471 * Builds the package namespaces and classes paths for the given packages
472 *
473 * @return void
474 */
475 protected function buildPackageNamespacesAndClassesPaths() {
476 $didLock = $this->acquireLock();
477
478 // Take a look again, after lock is acquired
479 if (!$this->loadPackageNamespacesFromCache()) {
480 foreach ($this->packages as $package) {
481 $this->buildPackageNamespaceAndClassesPath($package);
482 }
483 $this->sortPackageNamespaces();
484 $this->savePackageNamespacesAndClassesPathsToCache();
485 // The class alias map has to be rebuilt first, because ext_autoload files can contain
486 // old class names that need established class aliases.
487 $classNameToAliasMapping = $this->classAliasMap->setPackages($this->packages)->buildMappingAndInitializeEarlyInstanceMapping();
488 $this->loadClassFilesFromAutoloadRegistryIntoRuntimeClassInformationCache($this->packages);
489 $this->classAliasMap->buildMappingFiles($classNameToAliasMapping);
490 $this->transferRuntimeClassInformationCacheEntriesToClassesCache();
491 }
492
493 $this->releaseLock($didLock);
494 }
495
496 /**
497 * Builds the namespace and class paths for a single package
498 *
499 * @param \TYPO3\Flow\Package\PackageInterface $package
500 * @return void
501 */
502 protected function buildPackageNamespaceAndClassesPath(\TYPO3\Flow\Package\PackageInterface $package) {
503 if ($package instanceof \TYPO3\Flow\Package\PackageInterface) {
504 $this->buildPackageNamespace($package);
505 }
506 if ($package instanceof PackageInterface) {
507 $this->buildPackageClassPathsForLegacyExtension($package);
508 }
509 }
510
511 /**
512 * Load package namespaces from cache
513 *
514 * @return bool TRUE if package namespaces were loaded
515 */
516 protected function loadPackageNamespacesFromCache() {
517 $cacheEntryIdentifier = $this->getCacheEntryIdentifier();
518 if ($cacheEntryIdentifier === NULL) {
519 return FALSE;
520 }
521 $packageData = $this->coreCache->requireOnce($cacheEntryIdentifier);
522 if ($packageData !== FALSE) {
523 list($packageNamespaces, $packageClassesPaths) = $packageData;
524 if (is_array($packageNamespaces) && is_array($packageClassesPaths)) {
525 $this->packageNamespaces = $packageNamespaces;
526 $this->packageClassesPaths = $packageClassesPaths;
527 return TRUE;
528 }
529 }
530 return FALSE;
531 }
532
533 /**
534 * Extracts the namespace from a package
535 *
536 * @param \TYPO3\Flow\Package\PackageInterface $package
537 * @return void
538 */
539 protected function buildPackageNamespace(\TYPO3\Flow\Package\PackageInterface $package) {
540 $packageNamespace = $package->getNamespace();
541 // Ignore legacy extensions with unkown vendor name
542 if ($packageNamespace[0] !== '*') {
543 $this->packageNamespaces[$packageNamespace] = array(
544 'namespaceLength' => strlen($packageNamespace),
545 'classesPath' => $package->getClassesPath(),
546 'packagePath' => $package->getPackagePath(),
547 'substituteNamespaceInPath' => ($package instanceof PackageInterface)
548 );
549 }
550 }
551
552 /**
553 * Save autoload registry to cache
554 *
555 * @param array $packages
556 * @return void
557 */
558 protected function loadClassFilesFromAutoloadRegistryIntoRuntimeClassInformationCache(array $packages) {
559 $classFileAutoloadRegistry = array();
560 foreach ($packages as $package) {
561 if ($package instanceof PackageInterface) {
562 $classFilesFromAutoloadRegistry = $package->getClassFilesFromAutoloadRegistry();
563 if (is_array($classFilesFromAutoloadRegistry)) {
564 $classFileAutoloadRegistry = array_merge($classFileAutoloadRegistry, $classFilesFromAutoloadRegistry);
565 }
566 }
567 }
568 foreach ($classFileAutoloadRegistry as $className => $classFilePath) {
569 $lowercasedClassName = strtolower($className);
570 if (!isset($this->runtimeClassLoadingInformationCache[$lowercasedClassName]) && @file_exists($classFilePath)) {
571 $this->runtimeClassLoadingInformationCache[$lowercasedClassName] = array($classFilePath, $className);
572 }
573 }
574 }
575
576 /**
577 * Transfers all entries from the early class information cache to
578 * the classes cache in order to make them persistent
579 *
580 * @return void
581 */
582 protected function transferRuntimeClassInformationCacheEntriesToClassesCache() {
583 foreach ($this->runtimeClassLoadingInformationCache as $classLoadingInformation) {
584 $cacheEntryIdentifier = strtolower(str_replace('\\', '_', $classLoadingInformation[1]));
585 if (!$this->classesCache->has($cacheEntryIdentifier)) {
586 $this->classesCache->set($cacheEntryIdentifier, implode("\xff", $classLoadingInformation));
587 }
588 }
589 }
590
591 /**
592 * @param PackageInterface $package
593 * @return void
594 */
595 protected function buildPackageClassPathsForLegacyExtension(PackageInterface $package) {
596 $this->packageClassesPaths[$package->getPackageKey()] = $package->getClassesPath();
597 foreach (array_keys($package->getPackageReplacementKeys()) as $packageToReplace) {
598 $this->packageClassesPaths[$packageToReplace] = $package->getClassesPath();
599 }
600 }
601
602 /**
603 * Save package namespaces and classes paths to cache
604 *
605 * @return void
606 */
607 protected function savePackageNamespacesAndClassesPathsToCache() {
608 $cacheEntryIdentifier = $this->getCacheEntryIdentifier();
609 if ($cacheEntryIdentifier !== NULL) {
610 $this->coreCache->set(
611 $this->getCacheEntryIdentifier(),
612 'return ' . var_export(array($this->packageNamespaces, $this->packageClassesPaths), TRUE) . ';'
613 );
614 }
615 }
616
617 /**
618 * Sorts longer package namespaces first, to find specific matches before generic ones
619 *
620 * @return void
621 */
622 protected function sortPackageNamespaces() {
623 $sortPackages = function ($a, $b) {
624 if (($lenA = strlen($a)) === ($lenB = strlen($b))) {
625 return strcmp($a, $b);
626 }
627 return $lenA > $lenB ? -1 : 1;
628 };
629 uksort($this->packageNamespaces, $sortPackages);
630 }
631
632 /**
633 * This method is necessary for the early loading of the cores autoload registry
634 *
635 * @param array $classFileAutoloadRegistry
636 * @return void
637 */
638 public function setRuntimeClassLoadingInformationFromAutoloadRegistry(array $classFileAutoloadRegistry) {
639 foreach ($classFileAutoloadRegistry as $className => $classFilePath) {
640 $lowercasedClassName = strtolower($className);
641 if (!isset($this->runtimeClassLoadingInformationCache[$lowercasedClassName])) {
642 $this->runtimeClassLoadingInformationCache[$lowercasedClassName] = array($classFilePath, $className);
643 }
644 }
645 }
646
647 /**
648 * Set alias for class name
649 *
650 * @param string $aliasClassName
651 * @param string $originalClassName
652 * @return bool
653 */
654 public function setAliasForClassName($aliasClassName, $originalClassName) {
655 return $this->classAliasMap->setAliasForClassName($aliasClassName, $originalClassName);
656 }
657
658 /**
659 * Get class name for alias
660 *
661 * @param string $alias
662 * @return mixed
663 */
664 static public function getClassNameForAlias($alias) {
665 return static::$staticAliasMap->getClassNameForAlias($alias);
666 }
667
668 /**
669 * Get alias for class name
670 *
671 * @param string $className
672 * @return mixed
673 * @deprecated since 6.2, will be removed 2 versions later - use getAliasesForClassName() instead
674 */
675 static public function getAliasForClassName($className) {
676 GeneralUtility::logDeprecatedFunction();
677 $aliases = static::$staticAliasMap->getAliasesForClassName($className);
678 return is_array($aliases) && isset($aliases[0]) ? $aliases[0] : NULL;
679 }
680
681 /**
682 * Get an aliases for a class name
683 *
684 * @param string $className
685 * @return mixed
686 */
687 static public function getAliasesForClassName($className) {
688 return static::$staticAliasMap->getAliasesForClassName($className);
689 }
690
691 /**
692 * Acquires a lock for the cache if we didn't already lock before.
693 *
694 * @return bool TRUE if the cache was acquired by this call and needs to be released
695 * @throws \RuntimeException
696 */
697 protected function acquireLock() {
698 if (!$this->isLoadingLocker) {
699 $lockObject = $this->getLocker();
700
701 if ($lockObject === NULL) {
702 // During installation typo3temp does not yet exist, so the locker can not
703 // do its job. In this case it does not need to be released again.
704 return FALSE;
705 }
706
707 // We didn't lock yet so do it
708 if (!$lockObject->getLockStatus()) {
709 if (!$lockObject->acquireExclusiveLock()) {
710 throw new \RuntimeException('Could not acquire lock for ClassLoader cache creation.', 1394480725);
711 }
712 return TRUE;
713 }
714 }
715 return FALSE;
716 }
717
718 /**
719 * Releases a lock
720 *
721 * @param bool $needRelease The result of the call to acquireLock()
722 *
723 * @return void
724 */
725 protected function releaseLock($needRelease) {
726 if ($needRelease) {
727 $lockObject = $this->getLocker();
728 $lockObject->release();
729 }
730 }
731
732 /**
733 * Gets the TYPO3 Locker object or creates an instance of it.
734 *
735 * @throws \RuntimeException
736 * @return \TYPO3\CMS\Core\Locking\Locker|NULL Only NULL if we are in installer and typo3temp does not exist yet
737 */
738 protected function getLocker() {
739 if (NULL === $this->lockObject) {
740 $this->isLoadingLocker = TRUE;
741
742 try {
743 $this->lockObject = new Locker('ClassLoader-cache-classes', Locker::LOCKING_METHOD_SIMPLE);
744 } catch (\RuntimeException $e) {
745 // The RuntimeException in constructor happens if directory typo3temp/locks could not be created.
746 // This usually happens during installation step 1 where typo3temp itself does not exist yet. In
747 // this case we proceed without locking, otherwise a missing typo3temp directory indicates a
748 // hard problem of the instance and we throw up.
749 // @TODO: This solution currently conflicts with separation of concerns since the class loader
750 // handles installation specific stuff. Find a better way to do this.
751 if (defined('TYPO3_enterInstallScript') && TYPO3_enterInstallScript) {
752 // Installer is running => So work without Locking.
753 return NULL;
754 } else {
755 throw $e;
756 }
757 }
758 $this->lockObject->setEnableLogging(FALSE);
759 $this->isLoadingLocker = FALSE;
760 }
761
762 return $this->lockObject;
763 }
764 }