FileDriver.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. <?php
  2. namespace Doctrine\Persistence\Mapping\Driver;
  3. use Doctrine\Persistence\Mapping\ClassMetadata;
  4. use Doctrine\Persistence\Mapping\MappingException;
  5. use function array_keys;
  6. use function array_merge;
  7. use function array_unique;
  8. use function is_file;
  9. use function str_replace;
  10. /**
  11. * Base driver for file-based metadata drivers.
  12. *
  13. * A file driver operates in a mode where it loads the mapping files of individual
  14. * classes on demand. This requires the user to adhere to the convention of 1 mapping
  15. * file per class and the file names of the mapping files must correspond to the full
  16. * class name, including namespace, with the namespace delimiters '\', replaced by dots '.'.
  17. */
  18. abstract class FileDriver implements MappingDriver
  19. {
  20. /** @var FileLocator */
  21. protected $locator;
  22. /** @var ClassMetadata[]|null */
  23. protected $classCache;
  24. /** @var string|null */
  25. protected $globalBasename;
  26. /**
  27. * Initializes a new FileDriver that looks in the given path(s) for mapping
  28. * documents and operates in the specified operating mode.
  29. *
  30. * @param string|string[]|FileLocator $locator A FileLocator or one/multiple paths
  31. * where mapping documents can be found.
  32. * @param string|null $fileExtension
  33. */
  34. public function __construct($locator, $fileExtension = null)
  35. {
  36. if ($locator instanceof FileLocator) {
  37. $this->locator = $locator;
  38. } else {
  39. $this->locator = new DefaultFileLocator((array) $locator, $fileExtension);
  40. }
  41. }
  42. /**
  43. * Sets the global basename.
  44. *
  45. * @param string $file
  46. *
  47. * @return void
  48. */
  49. public function setGlobalBasename($file)
  50. {
  51. $this->globalBasename = $file;
  52. }
  53. /**
  54. * Retrieves the global basename.
  55. *
  56. * @return string|null
  57. */
  58. public function getGlobalBasename()
  59. {
  60. return $this->globalBasename;
  61. }
  62. /**
  63. * Gets the element of schema meta data for the class from the mapping file.
  64. * This will lazily load the mapping file if it is not loaded yet.
  65. *
  66. * @param string $className
  67. *
  68. * @return ClassMetadata The element of schema meta data.
  69. *
  70. * @throws MappingException
  71. */
  72. public function getElement($className)
  73. {
  74. if ($this->classCache === null) {
  75. $this->initialize();
  76. }
  77. if (isset($this->classCache[$className])) {
  78. return $this->classCache[$className];
  79. }
  80. $result = $this->loadMappingFile($this->locator->findMappingFile($className));
  81. if (! isset($result[$className])) {
  82. throw MappingException::invalidMappingFile($className, str_replace('\\', '.', $className) . $this->locator->getFileExtension());
  83. }
  84. $this->classCache[$className] = $result[$className];
  85. return $result[$className];
  86. }
  87. /**
  88. * {@inheritDoc}
  89. */
  90. public function isTransient($className)
  91. {
  92. if ($this->classCache === null) {
  93. $this->initialize();
  94. }
  95. if (isset($this->classCache[$className])) {
  96. return false;
  97. }
  98. return ! $this->locator->fileExists($className);
  99. }
  100. /**
  101. * {@inheritDoc}
  102. */
  103. public function getAllClassNames()
  104. {
  105. if ($this->classCache === null) {
  106. $this->initialize();
  107. }
  108. if (! $this->classCache) {
  109. return (array) $this->locator->getAllClassNames($this->globalBasename);
  110. }
  111. return array_unique(array_merge(
  112. array_keys($this->classCache),
  113. (array) $this->locator->getAllClassNames($this->globalBasename)
  114. ));
  115. }
  116. /**
  117. * Loads a mapping file with the given name and returns a map
  118. * from class/entity names to their corresponding file driver elements.
  119. *
  120. * @param string $file The mapping file to load.
  121. *
  122. * @return ClassMetadata[]
  123. */
  124. abstract protected function loadMappingFile($file);
  125. /**
  126. * Initializes the class cache from all the global files.
  127. *
  128. * Using this feature adds a substantial performance hit to file drivers as
  129. * more metadata has to be loaded into memory than might actually be
  130. * necessary. This may not be relevant to scenarios where caching of
  131. * metadata is in place, however hits very hard in scenarios where no
  132. * caching is used.
  133. *
  134. * @return void
  135. */
  136. protected function initialize()
  137. {
  138. $this->classCache = [];
  139. if ($this->globalBasename === null) {
  140. return;
  141. }
  142. foreach ($this->locator->getPaths() as $path) {
  143. $file = $path . '/' . $this->globalBasename . $this->locator->getFileExtension();
  144. if (! is_file($file)) {
  145. continue;
  146. }
  147. $this->classCache = array_merge(
  148. $this->classCache,
  149. $this->loadMappingFile($file)
  150. );
  151. }
  152. }
  153. /**
  154. * Retrieves the locator used to discover mapping files by className.
  155. *
  156. * @return FileLocator
  157. */
  158. public function getLocator()
  159. {
  160. return $this->locator;
  161. }
  162. /**
  163. * Sets the locator used to discover mapping files by className.
  164. */
  165. public function setLocator(FileLocator $locator)
  166. {
  167. $this->locator = $locator;
  168. }
  169. }