Finder.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. <?php
  2. declare(strict_types=1);
  3. namespace Doctrine\Migrations\Finder;
  4. use Doctrine\Migrations\Finder\Exception\InvalidDirectory;
  5. use Doctrine\Migrations\Finder\Exception\NameIsReserved;
  6. use ReflectionClass;
  7. use function assert;
  8. use function get_declared_classes;
  9. use function in_array;
  10. use function is_dir;
  11. use function ksort;
  12. use function realpath;
  13. use function strlen;
  14. use function strncmp;
  15. use const SORT_STRING;
  16. /**
  17. * The Finder class is responsible for for finding migrations on disk at a given path.
  18. */
  19. abstract class Finder implements MigrationFinder
  20. {
  21. protected static function requireOnce(string $path): void
  22. {
  23. require_once $path;
  24. }
  25. /**
  26. * @throws InvalidDirectory
  27. */
  28. protected function getRealPath(string $directory): string
  29. {
  30. $dir = realpath($directory);
  31. if ($dir === false || ! is_dir($dir)) {
  32. throw InvalidDirectory::new($directory);
  33. }
  34. return $dir;
  35. }
  36. /**
  37. * @param string[] $files
  38. *
  39. * @return string[]
  40. *
  41. * @throws NameIsReserved
  42. */
  43. protected function loadMigrations(array $files, ?string $namespace): array
  44. {
  45. $includedFiles = [];
  46. foreach ($files as $file) {
  47. static::requireOnce($file);
  48. $realFile = realpath($file);
  49. assert($realFile !== false);
  50. $includedFiles[] = $realFile;
  51. }
  52. $classes = $this->loadMigrationClasses($includedFiles, $namespace);
  53. $versions = [];
  54. foreach ($classes as $class) {
  55. $versions[] = $class->getName();
  56. }
  57. ksort($versions, SORT_STRING);
  58. return $versions;
  59. }
  60. /**
  61. * Look up all declared classes and find those classes contained
  62. * in the given `$files` array.
  63. *
  64. * @param string[] $files The set of files that were `required`
  65. * @param string|null $namespace If not null only classes in this namespace will be returned
  66. *
  67. * @return ReflectionClass<object>[] the classes in `$files`
  68. */
  69. protected function loadMigrationClasses(array $files, ?string $namespace = null): array
  70. {
  71. $classes = [];
  72. foreach (get_declared_classes() as $class) {
  73. $reflectionClass = new ReflectionClass($class);
  74. if (! in_array($reflectionClass->getFileName(), $files, true)) {
  75. continue;
  76. }
  77. if ($namespace !== null && ! $this->isReflectionClassInNamespace($reflectionClass, $namespace)) {
  78. continue;
  79. }
  80. $classes[] = $reflectionClass;
  81. }
  82. return $classes;
  83. }
  84. /**
  85. * @param ReflectionClass<object> $reflectionClass
  86. */
  87. private function isReflectionClassInNamespace(ReflectionClass $reflectionClass, string $namespace): bool
  88. {
  89. return strncmp($reflectionClass->getName(), $namespace . '\\', strlen($namespace) + 1) === 0;
  90. }
  91. }