/wp-content/plugins/mailpoet/vendor-prefixed/doctrine/persistence/lib/Doctrine/Persistence/Mapping/AbstractClassMetadataFactory.php

https://gitlab.com/remyvianne/krowkaramel · PHP · 246 lines · 240 code · 0 blank · 6 comment · 24 complexity · ff7384daf79ca9af0215911a07cb4b92 MD5 · raw file

  1. <?php
  2. namespace MailPoetVendor\Doctrine\Persistence\Mapping;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoetVendor\Doctrine\Common\Cache\Cache;
  5. use MailPoetVendor\Doctrine\Common\Cache\Psr6\CacheAdapter;
  6. use MailPoetVendor\Doctrine\Common\Cache\Psr6\DoctrineProvider;
  7. use MailPoetVendor\Doctrine\Deprecations\Deprecation;
  8. use MailPoetVendor\Doctrine\Persistence\Mapping\Driver\MappingDriver;
  9. use MailPoetVendor\Doctrine\Persistence\Proxy;
  10. use MailPoetVendor\Psr\Cache\CacheItemPoolInterface;
  11. use ReflectionException;
  12. use function array_combine;
  13. use function array_keys;
  14. use function array_map;
  15. use function array_reverse;
  16. use function array_unshift;
  17. use function assert;
  18. use function explode;
  19. use function is_array;
  20. use function str_replace;
  21. use function strpos;
  22. use function strrpos;
  23. use function substr;
  24. abstract class AbstractClassMetadataFactory implements ClassMetadataFactory
  25. {
  26. protected $cacheSalt = '__CLASSMETADATA__';
  27. private $cacheDriver;
  28. private $cache;
  29. private $loadedMetadata = [];
  30. protected $initialized = \false;
  31. private $reflectionService = null;
  32. private $proxyClassNameResolver = null;
  33. public function setCacheDriver(?Cache $cacheDriver = null)
  34. {
  35. Deprecation::trigger('doctrine/persistence', 'https://github.com/doctrine/persistence/issues/184', '%s is deprecated. Use setCache() with a PSR-6 cache instead.', __METHOD__);
  36. $this->cacheDriver = $cacheDriver;
  37. if ($cacheDriver === null) {
  38. $this->cache = null;
  39. return;
  40. }
  41. $this->cache = CacheAdapter::wrap($cacheDriver);
  42. }
  43. public function getCacheDriver()
  44. {
  45. Deprecation::trigger('doctrine/persistence', 'https://github.com/doctrine/persistence/issues/184', '%s is deprecated. Use getCache() instead.', __METHOD__);
  46. return $this->cacheDriver;
  47. }
  48. public function setCache(CacheItemPoolInterface $cache) : void
  49. {
  50. $this->cache = $cache;
  51. $this->cacheDriver = DoctrineProvider::wrap($cache);
  52. }
  53. protected final function getCache() : ?CacheItemPoolInterface
  54. {
  55. return $this->cache;
  56. }
  57. public function getLoadedMetadata()
  58. {
  59. return $this->loadedMetadata;
  60. }
  61. public function getAllMetadata()
  62. {
  63. if (!$this->initialized) {
  64. $this->initialize();
  65. }
  66. $driver = $this->getDriver();
  67. $metadata = [];
  68. foreach ($driver->getAllClassNames() as $className) {
  69. $metadata[] = $this->getMetadataFor($className);
  70. }
  71. return $metadata;
  72. }
  73. public function setProxyClassNameResolver(ProxyClassNameResolver $resolver) : void
  74. {
  75. $this->proxyClassNameResolver = $resolver;
  76. }
  77. protected abstract function initialize();
  78. protected abstract function getFqcnFromAlias($namespaceAlias, $simpleClassName);
  79. protected abstract function getDriver();
  80. protected abstract function wakeupReflection(ClassMetadata $class, ReflectionService $reflService);
  81. protected abstract function initializeReflection(ClassMetadata $class, ReflectionService $reflService);
  82. protected abstract function isEntity(ClassMetadata $class);
  83. public function getMetadataFor($className)
  84. {
  85. if (isset($this->loadedMetadata[$className])) {
  86. return $this->loadedMetadata[$className];
  87. }
  88. // Check for namespace alias
  89. if (strpos($className, ':') !== \false) {
  90. [$namespaceAlias, $simpleClassName] = explode(':', $className, 2);
  91. $realClassName = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
  92. } else {
  93. $realClassName = $this->getRealClass($className);
  94. }
  95. if (isset($this->loadedMetadata[$realClassName])) {
  96. // We do not have the alias name in the map, include it
  97. return $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
  98. }
  99. $loadingException = null;
  100. try {
  101. if ($this->cache) {
  102. $cached = $this->cache->getItem($this->getCacheKey($realClassName))->get();
  103. if ($cached instanceof ClassMetadata) {
  104. $this->loadedMetadata[$realClassName] = $cached;
  105. $this->wakeupReflection($cached, $this->getReflectionService());
  106. } else {
  107. $loadedMetadata = $this->loadMetadata($realClassName);
  108. $classNames = array_combine(array_map([$this, 'getCacheKey'], $loadedMetadata), $loadedMetadata);
  109. assert(is_array($classNames));
  110. foreach ($this->cache->getItems(array_keys($classNames)) as $item) {
  111. if (!isset($classNames[$item->getKey()])) {
  112. continue;
  113. }
  114. $item->set($this->loadedMetadata[$classNames[$item->getKey()]]);
  115. $this->cache->saveDeferred($item);
  116. }
  117. $this->cache->commit();
  118. }
  119. } else {
  120. $this->loadMetadata($realClassName);
  121. }
  122. } catch (MappingException $loadingException) {
  123. $fallbackMetadataResponse = $this->onNotFoundMetadata($realClassName);
  124. if (!$fallbackMetadataResponse) {
  125. throw $loadingException;
  126. }
  127. $this->loadedMetadata[$realClassName] = $fallbackMetadataResponse;
  128. }
  129. if ($className !== $realClassName) {
  130. // We do not have the alias name in the map, include it
  131. $this->loadedMetadata[$className] = $this->loadedMetadata[$realClassName];
  132. }
  133. return $this->loadedMetadata[$className];
  134. }
  135. public function hasMetadataFor($className)
  136. {
  137. return isset($this->loadedMetadata[$className]);
  138. }
  139. public function setMetadataFor($className, $class)
  140. {
  141. $this->loadedMetadata[$className] = $class;
  142. }
  143. protected function getParentClasses($name)
  144. {
  145. // Collect parent classes, ignoring transient (not-mapped) classes.
  146. $parentClasses = [];
  147. foreach (array_reverse($this->getReflectionService()->getParentClasses($name)) as $parentClass) {
  148. if ($this->getDriver()->isTransient($parentClass)) {
  149. continue;
  150. }
  151. $parentClasses[] = $parentClass;
  152. }
  153. return $parentClasses;
  154. }
  155. protected function loadMetadata($name)
  156. {
  157. if (!$this->initialized) {
  158. $this->initialize();
  159. }
  160. $loaded = [];
  161. $parentClasses = $this->getParentClasses($name);
  162. $parentClasses[] = $name;
  163. // Move down the hierarchy of parent classes, starting from the topmost class
  164. $parent = null;
  165. $rootEntityFound = \false;
  166. $visited = [];
  167. $reflService = $this->getReflectionService();
  168. foreach ($parentClasses as $className) {
  169. if (isset($this->loadedMetadata[$className])) {
  170. $parent = $this->loadedMetadata[$className];
  171. if ($this->isEntity($parent)) {
  172. $rootEntityFound = \true;
  173. array_unshift($visited, $className);
  174. }
  175. continue;
  176. }
  177. $class = $this->newClassMetadataInstance($className);
  178. $this->initializeReflection($class, $reflService);
  179. $this->doLoadMetadata($class, $parent, $rootEntityFound, $visited);
  180. $this->loadedMetadata[$className] = $class;
  181. $parent = $class;
  182. if ($this->isEntity($class)) {
  183. $rootEntityFound = \true;
  184. array_unshift($visited, $className);
  185. }
  186. $this->wakeupReflection($class, $reflService);
  187. $loaded[] = $className;
  188. }
  189. return $loaded;
  190. }
  191. protected function onNotFoundMetadata($className)
  192. {
  193. return null;
  194. }
  195. protected abstract function doLoadMetadata($class, $parent, $rootEntityFound, array $nonSuperclassParents);
  196. protected abstract function newClassMetadataInstance($className);
  197. public function isTransient($class)
  198. {
  199. if (!$this->initialized) {
  200. $this->initialize();
  201. }
  202. // Check for namespace alias
  203. if (strpos($class, ':') !== \false) {
  204. [$namespaceAlias, $simpleClassName] = explode(':', $class, 2);
  205. $class = $this->getFqcnFromAlias($namespaceAlias, $simpleClassName);
  206. }
  207. return $this->getDriver()->isTransient($class);
  208. }
  209. public function setReflectionService(ReflectionService $reflectionService)
  210. {
  211. $this->reflectionService = $reflectionService;
  212. }
  213. public function getReflectionService()
  214. {
  215. if ($this->reflectionService === null) {
  216. $this->reflectionService = new RuntimeReflectionService();
  217. }
  218. return $this->reflectionService;
  219. }
  220. protected function getCacheKey(string $realClassName) : string
  221. {
  222. return str_replace('\\', '__', $realClassName) . $this->cacheSalt;
  223. }
  224. private function getRealClass(string $class) : string
  225. {
  226. if ($this->proxyClassNameResolver === null) {
  227. $this->createDefaultProxyClassNameResolver();
  228. }
  229. assert($this->proxyClassNameResolver !== null);
  230. return $this->proxyClassNameResolver->resolveClassName($class);
  231. }
  232. private function createDefaultProxyClassNameResolver() : void
  233. {
  234. $this->proxyClassNameResolver = new class implements ProxyClassNameResolver
  235. {
  236. public function resolveClassName(string $className) : string
  237. {
  238. $pos = strrpos($className, '\\' . Proxy::MARKER . '\\');
  239. if ($pos === \false) {
  240. return $className;
  241. }
  242. return substr($className, $pos + Proxy::MARKER_LENGTH + 2);
  243. }
  244. };
  245. }
  246. }