From 17ead38c8cd3e2bb5be52cc700c748aff084a6c3 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Thu, 3 Oct 2024 23:51:28 -0400 Subject: [PATCH 1/9] Import most of Phinx\Util\Util Most but not all. I've only included the methods we're currently relying on in migrations. This is another step towards decoupling from phinx for the new backend. --- src/Command/BakeSimpleMigrationCommand.php | 2 +- src/Command/Phinx/Create.php | 2 +- src/Migration/Manager.php | 2 +- src/Table.php | 2 + src/Util/Util.php | 319 +++++++++++++++++++++ 5 files changed, 324 insertions(+), 3 deletions(-) create mode 100644 src/Util/Util.php diff --git a/src/Command/BakeSimpleMigrationCommand.php b/src/Command/BakeSimpleMigrationCommand.php index 7c3f06a8..879ee237 100644 --- a/src/Command/BakeSimpleMigrationCommand.php +++ b/src/Command/BakeSimpleMigrationCommand.php @@ -21,7 +21,7 @@ use Cake\Console\ConsoleIo; use Cake\Console\ConsoleOptionParser; use Cake\Utility\Inflector; -use Phinx\Util\Util; +use Migrations\Util\Util; /** * Task class for generating migration snapshot files. diff --git a/src/Command/Phinx/Create.php b/src/Command/Phinx/Create.php index 51d0d441..c619a25f 100644 --- a/src/Command/Phinx/Create.php +++ b/src/Command/Phinx/Create.php @@ -15,8 +15,8 @@ use Cake\Utility\Inflector; use Migrations\ConfigurationTrait; +use Migrations\Util\Util; use Phinx\Console\Command\Create as CreateCommand; -use Phinx\Util\Util; use Symfony\Component\Console\Input\InputArgument; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Input\InputOption; diff --git a/src/Migration/Manager.php b/src/Migration/Manager.php index 59872621..dbdb159c 100644 --- a/src/Migration/Manager.php +++ b/src/Migration/Manager.php @@ -18,9 +18,9 @@ use Migrations\SeedInterface; use Migrations\Shim\MigrationAdapter; use Migrations\Shim\SeedAdapter; +use Migrations\Util\Util; use Phinx\Migration\MigrationInterface as PhinxMigrationInterface; use Phinx\Seed\SeedInterface as PhinxSeedInterface; -use Phinx\Util\Util; use Psr\Container\ContainerInterface; use RuntimeException; diff --git a/src/Table.php b/src/Table.php index bfb504b9..5cc3feca 100644 --- a/src/Table.php +++ b/src/Table.php @@ -21,6 +21,8 @@ use Phinx\Util\Literal; /** + * TODO figure out how to update this for built-in backend. + * * @method \Migrations\CakeAdapter getAdapter() */ class Table extends BaseTable diff --git a/src/Util/Util.php b/src/Util/Util.php new file mode 100644 index 00000000..de00455e --- /dev/null +++ b/src/Util/Util.php @@ -0,0 +1,319 @@ +format(static::DATE_FORMAT); + } + + /** + * Gets an array of all the existing migration class names. + * + * @param string $path Path + * @return string[] + */ + public static function getExistingMigrationClassNames(string $path): array + { + $classNames = []; + + if (!is_dir($path)) { + return $classNames; + } + + // filter the files to only get the ones that match our naming scheme + $phpFiles = static::getFiles($path); + + foreach ($phpFiles as $filePath) { + $fileName = basename($filePath); + if (preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName)) { + $classNames[] = static::mapFileNameToClassName($fileName); + } + } + + return $classNames; + } + + /** + * Get the version from the beginning of a file name. + * + * @param string $fileName File Name + * @return int + */ + public static function getVersionFromFileName(string $fileName): int + { + $matches = []; + preg_match('/^[0-9]+/', basename($fileName), $matches); + $value = (int)($matches[0] ?? null); + if (!$value) { + throw new RuntimeException(sprintf('Cannot get a valid version from filename `%s`', $fileName)); + } + + return $value; + } + + /** + * Turn migration names like 'CreateUserTable' into file names like + * '12345678901234_create_user_table.php' or 'LimitResourceNamesTo30Chars' into + * '12345678901234_limit_resource_names_to_30_chars.php'. + * + * @param string $className Class Name + * @return string + */ + public static function mapClassNameToFileName(string $className): string + { + // TODO replace with Inflector + $snake = function ($matches) { + return '_' . strtolower($matches[0]); + }; + $fileName = preg_replace_callback('/\d+|[A-Z]/', $snake, $className); + $fileName = static::getCurrentTimestamp() . "$fileName.php"; + + return $fileName; + } + + /** + * Turn file names like '12345678901234_create_user_table.php' into class + * names like 'CreateUserTable'. + * + * @param string $fileName File Name + * @return string + */ + public static function mapFileNameToClassName(string $fileName): string + { + // TODO replace with Inflector + $matches = []; + if (preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName, $matches)) { + $fileName = $matches[1]; + } elseif (preg_match(static::MIGRATION_FILE_NAME_NO_NAME_PATTERN, $fileName)) { + return 'V' . substr($fileName, 0, strlen($fileName) - 4); + } + + $className = str_replace('_', '', ucwords($fileName, '_')); + + return $className; + } + + /** + * Check if a migration class name is unique regardless of the + * timestamp. + * + * This method takes a class name and a path to a migrations directory. + * + * Migration class names must be in PascalCase format but consecutive + * capitals are allowed. + * e.g: AddIndexToPostsTable or CustomHTMLTitle. + * + * @param string $className Class Name + * @param string $path Path + * @return bool + */ + public static function isUniqueMigrationClassName(string $className, string $path): bool + { + $existingClassNames = static::getExistingMigrationClassNames($path); + + return !in_array($className, $existingClassNames, true); + } + + /** + * Check if a migration/seed class name is valid. + * + * Migration & Seed class names must be in CamelCase format. + * e.g: CreateUserTable, AddIndexToPostsTable or UserSeeder. + * + * Single words are not allowed on their own. + * + * @param string $className Class Name + * @return bool + */ + public static function isValidPhinxClassName(string $className): bool + { + return (bool)preg_match(static::CLASS_NAME_PATTERN, $className); + } + + /** + * Check if a migration file name is valid. + * + * @param string $fileName File Name + * @return bool + */ + public static function isValidMigrationFileName(string $fileName): bool + { + return (bool)preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName) + || (bool)preg_match(static::MIGRATION_FILE_NAME_NO_NAME_PATTERN, $fileName); + } + + /** + * Check if a seed file name is valid. + * + * @param string $fileName File Name + * @return bool + */ + public static function isValidSeedFileName(string $fileName): bool + { + return (bool)preg_match(static::SEED_FILE_NAME_PATTERN, $fileName); + } + + /** + * Expands a set of paths with curly braces (if supported by the OS). + * + * @param string[] $paths Paths + * @return string[] + */ + public static function globAll(array $paths): array + { + $result = []; + + foreach ($paths as $path) { + $result = array_merge($result, static::glob($path)); + } + + return $result; + } + + /** + * Expands a path with curly braces (if supported by the OS). + * + * @param string $path Path + * @return string[] + */ + public static function glob(string $path): array + { + return glob($path, defined('GLOB_BRACE') ? GLOB_BRACE : 0); + } + + /** + * Takes the path to a php file and attempts to include it if readable + * + * @param string $filename Filename + * @param \Symfony\Component\Console\Input\InputInterface|null $input Input + * @param \Symfony\Component\Console\Output\OutputInterface|null $output Output + * @param \Phinx\Console\Command\AbstractCommand|mixed|null $context Context + * @throws \Exception + * @return string + */ + public static function loadPhpFile(string $filename, ?InputInterface $input = null, ?OutputInterface $output = null, mixed $context = null): string + { + $filePath = realpath($filename); + if (!file_exists($filePath)) { + throw new Exception(sprintf("File does not exist: %s \n", $filename)); + } + + /** + * I lifed this from phpunits FileLoader class + * + * @see https://github.com/sebastianbergmann/phpunit/pull/2751 + */ + $isReadable = @fopen($filePath, 'r') !== false; + + if (!$isReadable) { + throw new Exception(sprintf("Cannot open file %s \n", $filename)); + } + + // TODO remove $input, $output, and $context from scope + // prevent this to be propagated to the included file + unset($isReadable); + + include_once $filePath; + + return $filePath; + } + + /** + * Given an array of paths, return all unique PHP files that are in them + * + * @param string|string[] $paths Path or array of paths to get .php files. + * @return string[] + */ + public static function getFiles(string|array $paths): array + { + $files = static::globAll(array_map(function ($path) { + return $path . DIRECTORY_SEPARATOR . '*.php'; + }, (array)$paths)); + // glob() can return the same file multiple times + // This will cause the migration to fail with a + // false assumption of duplicate migrations + // https://php.net/manual/en/function.glob.php#110340 + $files = array_unique($files); + + return $files; + } + + /** + * Attempt to remove the current working directory from a path for output. + * + * @param string $path Path to remove cwd prefix from + * @return string + */ + public static function relativePath(string $path): string + { + $realpath = realpath($path); + if ($realpath !== false) { + $path = $realpath; + } + + $cwd = getcwd(); + if ($cwd !== false) { + $cwd .= DIRECTORY_SEPARATOR; + $cwdLen = strlen($cwd); + + if (substr($path, 0, $cwdLen) === $cwd) { + $path = substr($path, $cwdLen); + } + } + + return $path; + } +} From b720bb511e3efa5713262a5583183a04821400e8 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Thu, 3 Oct 2024 23:56:54 -0400 Subject: [PATCH 2/9] Import tests as well --- tests/TestCase/Util/UtilTest.php | 174 ++++++++++++++++++ .../20120111235330_test_migration.php | 22 +++ .../20120116183504_test_migration_2.php | 22 +++ .../TestCase/Util/_files/migrations/empty.txt | 0 .../_files/migrations/not_a_migration.php | 3 + .../_files/migrations/subdirectory/empty.txt | 0 .../_files/migrations/subdirectory/foobar.php | 3 + 7 files changed, 224 insertions(+) create mode 100644 tests/TestCase/Util/UtilTest.php create mode 100644 tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php create mode 100644 tests/TestCase/Util/_files/migrations/20120116183504_test_migration_2.php create mode 100644 tests/TestCase/Util/_files/migrations/empty.txt create mode 100644 tests/TestCase/Util/_files/migrations/not_a_migration.php create mode 100644 tests/TestCase/Util/_files/migrations/subdirectory/empty.txt create mode 100644 tests/TestCase/Util/_files/migrations/subdirectory/foobar.php diff --git a/tests/TestCase/Util/UtilTest.php b/tests/TestCase/Util/UtilTest.php new file mode 100644 index 00000000..a9c21205 --- /dev/null +++ b/tests/TestCase/Util/UtilTest.php @@ -0,0 +1,174 @@ +getCorrectedPath(__DIR__ . '/_files/migrations')); + $this->assertCount(count($expectedResults), $existingClassNames); + foreach ($expectedResults as $expectedResult) { + $this->assertContains($expectedResult, $existingClassNames); + } + } + + public function testGetExistingMigrationClassNamesWithFile() + { + $file = $this->getCorrectedPath(__DIR__ . '/_files/migrations/20120111235330_test_migration.php'); + $existingClassNames = Util::getExistingMigrationClassNames($file); + $this->assertCount(0, $existingClassNames); + } + + public function testGetCurrentTimestamp() + { + $dt = new DateTime('now', new DateTimeZone('UTC')); + $expected = $dt->format(Util::DATE_FORMAT); + + $current = Util::getCurrentTimestamp(); + + // Rather than using a strict equals, we use greater/lessthan checks to + // prevent false positives when the test hits the edge of a second. + $this->assertGreaterThanOrEqual($expected, $current); + // We limit the assertion time to 2 seconds, which should never fail. + $this->assertLessThanOrEqual($expected + 2, $current); + } + + public function testGetVersionFromFileName(): void + { + $this->assertSame(20221130101652, Util::getVersionFromFileName('20221130101652_test.php')); + } + + public function testGetVersionFromFileNameErrorNoVersion(): void + { + $this->expectException(RuntimeException::class); + Util::getVersionFromFileName('foo.php'); + } + + public function testGetVersionFromFileNameErrorZeroVersion(): VoidCommand + { + $this->expectException(RuntimeException::class); + Util::getVersionFromFileName('0_foo.php'); + } + + public function providerMapClassNameToFileName(): array + { + return [ + ['CamelCase87afterSomeBooze', '/^\d{14}_camel_case_87after_some_booze\.php$/'], + ['CreateUserTable', '/^\d{14}_create_user_table\.php$/'], + ['LimitResourceNamesTo30Chars', '/^\d{14}_limit_resource_names_to_30_chars\.php$/'], + ]; + } + + /** + * @dataProvider providerMapClassNameToFileName + */ + public function testMapClassNameToFileName(string $name, string $pattern): void + { + $this->assertMatchesRegularExpression($pattern, Util::mapClassNameToFileName($name)); + } + + public function providerMapFileName(): array + { + return [ + ['20150902094024_create_user_table.php', 'CreateUserTable'], + ['20150902102548_my_first_migration2.php', 'MyFirstMigration2'], + ['20200412012035_camel_case_87after_some_booze.php', 'CamelCase87afterSomeBooze'], + ['20200412012036_limit_resource_names_to_30_chars.php', 'LimitResourceNamesTo30Chars'], + ['20200412012037_back_compat_names_to30_chars.php', 'BackCompatNamesTo30Chars'], + ['20200412012037.php', 'V20200412012037'], + ]; + } + + /** + * @dataProvider providerMapFileName + */ + public function testMapFileNameToClassName(string $fileName, string $className) + { + $this->assertEquals($className, Util::mapFileNameToClassName($fileName)); + } + + public function providerValidClassName(): array + { + return [ + ['camelCase', false], + ['CreateUserTable', true], + ['UserSeeder', true], + ['Test', true], + ['test', false], + ['Q', true], + ['XMLTriggers', true], + ['Form_Cards', false], + ['snake_high_scores', false], + ['Code2319Incidents', true], + ['V20200509232007', true], + ]; + } + + /** + * @dataProvider providerValidClassName + */ + public function testIsValidPhinxClassName(string $className, bool $valid): void + { + $this->assertSame($valid, Util::isValidPhinxClassName($className)); + } + + public function testGlobPath() + { + $files = Util::glob(__DIR__ . '/_files/migrations/empty.txt'); + $this->assertCount(1, $files); + $this->assertEquals('empty.txt', basename($files[0])); + + $files = Util::glob(__DIR__ . '/_files/migrations/*.php'); + $this->assertCount(3, $files); + $this->assertEquals('20120111235330_test_migration.php', basename($files[0])); + $this->assertEquals('20120116183504_test_migration_2.php', basename($files[1])); + $this->assertEquals('not_a_migration.php', basename($files[2])); + } + + public function testGlobAll() + { + $files = Util::globAll([ + __DIR__ . '/_files/migrations/*.php', + __DIR__ . '/_files/migrations/subdirectory/*.txt', + ]); + + $this->assertCount(4, $files); + $this->assertEquals('20120111235330_test_migration.php', basename($files[0])); + $this->assertEquals('20120116183504_test_migration_2.php', basename($files[1])); + $this->assertEquals('not_a_migration.php', basename($files[2])); + $this->assertEquals('empty.txt', basename($files[3])); + } + + public function testGetFiles() + { + $files = Util::getFiles([ + __DIR__ . '/_files/migrations', + __DIR__ . '/_files/migrations/subdirectory', + __DIR__ . '/_files/migrations/subdirectory', + ]); + + $this->assertCount(4, $files); + $this->assertEquals('20120111235330_test_migration.php', basename($files[0])); + $this->assertEquals('20120116183504_test_migration_2.php', basename($files[1])); + $this->assertEquals('not_a_migration.php', basename($files[2])); + $this->assertEquals('foobar.php', basename($files[3])); + } +} diff --git a/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php b/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php new file mode 100644 index 00000000..a68cc4d4 --- /dev/null +++ b/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php @@ -0,0 +1,22 @@ + Date: Fri, 4 Oct 2024 00:11:10 -0400 Subject: [PATCH 3/9] Apply formatting and type checking rules --- psalm-baseline.xml | 95 +++++++++++-------- src/Util/Util.php | 19 +++- tests/TestCase/Util/UtilTest.php | 2 +- .../20120111235330_test_migration.php | 1 + .../20120116183504_test_migration_2.php | 5 +- .../_files/migrations/not_a_migration.php | 1 + .../_files/migrations/subdirectory/foobar.php | 1 + 7 files changed, 77 insertions(+), 47 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index 17223cad..e5bf28b4 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,64 +1,73 @@ - + + + + + + - MigrationsDispatcher - MigrationsDispatcher::getCommands() - MigrationsDispatcher::getCommands() - \Migrations\MigrationsDispatcher - new MigrationsDispatcher(PHINX_VERSION) + + + + + + + + + - ConfigurationTrait + - $phinxName + - ConfigurationTrait + - ConfigurationTrait + - ConfigurationTrait + - ConfigurationTrait + - ConfigurationTrait + - setInput + - ConfigurationTrait + - ArrayAccess + io]]> - null + @@ -68,41 +77,41 @@ - getQueryBuilder + - $opened - is_array($newColumns) + + - getQueryBuilder + - \Phinx\Db\Adapter\AdapterInterface + - \Phinx\Db\Adapter\AdapterInterface + - \Phinx\Db\Adapter\AdapterInterface + - is_array($newColumns) + - $columns - $newColumns + + - verbose + @@ -118,47 +127,55 @@ }, $phpFiles )]]> - array_merge($versions, array_keys($migrations)) + + + getConfig()->getMigrationPath())]]> + getConfig()->getSeedPath())]]> + + + + + container)]]> - $executedVersion + - CONFIG + - ConfigurationTrait + - ConfigurationTrait + - $messages - $messages + + io->level()]]> - self::VERBOSITY_* + - $dropTables - $phinxTables - $tables + + + diff --git a/src/Util/Util.php b/src/Util/Util.php index de00455e..597a6c2b 100644 --- a/src/Util/Util.php +++ b/src/Util/Util.php @@ -18,7 +18,7 @@ /** * Temporary compatibility shim that can be refactored away. * - * @internal + * @deprecated This compatibility shim will be removed in 5.0 */ class Util { @@ -29,21 +29,25 @@ class Util /** * @var string + * @psalm-var non-empty-string */ protected const MIGRATION_FILE_NAME_PATTERN = '/^\d+_([a-z][a-z\d]*(?:_[a-z\d]+)*)\.php$/i'; /** * @var string + * @psalm-var non-empty-string */ protected const MIGRATION_FILE_NAME_NO_NAME_PATTERN = '/^[0-9]{14}\.php$/'; /** * @var string + * @psalm-var non-empty-string */ protected const SEED_FILE_NAME_PATTERN = '/^([a-z][a-z\d]*)\.php$/i'; /** * @var string + * @psalm-var non-empty-string */ protected const CLASS_NAME_PATTERN = '/^(?:[A-Z][a-z\d]*)+$/'; @@ -78,7 +82,7 @@ public static function getExistingMigrationClassNames(string $path): array foreach ($phpFiles as $filePath) { $fileName = basename($filePath); - if (preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName)) { + if ($fileName && preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName)) { $classNames[] = static::mapFileNameToClassName($fileName); } } @@ -210,7 +214,7 @@ public static function isValidSeedFileName(string $fileName): bool * Expands a set of paths with curly braces (if supported by the OS). * * @param string[] $paths Paths - * @return string[] + * @return array */ public static function globAll(array $paths): array { @@ -231,7 +235,12 @@ public static function globAll(array $paths): array */ public static function glob(string $path): array { - return glob($path, defined('GLOB_BRACE') ? GLOB_BRACE : 0); + $result = glob($path, defined('GLOB_BRACE') ? GLOB_BRACE : 0); + if ($result) { + return $result; + } + + return []; } /** @@ -247,7 +256,7 @@ public static function glob(string $path): array public static function loadPhpFile(string $filename, ?InputInterface $input = null, ?OutputInterface $output = null, mixed $context = null): string { $filePath = realpath($filename); - if (!file_exists($filePath)) { + if (!$filePath || !file_exists($filePath)) { throw new Exception(sprintf("File does not exist: %s \n", $filename)); } diff --git a/tests/TestCase/Util/UtilTest.php b/tests/TestCase/Util/UtilTest.php index a9c21205..932d6ac4 100644 --- a/tests/TestCase/Util/UtilTest.php +++ b/tests/TestCase/Util/UtilTest.php @@ -3,11 +3,11 @@ namespace Test\Phinx\Util; +use Cake\TestSuite\TestCase; use DateTime; use DateTimeZone; use Migrations\Util\Util; use RuntimeException; -use Cake\TestSuite\TestCase; class UtilTest extends TestCase { diff --git a/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php b/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php index a68cc4d4..27b10239 100644 --- a/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php +++ b/tests/TestCase/Util/_files/migrations/20120111235330_test_migration.php @@ -1,4 +1,5 @@ Date: Fri, 4 Oct 2024 23:02:56 -0400 Subject: [PATCH 4/9] Fix provider signatures --- tests/TestCase/Util/UtilTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/TestCase/Util/UtilTest.php b/tests/TestCase/Util/UtilTest.php index 932d6ac4..a1aa2cd7 100644 --- a/tests/TestCase/Util/UtilTest.php +++ b/tests/TestCase/Util/UtilTest.php @@ -68,7 +68,7 @@ public function testGetVersionFromFileNameErrorZeroVersion(): VoidCommand Util::getVersionFromFileName('0_foo.php'); } - public function providerMapClassNameToFileName(): array + public static function providerMapClassNameToFileName(): array { return [ ['CamelCase87afterSomeBooze', '/^\d{14}_camel_case_87after_some_booze\.php$/'], @@ -85,7 +85,7 @@ public function testMapClassNameToFileName(string $name, string $pattern): void $this->assertMatchesRegularExpression($pattern, Util::mapClassNameToFileName($name)); } - public function providerMapFileName(): array + public static function providerMapFileName(): array { return [ ['20150902094024_create_user_table.php', 'CreateUserTable'], @@ -105,7 +105,7 @@ public function testMapFileNameToClassName(string $fileName, string $className) $this->assertEquals($className, Util::mapFileNameToClassName($fileName)); } - public function providerValidClassName(): array + public static function providerValidClassName(): array { return [ ['camelCase', false], From 33c7c93cb1fdcb56b13ef64d4905e6f83fee1225 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 4 Oct 2024 23:15:25 -0400 Subject: [PATCH 5/9] Remove isValidPhinxFileName it isn't used internally and I don't see a reason to maintain it. --- src/Util/Util.php | 25 ++++--------------------- tests/TestCase/Util/UtilTest.php | 25 ------------------------- 2 files changed, 4 insertions(+), 46 deletions(-) diff --git a/src/Util/Util.php b/src/Util/Util.php index 597a6c2b..27814234 100644 --- a/src/Util/Util.php +++ b/src/Util/Util.php @@ -8,6 +8,7 @@ namespace Migrations\Util; +use Cake\Utility\Inflector; use DateTime; use DateTimeZone; use Exception; @@ -118,7 +119,8 @@ public static function getVersionFromFileName(string $fileName): int */ public static function mapClassNameToFileName(string $className): string { - // TODO replace with Inflector + // TODO it would be nice to replace this with Inflector::underscore + // but it will break compatibility for little end user gain. $snake = function ($matches) { return '_' . strtolower($matches[0]); }; @@ -137,7 +139,6 @@ public static function mapClassNameToFileName(string $className): string */ public static function mapFileNameToClassName(string $fileName): string { - // TODO replace with Inflector $matches = []; if (preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName, $matches)) { $fileName = $matches[1]; @@ -145,9 +146,7 @@ public static function mapFileNameToClassName(string $fileName): string return 'V' . substr($fileName, 0, strlen($fileName) - 4); } - $className = str_replace('_', '', ucwords($fileName, '_')); - - return $className; + return Inflector::camelize($fileName); } /** @@ -171,22 +170,6 @@ public static function isUniqueMigrationClassName(string $className, string $pat return !in_array($className, $existingClassNames, true); } - /** - * Check if a migration/seed class name is valid. - * - * Migration & Seed class names must be in CamelCase format. - * e.g: CreateUserTable, AddIndexToPostsTable or UserSeeder. - * - * Single words are not allowed on their own. - * - * @param string $className Class Name - * @return bool - */ - public static function isValidPhinxClassName(string $className): bool - { - return (bool)preg_match(static::CLASS_NAME_PATTERN, $className); - } - /** * Check if a migration file name is valid. * diff --git a/tests/TestCase/Util/UtilTest.php b/tests/TestCase/Util/UtilTest.php index a1aa2cd7..65283066 100644 --- a/tests/TestCase/Util/UtilTest.php +++ b/tests/TestCase/Util/UtilTest.php @@ -105,31 +105,6 @@ public function testMapFileNameToClassName(string $fileName, string $className) $this->assertEquals($className, Util::mapFileNameToClassName($fileName)); } - public static function providerValidClassName(): array - { - return [ - ['camelCase', false], - ['CreateUserTable', true], - ['UserSeeder', true], - ['Test', true], - ['test', false], - ['Q', true], - ['XMLTriggers', true], - ['Form_Cards', false], - ['snake_high_scores', false], - ['Code2319Incidents', true], - ['V20200509232007', true], - ]; - } - - /** - * @dataProvider providerValidClassName - */ - public function testIsValidPhinxClassName(string $className, bool $valid): void - { - $this->assertSame($valid, Util::isValidPhinxClassName($className)); - } - public function testGlobPath() { $files = Util::glob(__DIR__ . '/_files/migrations/empty.txt'); From 438722e4987bb2d415b51593c1ceed420db5589a Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 4 Oct 2024 23:17:06 -0400 Subject: [PATCH 6/9] Remove Util::relativePath It is unused internally. --- src/Util/Util.php | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/Util/Util.php b/src/Util/Util.php index 27814234..4d3b18d3 100644 --- a/src/Util/Util.php +++ b/src/Util/Util.php @@ -282,30 +282,4 @@ public static function getFiles(string|array $paths): array return $files; } - - /** - * Attempt to remove the current working directory from a path for output. - * - * @param string $path Path to remove cwd prefix from - * @return string - */ - public static function relativePath(string $path): string - { - $realpath = realpath($path); - if ($realpath !== false) { - $path = $realpath; - } - - $cwd = getcwd(); - if ($cwd !== false) { - $cwd .= DIRECTORY_SEPARATOR; - $cwdLen = strlen($cwd); - - if (substr($path, 0, $cwdLen) === $cwd) { - $path = substr($path, $cwdLen); - } - } - - return $path; - } } From 342ce3384a547b990594f07afe0378a7c79247f9 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Fri, 4 Oct 2024 23:19:22 -0400 Subject: [PATCH 7/9] Fix namespaces and mark Util as internal I won't be able to fully refactor it away. There are conventions for migration files that Inflector does not replicate. --- src/Util/Util.php | 2 +- tests/TestCase/Util/UtilTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Util/Util.php b/src/Util/Util.php index 4d3b18d3..f24a8f86 100644 --- a/src/Util/Util.php +++ b/src/Util/Util.php @@ -19,7 +19,7 @@ /** * Temporary compatibility shim that can be refactored away. * - * @deprecated This compatibility shim will be removed in 5.0 + * @internal */ class Util { diff --git a/tests/TestCase/Util/UtilTest.php b/tests/TestCase/Util/UtilTest.php index 65283066..a7620401 100644 --- a/tests/TestCase/Util/UtilTest.php +++ b/tests/TestCase/Util/UtilTest.php @@ -1,7 +1,7 @@ Date: Fri, 4 Oct 2024 23:22:52 -0400 Subject: [PATCH 8/9] Fix phpcs failure The test stubs for Util don't need to adhere to coding standards as they contain migration files from phinx. --- phpcs.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/phpcs.xml b/phpcs.xml index d180d0a7..7a7a8a87 100644 --- a/phpcs.xml +++ b/phpcs.xml @@ -6,6 +6,7 @@ tests/ */tests/comparisons/* + */tests/TestCase/Util/_files/* */test_app/config/* */TestBlog/config/* */BarPlugin/config/* From a2e46b81c0e3cb470dd791f80d5835300f8a5dcb Mon Sep 17 00:00:00 2001 From: Mark Story Date: Sun, 6 Oct 2024 22:37:35 -0400 Subject: [PATCH 9/9] Clean up baseline file --- psalm-baseline.xml | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/psalm-baseline.xml b/psalm-baseline.xml index e5bf28b4..2ef77c40 100644 --- a/psalm-baseline.xml +++ b/psalm-baseline.xml @@ -1,10 +1,5 @@ - - - - - @@ -15,10 +10,6 @@ - - - - @@ -129,14 +120,6 @@ )]]> - - getConfig()->getMigrationPath())]]> - getConfig()->getSeedPath())]]> - - - - - container)]]>