vendor/doctrine/persistence/src/Persistence/Mapping/Driver/ColocatedMappingDriver.php line 140

Open in your IDE?
  1. <?php
  2. namespace Doctrine\Persistence\Mapping\Driver;
  3. use Doctrine\Persistence\Mapping\MappingException;
  4. use FilesystemIterator;
  5. use RecursiveDirectoryIterator;
  6. use RecursiveIteratorIterator;
  7. use RecursiveRegexIterator;
  8. use ReflectionClass;
  9. use RegexIterator;
  10. use function array_merge;
  11. use function array_unique;
  12. use function assert;
  13. use function get_declared_classes;
  14. use function in_array;
  15. use function is_dir;
  16. use function preg_match;
  17. use function preg_quote;
  18. use function realpath;
  19. use function str_replace;
  20. use function strpos;
  21. /**
  22. * The ColocatedMappingDriver reads the mapping metadata located near the code.
  23. */
  24. trait ColocatedMappingDriver
  25. {
  26. /**
  27. * The paths where to look for mapping files.
  28. *
  29. * @var string[]
  30. */
  31. protected $paths = [];
  32. /**
  33. * The paths excluded from path where to look for mapping files.
  34. *
  35. * @var string[]
  36. */
  37. protected $excludePaths = [];
  38. /**
  39. * The file extension of mapping documents.
  40. *
  41. * @var string
  42. */
  43. protected $fileExtension = '.php';
  44. /**
  45. * Cache for getAllClassNames().
  46. *
  47. * @var string[]|null
  48. * @psalm-var list<class-string>|null
  49. */
  50. protected $classNames;
  51. /**
  52. * Appends lookup paths to metadata driver.
  53. *
  54. * @param string[] $paths
  55. *
  56. * @return void
  57. */
  58. public function addPaths(array $paths)
  59. {
  60. $this->paths = array_unique(array_merge($this->paths, $paths));
  61. }
  62. /**
  63. * Retrieves the defined metadata lookup paths.
  64. *
  65. * @return string[]
  66. */
  67. public function getPaths()
  68. {
  69. return $this->paths;
  70. }
  71. /**
  72. * Append exclude lookup paths to metadata driver.
  73. *
  74. * @param string[] $paths
  75. *
  76. * @return void
  77. */
  78. public function addExcludePaths(array $paths)
  79. {
  80. $this->excludePaths = array_unique(array_merge($this->excludePaths, $paths));
  81. }
  82. /**
  83. * Retrieve the defined metadata lookup exclude paths.
  84. *
  85. * @return string[]
  86. */
  87. public function getExcludePaths()
  88. {
  89. return $this->excludePaths;
  90. }
  91. /**
  92. * Gets the file extension used to look for mapping files under.
  93. *
  94. * @return string
  95. */
  96. public function getFileExtension()
  97. {
  98. return $this->fileExtension;
  99. }
  100. /**
  101. * Sets the file extension used to look for mapping files under.
  102. *
  103. * @return void
  104. */
  105. public function setFileExtension(string $fileExtension)
  106. {
  107. $this->fileExtension = $fileExtension;
  108. }
  109. /**
  110. * Returns whether the class with the specified name is transient. Only non-transient
  111. * classes, that is entities and mapped superclasses, should have their metadata loaded.
  112. *
  113. * @param string $className
  114. * @psalm-param class-string $className
  115. *
  116. * @return bool
  117. */
  118. abstract public function isTransient($className);
  119. /**
  120. * Gets the names of all mapped classes known to this driver.
  121. *
  122. * @return string[] The names of all mapped classes known to this driver.
  123. * @psalm-return list<class-string>
  124. */
  125. public function getAllClassNames()
  126. {
  127. if ($this->classNames !== null) {
  128. return $this->classNames;
  129. }
  130. if (! $this->paths) {
  131. throw MappingException::pathRequiredForDriver(static::class);
  132. }
  133. $classes = [];
  134. $includedFiles = [];
  135. foreach ($this->paths as $path) {
  136. if (! is_dir($path)) {
  137. throw MappingException::fileMappingDriversRequireConfiguredDirectoryPath($path);
  138. }
  139. $iterator = new RegexIterator(
  140. new RecursiveIteratorIterator(
  141. new RecursiveDirectoryIterator($path, FilesystemIterator::SKIP_DOTS),
  142. RecursiveIteratorIterator::LEAVES_ONLY
  143. ),
  144. '/^.+' . preg_quote($this->fileExtension) . '$/i',
  145. RecursiveRegexIterator::GET_MATCH
  146. );
  147. foreach ($iterator as $file) {
  148. $sourceFile = $file[0];
  149. if (preg_match('(^phar:)i', $sourceFile) === 0) {
  150. $sourceFile = realpath($sourceFile);
  151. }
  152. foreach ($this->excludePaths as $excludePath) {
  153. $realExcludePath = realpath($excludePath);
  154. assert($realExcludePath !== false);
  155. $exclude = str_replace('\\', '/', $realExcludePath);
  156. $current = str_replace('\\', '/', $sourceFile);
  157. if (strpos($current, $exclude) !== false) {
  158. continue 2;
  159. }
  160. }
  161. require_once $sourceFile;
  162. $includedFiles[] = $sourceFile;
  163. }
  164. }
  165. $declared = get_declared_classes();
  166. foreach ($declared as $className) {
  167. $rc = new ReflectionClass($className);
  168. $sourceFile = $rc->getFileName();
  169. if (! in_array($sourceFile, $includedFiles) || $this->isTransient($className)) {
  170. continue;
  171. }
  172. $classes[] = $className;
  173. }
  174. $this->classNames = $classes;
  175. return $classes;
  176. }
  177. }