1<?php 2 3/* 4 * This file is part of the TYPO3 CMS project. 5 * 6 * It is free software; you can redistribute it and/or modify it under 7 * the terms of the GNU General Public License, either version 2 8 * of the License, or any later version. 9 * 10 * For the full copyright and license information, please read the 11 * LICENSE.txt file that was distributed with this source code. 12 * 13 * The TYPO3 project - inspiring people to share! 14 */ 15 16namespace TYPO3\CMS\Extbase\Reflection; 17 18use TYPO3\CMS\Core\Cache\CacheManager; 19use TYPO3\CMS\Core\Cache\Exception\NoSuchCacheException; 20use TYPO3\CMS\Core\Cache\Frontend\FrontendInterface; 21use TYPO3\CMS\Core\Core\Environment; 22use TYPO3\CMS\Core\Information\Typo3Version; 23use TYPO3\CMS\Core\SingletonInterface; 24use TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException; 25 26/** 27 * Reflection service for acquiring reflection based information. 28 * Originally based on the TYPO3.Flow reflection service. 29 */ 30class ReflectionService implements SingletonInterface 31{ 32 /** 33 * @var string 34 */ 35 private static $cacheEntryIdentifier; 36 37 /** 38 * @var FrontendInterface 39 */ 40 protected $dataCache; 41 42 /** 43 * Indicates whether the Reflection cache needs to be updated. 44 * 45 * This flag needs to be set as soon as new Reflection information was 46 * created. 47 * 48 * @var bool 49 */ 50 protected $dataCacheNeedsUpdate = false; 51 52 /** 53 * Local cache for Class schemata 54 * 55 * @var array 56 */ 57 protected $classSchemata = []; 58 59 /** 60 * @var bool 61 */ 62 private $cachingEnabled = false; 63 64 /** 65 * If not $cacheManager is injected, the reflection service does not 66 * cache any data, useful for testing this service in unit tests. 67 * 68 * @param CacheManager $cacheManager 69 */ 70 public function __construct(CacheManager $cacheManager = null) 71 { 72 if ($cacheManager instanceof CacheManager) { 73 try { 74 $this->dataCache = $cacheManager->getCache('extbase'); 75 $this->cachingEnabled = true; 76 } catch (NoSuchCacheException $ignoredException) { 77 $this->cachingEnabled = false; 78 } 79 80 if ($this->cachingEnabled) { 81 static::$cacheEntryIdentifier = 'ClassSchemata_' . sha1((string)(new Typo3Version()) . Environment::getProjectPath()); 82 if (($classSchemata = $this->dataCache->get(static::$cacheEntryIdentifier)) !== false) { 83 $this->classSchemata = $classSchemata; 84 } 85 } 86 } 87 } 88 89 public function __destruct() 90 { 91 if ($this->dataCacheNeedsUpdate && $this->cachingEnabled) { 92 $this->dataCache->set(static::$cacheEntryIdentifier, $this->classSchemata); 93 } 94 } 95 96 /** 97 * Returns the class schema for the given class 98 * 99 * @param mixed $classNameOrObject The class name or an object 100 * @return ClassSchema 101 * @throws \TYPO3\CMS\Extbase\Reflection\Exception\UnknownClassException 102 */ 103 public function getClassSchema($classNameOrObject): ClassSchema 104 { 105 $className = is_object($classNameOrObject) ? get_class($classNameOrObject) : $classNameOrObject; 106 if (isset($this->classSchemata[$className])) { 107 return $this->classSchemata[$className]; 108 } 109 110 return $this->buildClassSchema($className); 111 } 112 113 /** 114 * Builds class schemata from classes annotated as entities or value objects 115 * 116 * @param string $className 117 * @throws Exception\UnknownClassException 118 * @return ClassSchema The class schema 119 */ 120 protected function buildClassSchema($className): ClassSchema 121 { 122 try { 123 $classSchema = new ClassSchema($className); 124 } catch (\ReflectionException $e) { 125 throw new UnknownClassException($e->getMessage() . '. Reflection failed.', 1278450972, $e); 126 } 127 $this->classSchemata[$className] = $classSchema; 128 $this->dataCacheNeedsUpdate = true; 129 return $classSchema; 130 } 131 132 /** 133 * @internal 134 */ 135 public function __sleep(): array 136 { 137 return []; 138 } 139 140 /** 141 * @internal 142 */ 143 public function __wakeup(): void 144 { 145 $this->dataCache = null; 146 $this->dataCacheNeedsUpdate = false; 147 $this->classSchemata = []; 148 $this->cachingEnabled = false; 149 } 150} 151