From 4a977750bcfb2273b045bc57d1d92dad30f519da Mon Sep 17 00:00:00 2001 From: kharhamel Date: Mon, 2 Sep 2019 17:29:52 +0200 Subject: [PATCH 01/10] added a schema lock file to tdbm --- .gitignore | 2 + composer.json | 3 +- src/TDBMSchemaAnalyzer.php | 55 +++++++++++--------------- src/Utils/ImmutableCaster.php | 38 ++++++++++++++++++ src/Utils/RootProjectLocator.php | 13 ++++++ src/Utils/TDBMDaoGenerator.php | 14 +++---- tests/Commands/GenerateCommandTest.php | 8 ++++ tests/TDBMDaoGeneratorTest.php | 9 +++++ tests/TDBMSchemaAnalyzerTest.php | 21 ++++++++++ 9 files changed, 122 insertions(+), 41 deletions(-) create mode 100644 src/Utils/ImmutableCaster.php create mode 100644 src/Utils/RootProjectLocator.php diff --git a/.gitignore b/.gitignore index 15946e62..d8d055a6 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,5 @@ vendor/* .phpunit.result.cache /phpbench.sh /xdebug/ +.php_cs.cache +tdbm.lock.yml \ No newline at end of file diff --git a/composer.json b/composer.json index 7838e98a..e005de4f 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,8 @@ "ext-PDO": "*", "ext-json": "*", "ext-hash": "*", - "ext-filter": "*" + "ext-filter": "*", + "brain-diminished/schema-version-control": "^1.0" }, "require-dev" : { "phpunit/phpunit": "^7.4.4 || ^8.0.0", diff --git a/src/TDBMSchemaAnalyzer.php b/src/TDBMSchemaAnalyzer.php index d9948c70..ab3d3fb9 100644 --- a/src/TDBMSchemaAnalyzer.php +++ b/src/TDBMSchemaAnalyzer.php @@ -3,6 +3,7 @@ namespace TheCodingMachine\TDBM; +use BrainDiminished\SchemaVersionControl\SchemaVersionControlService; use Doctrine\Common\Cache\Cache; use Doctrine\DBAL\Connection; use Doctrine\DBAL\Schema\Column; @@ -12,12 +13,16 @@ use Doctrine\DBAL\Types\DateType; use Doctrine\DBAL\Types\Type; use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer; +use TheCodingMachine\TDBM\Utils\ImmutableCaster; +use TheCodingMachine\TDBM\Utils\RootProjectLocator; /** * This class is used to analyze the schema and return valuable information / hints. */ class TDBMSchemaAnalyzer { + const schemaFileName = 'tdbm.lock.yml'; + private $connection; /** @@ -40,6 +45,11 @@ class TDBMSchemaAnalyzer */ private $schemaAnalyzer; + /** + * @var SchemaVersionControlService + */ + private $schemaVersionControlService; + /** * @param Connection $connection The DBAL DB connection to use * @param Cache $cache A cache service to be used @@ -51,6 +61,7 @@ public function __construct(Connection $connection, Cache $cache, SchemaAnalyzer $this->connection = $connection; $this->cache = $cache; $this->schemaAnalyzer = $schemaAnalyzer; + $this->schemaVersionControlService = new SchemaVersionControlService($this->connection, self::getLockFilePath()); } /** @@ -67,20 +78,25 @@ public function getCachePrefix(): string return $this->cachePrefix; } + public static function getLockFilePath(): string + { + return RootProjectLocator::getRootLocationPath().self::schemaFileName; + } + /** * Returns the (cached) schema. - * - * @return Schema */ - public function getSchema(): Schema + public function getSchema(bool $ignoreCache = false): Schema { if ($this->schema === null) { $cacheKey = $this->getCachePrefix().'_immutable_schema'; - if ($this->cache->contains($cacheKey)) { + if (!$ignoreCache && $this->cache->contains($cacheKey)) { $this->schema = $this->cache->fetch($cacheKey); + } elseif (!file_exists(self::getLockFilePath())) { + throw new TDBMException('No tdbm lock file found. Please regenerate DAOs and Beans.'); } else { - $this->schema = $this->connection->getSchemaManager()->createSchema(); - $this->castSchemaToImmutable($this->schema); + $this->schema = $this->schemaVersionControlService->loadSchemaFile(); + ImmutableCaster::castSchemaToImmutable($this->schema); $this->cache->save($cacheKey, $this->schema); } } @@ -88,32 +104,9 @@ public function getSchema(): Schema return $this->schema; } - private function castSchemaToImmutable(Schema $schema): void + public function generateLockFile(): void { - foreach ($schema->getTables() as $table) { - foreach ($table->getColumns() as $column) { - $this->toImmutableType($column); - } - } - } - - /** - * Changes the type of a column to an immutable date type if the type is a date. - * This is needed because by default, when reading a Schema, Doctrine assumes a mutable datetime. - */ - private function toImmutableType(Column $column): void - { - $mapping = [ - Type::DATE => Type::DATE_IMMUTABLE, - Type::DATETIME => Type::DATETIME_IMMUTABLE, - Type::DATETIMETZ => Type::DATETIMETZ_IMMUTABLE, - Type::TIME => Type::TIME_IMMUTABLE - ]; - - $typeName = $column->getType()->getName(); - if (isset($mapping[$typeName])) { - $column->setType(Type::getType($mapping[$typeName])); - } + $this->schemaVersionControlService->dumpSchema(); } /** diff --git a/src/Utils/ImmutableCaster.php b/src/Utils/ImmutableCaster.php new file mode 100644 index 00000000..c8e52788 --- /dev/null +++ b/src/Utils/ImmutableCaster.php @@ -0,0 +1,38 @@ +getTables() as $table) { + foreach ($table->getColumns() as $column) { + self::toImmutableType($column); + } + } + } + + /** + * Changes the type of a column to an immutable date type if the type is a date. + * This is needed because by default, when reading a Schema, Doctrine assumes a mutable datetime. + */ + private static function toImmutableType(Column $column): void + { + $mapping = [ + Type::DATE => Type::DATE_IMMUTABLE, + Type::DATETIME => Type::DATETIME_IMMUTABLE, + Type::DATETIMETZ => Type::DATETIMETZ_IMMUTABLE, + Type::TIME => Type::TIME_IMMUTABLE + ]; + + $typeName = $column->getType()->getName(); + if (isset($mapping[$typeName])) { + $column->setType(Type::getType($mapping[$typeName])); + } + } +} diff --git a/src/Utils/RootProjectLocator.php b/src/Utils/RootProjectLocator.php new file mode 100644 index 00000000..61ecc534 --- /dev/null +++ b/src/Utils/RootProjectLocator.php @@ -0,0 +1,13 @@ +getFileName(), 3).'/'; + } +} diff --git a/src/Utils/TDBMDaoGenerator.php b/src/Utils/TDBMDaoGenerator.php index 6c6dc32b..195e853f 100644 --- a/src/Utils/TDBMDaoGenerator.php +++ b/src/Utils/TDBMDaoGenerator.php @@ -33,11 +33,6 @@ */ class TDBMDaoGenerator { - /** - * @var Schema - */ - private $schema; - /** * @var TDBMSchemaAnalyzer */ @@ -66,7 +61,6 @@ class TDBMDaoGenerator public function __construct(ConfigurationInterface $configuration, TDBMSchemaAnalyzer $tdbmSchemaAnalyzer) { $this->configuration = $configuration; - $this->schema = $tdbmSchemaAnalyzer->getSchema(); $this->tdbmSchemaAnalyzer = $tdbmSchemaAnalyzer; $this->namingStrategy = $configuration->getNamingStrategy(); $this->eventDispatcher = $configuration->getGeneratorEventDispatcher(); @@ -79,9 +73,11 @@ public function __construct(ConfigurationInterface $configuration, TDBMSchemaAna */ public function generateAllDaosAndBeans(): void { - // TODO: check that no class name ends with "Base". Otherwise, there will be name clash. + $this->tdbmSchemaAnalyzer->generateLockFile(); + $schema = $this->tdbmSchemaAnalyzer->getSchema(); - $tableList = $this->schema->getTables(); + // TODO: check that no class name ends with "Base". Otherwise, there will be name clash. + $tableList = $schema->getTables(); // Remove all beans and daos from junction tables $junctionTables = $this->configuration->getSchemaAnalyzer()->detectJunctionTables(true); @@ -97,7 +93,7 @@ public function generateAllDaosAndBeans(): void $beanDescriptors = []; - $beanRegistry = new BeanRegistry($this->configuration, $this->schema, $this->tdbmSchemaAnalyzer, $this->namingStrategy); + $beanRegistry = new BeanRegistry($this->configuration, $schema, $this->tdbmSchemaAnalyzer, $this->namingStrategy); foreach ($tableList as $table) { $beanDescriptors[] = $beanRegistry->addBeanForTable($table); } diff --git a/tests/Commands/GenerateCommandTest.php b/tests/Commands/GenerateCommandTest.php index fb1b4f6c..ff1a35f1 100644 --- a/tests/Commands/GenerateCommandTest.php +++ b/tests/Commands/GenerateCommandTest.php @@ -10,6 +10,7 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; +use TheCodingMachine\TDBM\TDBMSchemaAnalyzer; class GenerateCommandTest extends TDBMAbstractServiceTest { @@ -24,9 +25,16 @@ public function testCall(): void $input = new ArrayInput([ ], self::getInputDefinition()); + //let's delete the lock file + $schemaFilePath = TDBMSchemaAnalyzer::getLockFilePath(); + if (file_exists($schemaFilePath)) { + unlink($schemaFilePath); + } $result = $this->callCommand(new GenerateCommand($this->getConfiguration()), $input); $this->assertContains('Finished regenerating DAOs and beans', $result); + //Check that the lock file was generated + $this->assertFileExists($schemaFilePath); } /** diff --git a/tests/TDBMDaoGeneratorTest.php b/tests/TDBMDaoGeneratorTest.php index e1e4d4e8..f716772b 100644 --- a/tests/TDBMDaoGeneratorTest.php +++ b/tests/TDBMDaoGeneratorTest.php @@ -114,10 +114,19 @@ public function testDaoGeneration(): void touch($dummyFile); $this->assertFileExists($dummyFile); + //let's delete the lock file + $schemaFilePath = TDBMSchemaAnalyzer::getLockFilePath(); + if (file_exists($schemaFilePath)) { + unlink($schemaFilePath); + } + $this->tdbmDaoGenerator->generateAllDaosAndBeans(); $this->assertFileNotExists($dummyFile); + //Check that the lock file was generated + $this->assertFileExists($schemaFilePath); + // Let's require all files to check they are valid PHP! // Test the daoFactory require_once $this->rootPath . 'src/Test/Dao/Generated/DaoFactory.php'; diff --git a/tests/TDBMSchemaAnalyzerTest.php b/tests/TDBMSchemaAnalyzerTest.php index e33a3808..c5894b1f 100644 --- a/tests/TDBMSchemaAnalyzerTest.php +++ b/tests/TDBMSchemaAnalyzerTest.php @@ -23,6 +23,7 @@ use Doctrine\Common\Cache\ArrayCache; use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer; +use TheCodingMachine\TDBM\Utils\ImmutableCaster; class TDBMSchemaAnalyzerTest extends TDBMAbstractServiceTest { @@ -38,6 +39,26 @@ protected function setUp(): void $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), new ArrayCache(), $schemaAnalyzer); } + public function testSchemaLock(): void + { + $schemaFromConnec = self::getConnection()->getSchemaManager()->createSchema(); + $tableNames = []; + //lock file doesn't save the database name so we have to replace it manually. + foreach ($schemaFromConnec->getTableNames() as $tableName) { + $tableNames[] = str_replace('tdbm_testcase', 'public', $tableName); + } + ImmutableCaster::castSchemaToImmutable($schemaFromConnec); + + $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); + $cache = new ArrayCache(); + $tdbmSchemaAnalyzer1 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + + $schemaFromAnalyser = $tdbmSchemaAnalyzer1->getSchema(true); + $schemaFromAnalyserCached = $tdbmSchemaAnalyzer1->getSchema(); + $this->assertEquals($tableNames, $schemaFromAnalyser->getTableNames()); + $this->assertEquals($schemaFromAnalyser->getTableNames(), $schemaFromAnalyserCached->getTableNames()); + } + public function testGetSchema(): void { $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); From 446d15280c5b2e3e64936c9e7a3ac9544df3f289 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Fri, 6 Sep 2019 18:34:18 +0200 Subject: [PATCH 02/10] added composer classLoader as a hidden dependancy --- composer-require-checker.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/composer-require-checker.json b/composer-require-checker.json index 8718fd43..7f829518 100644 --- a/composer-require-checker.json +++ b/composer-require-checker.json @@ -8,7 +8,8 @@ "TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestUserDaoTrait", "TheCodingMachine\\TDBM\\Fixtures\\Interfaces\\TestUserInterface", "TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestUserTrait", - "TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestOtherUserTrait" + "TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestOtherUserTrait", + "Composer\\Autoload\\ClassLoader" ], "php-core-extensions" : [ "Core", From 472b0b14f56688e217e047be3529b149f812c1f7 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Fri, 6 Sep 2019 21:44:24 +0200 Subject: [PATCH 03/10] added a test when trying to load the schema without a cache or lock file --- tests/TDBMDaoGeneratorTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/TDBMDaoGeneratorTest.php b/tests/TDBMDaoGeneratorTest.php index f716772b..298d3430 100644 --- a/tests/TDBMDaoGeneratorTest.php +++ b/tests/TDBMDaoGeneratorTest.php @@ -104,6 +104,20 @@ protected function setUp(): void //$this->tdbmDaoGenerator->setComposerFile($this->rootPath.'composer.json'); } + public function testGetSchemaCrashWithoutLock() + { + //let's delete the lock file + $schemaFilePath = TDBMSchemaAnalyzer::getLockFilePath(); + if (file_exists($schemaFilePath)) { + unlink($schemaFilePath); + } + //let's check we cannot call get schema without a lock file + $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), new ArrayCache(), $schemaAnalyzer); + $this->expectException('TheCodingMachine\TDBM\TDBMException'); + $schema1 = $tdbmSchemaAnalyzer->getSchema(true); + } + public function testDaoGeneration(): void { // Remove all previously generated files. From e837a57ce5b9f05db30fda4c28f87d0a698414cf Mon Sep 17 00:00:00 2001 From: kharhamel Date: Mon, 9 Sep 2019 10:43:08 +0200 Subject: [PATCH 04/10] edited minimum dependancy version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index e005de4f..59c44b5e 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "ext-json": "*", "ext-hash": "*", "ext-filter": "*", - "brain-diminished/schema-version-control": "^1.0" + "brain-diminished/schema-version-control": "^1.0.1" }, "require-dev" : { "phpunit/phpunit": "^7.4.4 || ^8.0.0", From 3ed959dd680749bbde5a8d905b6f60b7d8a95a9a Mon Sep 17 00:00:00 2001 From: kharhamel Date: Fri, 20 Sep 2019 17:23:38 +0200 Subject: [PATCH 05/10] fixed a test in postgres --- tests/TDBMSchemaAnalyzerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/TDBMSchemaAnalyzerTest.php b/tests/TDBMSchemaAnalyzerTest.php index c5894b1f..2111914a 100644 --- a/tests/TDBMSchemaAnalyzerTest.php +++ b/tests/TDBMSchemaAnalyzerTest.php @@ -44,10 +44,10 @@ public function testSchemaLock(): void $schemaFromConnec = self::getConnection()->getSchemaManager()->createSchema(); $tableNames = []; //lock file doesn't save the database name so we have to replace it manually. + ImmutableCaster::castSchemaToImmutable($schemaFromConnec); foreach ($schemaFromConnec->getTableNames() as $tableName) { - $tableNames[] = str_replace('tdbm_testcase', 'public', $tableName); + $tableNames[] = str_replace(['tdbm_testcase', 'postgres'], 'public', $tableName); } - ImmutableCaster::castSchemaToImmutable($schemaFromConnec); $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); From e53a4148c5f1ebaa0059ea36c41880732beedcf7 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Tue, 24 Sep 2019 12:07:30 +0200 Subject: [PATCH 06/10] added an option to generate the daos from lock file --- src/Commands/GenerateCommand.php | 7 ++++++- src/TDBMSchemaAnalyzer.php | 1 + src/TDBMService.php | 4 ++-- src/Utils/TDBMDaoGenerator.php | 6 ++++-- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Commands/GenerateCommand.php b/src/Commands/GenerateCommand.php index 16d11982..5572be78 100644 --- a/src/Commands/GenerateCommand.php +++ b/src/Commands/GenerateCommand.php @@ -3,6 +3,7 @@ namespace TheCodingMachine\TDBM\Commands; +use Symfony\Component\Console\Input\InputOption; use TheCodingMachine\TDBM\ConfigurationInterface; use TheCodingMachine\TDBM\TDBMService; use Mouf\Utils\Log\Psr\MultiLogger; @@ -30,6 +31,9 @@ protected function configure() $this->setName('tdbm:generate') ->setDescription('Generates DAOs and beans.') ->setHelp('Use this command to generate or regenerate the DAOs and beans for your project.') + ->addOption( + 'from-lock',null,InputOption::VALUE_OPTIONAL, 'Load the schema from the lock file instead of database',false + ); ; } @@ -39,6 +43,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $alteredConf = new AlteredConfiguration($this->configuration); + $fromLock = (bool) $input->getOption('from-lock'); $loggers = [ new ConsoleLogger($output) ]; @@ -54,7 +59,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $multiLogger->notice('Starting regenerating DAOs and beans'); $tdbmService = new TDBMService($this->configuration); - $tdbmService->generateAllDaosAndBeans(); + $tdbmService->generateAllDaosAndBeans($fromLock); $multiLogger->notice('Finished regenerating DAOs and beans'); } diff --git a/src/TDBMSchemaAnalyzer.php b/src/TDBMSchemaAnalyzer.php index ab3d3fb9..5b5b2194 100644 --- a/src/TDBMSchemaAnalyzer.php +++ b/src/TDBMSchemaAnalyzer.php @@ -78,6 +78,7 @@ public function getCachePrefix(): string return $this->cachePrefix; } + //todo: in config public static function getLockFilePath(): string { return RootProjectLocator::getRootLocationPath().self::schemaFileName; diff --git a/src/TDBMService.php b/src/TDBMService.php index ad33b10c..8228dc5d 100644 --- a/src/TDBMService.php +++ b/src/TDBMService.php @@ -527,7 +527,7 @@ public function _addToToSaveObjectList(DbRow $myObject): void /** * Generates all the daos and beans. */ - public function generateAllDaosAndBeans() : void + public function generateAllDaosAndBeans(bool $fromLock = false) : void { // Purge cache before generating anything. if ($this->cache instanceof ClearableCache) { @@ -535,7 +535,7 @@ public function generateAllDaosAndBeans() : void } $tdbmDaoGenerator = new TDBMDaoGenerator($this->configuration, $this->tdbmSchemaAnalyzer); - $tdbmDaoGenerator->generateAllDaosAndBeans(); + $tdbmDaoGenerator->generateAllDaosAndBeans($fromLock); } /** diff --git a/src/Utils/TDBMDaoGenerator.php b/src/Utils/TDBMDaoGenerator.php index 195e853f..3bd2fccf 100644 --- a/src/Utils/TDBMDaoGenerator.php +++ b/src/Utils/TDBMDaoGenerator.php @@ -71,9 +71,11 @@ public function __construct(ConfigurationInterface $configuration, TDBMSchemaAna * * @throws TDBMException */ - public function generateAllDaosAndBeans(): void + public function generateAllDaosAndBeans(bool $fromLock = false): void { - $this->tdbmSchemaAnalyzer->generateLockFile(); + if (!$fromLock) { + $this->tdbmSchemaAnalyzer->generateLockFile(); + } $schema = $this->tdbmSchemaAnalyzer->getSchema(); // TODO: check that no class name ends with "Base". Otherwise, there will be name clash. From 51a99714f794210ef846c112d18a037a1626b157 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Tue, 24 Sep 2019 13:56:00 +0200 Subject: [PATCH 07/10] allow edition of the lockfile path in configuration --- src/Commands/AlteredConfiguration.php | 5 ++++ src/Commands/GenerateCommand.php | 8 ++++-- src/Configuration.php | 16 ++++++++++- src/ConfigurationInterface.php | 2 ++ src/TDBMSchemaAnalyzer.php | 22 +++++++-------- src/TDBMService.php | 3 ++- tests/Commands/GenerateCommandTest.php | 37 +++++--------------------- tests/Performance/ManyToOneBench.php | 2 +- tests/TDBMDaoGeneratorTest.php | 10 +++---- tests/TDBMSchemaAnalyzerTest.php | 16 +++++------ tests/Utils/BeanDescriptorTest.php | 3 ++- 11 files changed, 64 insertions(+), 60 deletions(-) diff --git a/src/Commands/AlteredConfiguration.php b/src/Commands/AlteredConfiguration.php index b705372d..51a6b880 100644 --- a/src/Commands/AlteredConfiguration.php +++ b/src/Commands/AlteredConfiguration.php @@ -138,4 +138,9 @@ public function getAnnotationParser(): AnnotationParser { return $this->configuration->getAnnotationParser(); } + + public function getLockFilePath(): string + { + return $this->configuration->getLockFilePath(); + } } diff --git a/src/Commands/GenerateCommand.php b/src/Commands/GenerateCommand.php index 5572be78..f7565b4c 100644 --- a/src/Commands/GenerateCommand.php +++ b/src/Commands/GenerateCommand.php @@ -32,8 +32,12 @@ protected function configure() ->setDescription('Generates DAOs and beans.') ->setHelp('Use this command to generate or regenerate the DAOs and beans for your project.') ->addOption( - 'from-lock',null,InputOption::VALUE_OPTIONAL, 'Load the schema from the lock file instead of database',false - ); + 'from-lock', + null, + InputOption::VALUE_OPTIONAL, + 'Load the schema from the lock file instead of database', + false + ) ; } diff --git a/src/Configuration.php b/src/Configuration.php index 1b0bec2c..377dd57b 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -21,6 +21,7 @@ use TheCodingMachine\TDBM\Utils\PathFinder\PathFinderInterface; use Psr\Log\LoggerInterface; use TheCodingMachine\TDBM\Utils\PathFinder\PathFinder; +use TheCodingMachine\TDBM\Utils\RootProjectLocator; class Configuration implements ConfigurationInterface { @@ -69,6 +70,7 @@ class Configuration implements ConfigurationInterface * @var AnnotationParser */ private $annotationParser; + private $lockFilePath; /** * @param string $beanNamespace The namespace hosting the beans @@ -81,9 +83,10 @@ class Configuration implements ConfigurationInterface * @param GeneratorListenerInterface[] $generatorListeners A list of listeners that will be triggered when beans/daos are generated * @param AnnotationParser|null $annotationParser * @param CodeGeneratorListenerInterface[] $codeGeneratorListeners A list of listeners that can alter code generation of each bean/dao + * @param string|null $lockFilePath * @throws \Mouf\Database\SchemaAnalyzer\SchemaAnalyzerException */ - public function __construct(string $beanNamespace, string $daoNamespace, Connection $connection, NamingStrategyInterface $namingStrategy = null, Cache $cache = null, SchemaAnalyzer $schemaAnalyzer = null, LoggerInterface $logger = null, array $generatorListeners = [], AnnotationParser $annotationParser = null, array $codeGeneratorListeners = []) + public function __construct(string $beanNamespace, string $daoNamespace, Connection $connection, NamingStrategyInterface $namingStrategy = null, Cache $cache = null, SchemaAnalyzer $schemaAnalyzer = null, LoggerInterface $logger = null, array $generatorListeners = [], AnnotationParser $annotationParser = null, array $codeGeneratorListeners = [], string $lockFilePath = null) { $this->beanNamespace = rtrim($beanNamespace, '\\'); $this->daoNamespace = rtrim($daoNamespace, '\\'); @@ -104,6 +107,7 @@ public function __construct(string $beanNamespace, string $daoNamespace, Connect $this->annotationParser = $annotationParser ?: AnnotationParser::buildWithDefaultAnnotations([]); $this->codeGeneratorListener = new CodeGeneratorEventDispatcher($codeGeneratorListeners); $this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy($this->annotationParser, $this->connection->getSchemaManager()); + $this->lockFilePath = $lockFilePath; } /** @@ -214,4 +218,14 @@ public function getAnnotationParser(): AnnotationParser { return $this->annotationParser; } + + public static function getDefaultLockFilePath(): string + { + return RootProjectLocator::getRootLocationPath().'tdbm.lock.yml'; + } + + public function getLockFilePath(): string + { + return $this->lockFilePath ?: self::getDefaultLockFilePath(); + } } diff --git a/src/ConfigurationInterface.php b/src/ConfigurationInterface.php index 45a19fe5..703a8bda 100644 --- a/src/ConfigurationInterface.php +++ b/src/ConfigurationInterface.php @@ -73,4 +73,6 @@ public function getPathFinder(): PathFinderInterface; * @return AnnotationParser */ public function getAnnotationParser(): AnnotationParser; + + public function getLockFilePath(): string; } diff --git a/src/TDBMSchemaAnalyzer.php b/src/TDBMSchemaAnalyzer.php index 5b5b2194..296728df 100644 --- a/src/TDBMSchemaAnalyzer.php +++ b/src/TDBMSchemaAnalyzer.php @@ -14,15 +14,13 @@ use Doctrine\DBAL\Types\Type; use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer; use TheCodingMachine\TDBM\Utils\ImmutableCaster; -use TheCodingMachine\TDBM\Utils\RootProjectLocator; /** * This class is used to analyze the schema and return valuable information / hints. */ class TDBMSchemaAnalyzer { - const schemaFileName = 'tdbm.lock.yml'; - + private $lockFilePath; private $connection; /** @@ -51,17 +49,19 @@ class TDBMSchemaAnalyzer private $schemaVersionControlService; /** - * @param Connection $connection The DBAL DB connection to use - * @param Cache $cache A cache service to be used + * @param Connection $connection The DBAL DB connection to use + * @param Cache $cache A cache service to be used * @param SchemaAnalyzer $schemaAnalyzer The schema analyzer that will be used to find shortest paths... * Will be automatically created if not passed + * @param string $lockFilePath The path for the lock file which will store the database schema */ - public function __construct(Connection $connection, Cache $cache, SchemaAnalyzer $schemaAnalyzer) + public function __construct(Connection $connection, Cache $cache, SchemaAnalyzer $schemaAnalyzer, string $lockFilePath) { $this->connection = $connection; $this->cache = $cache; $this->schemaAnalyzer = $schemaAnalyzer; - $this->schemaVersionControlService = new SchemaVersionControlService($this->connection, self::getLockFilePath()); + $this->lockFilePath = $lockFilePath; + $this->schemaVersionControlService = new SchemaVersionControlService($this->connection, $this->lockFilePath); } /** @@ -78,10 +78,9 @@ public function getCachePrefix(): string return $this->cachePrefix; } - //todo: in config - public static function getLockFilePath(): string + public function getLockFilePath(): string { - return RootProjectLocator::getRootLocationPath().self::schemaFileName; + return $this->lockFilePath; } /** @@ -93,7 +92,7 @@ public function getSchema(bool $ignoreCache = false): Schema $cacheKey = $this->getCachePrefix().'_immutable_schema'; if (!$ignoreCache && $this->cache->contains($cacheKey)) { $this->schema = $this->cache->fetch($cacheKey); - } elseif (!file_exists(self::getLockFilePath())) { + } elseif (!file_exists($this->getLockFilePath())) { throw new TDBMException('No tdbm lock file found. Please regenerate DAOs and Beans.'); } else { $this->schema = $this->schemaVersionControlService->loadSchemaFile(); @@ -108,6 +107,7 @@ public function getSchema(bool $ignoreCache = false): Schema public function generateLockFile(): void { $this->schemaVersionControlService->dumpSchema(); + \chmod($this->getLockFilePath(), 0664); } /** diff --git a/src/TDBMService.php b/src/TDBMService.php index 8228dc5d..aec76524 100644 --- a/src/TDBMService.php +++ b/src/TDBMService.php @@ -187,10 +187,11 @@ public function __construct(ConfigurationInterface $configuration) $this->connection = $configuration->getConnection(); $this->cache = $configuration->getCache(); $this->schemaAnalyzer = $configuration->getSchemaAnalyzer(); + $lockFilePath = $configuration->getLockFilePath(); $this->magicQuery = new MagicQuery($this->connection, $this->cache, $this->schemaAnalyzer); - $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->connection, $this->cache, $this->schemaAnalyzer); + $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->connection, $this->cache, $this->schemaAnalyzer, $lockFilePath); $this->cachePrefix = $this->tdbmSchemaAnalyzer->getCachePrefix(); $this->toSaveObjects = new \SplObjectStorage(); diff --git a/tests/Commands/GenerateCommandTest.php b/tests/Commands/GenerateCommandTest.php index ff1a35f1..9a5487d3 100644 --- a/tests/Commands/GenerateCommandTest.php +++ b/tests/Commands/GenerateCommandTest.php @@ -3,6 +3,7 @@ namespace TheCodingMachine\TDBM\Commands; +use TheCodingMachine\TDBM\Configuration; use TheCodingMachine\TDBM\TDBMAbstractServiceTest; use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Input\ArrayInput; @@ -10,49 +11,25 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\BufferedOutput; use Symfony\Component\Console\Output\OutputInterface; -use TheCodingMachine\TDBM\TDBMSchemaAnalyzer; class GenerateCommandTest extends TDBMAbstractServiceTest { - public static function getInputDefinition() - { - return new InputDefinition([ - ]); - } - public function testCall(): void { - $input = new ArrayInput([ - ], self::getInputDefinition()); + $input = new ArrayInput([], new InputDefinition([])); + $output = new BufferedOutput(); + $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); //let's delete the lock file - $schemaFilePath = TDBMSchemaAnalyzer::getLockFilePath(); + $schemaFilePath = Configuration::getDefaultLockFilePath(); if (file_exists($schemaFilePath)) { unlink($schemaFilePath); } - $result = $this->callCommand(new GenerateCommand($this->getConfiguration()), $input); + (new GenerateCommand($this->getConfiguration()))->run($input, $output); + $result = $output->fetch(); $this->assertContains('Finished regenerating DAOs and beans', $result); //Check that the lock file was generated $this->assertFileExists($schemaFilePath); } - - /** - * Calls the command passed in parameter. Returns the output. - * - * @param Command $command - * @param InputInterface $input - * @return string - */ - protected function callCommand(Command $command, InputInterface $input) : string - { - $output = new BufferedOutput(); - $output->setVerbosity(OutputInterface::VERBOSITY_DEBUG); - - $r = new \ReflectionMethod($command, 'execute'); - $r->setAccessible(true); - $r->invoke($command, $input, $output); - - return $output->fetch(); - } } diff --git a/tests/Performance/ManyToOneBench.php b/tests/Performance/ManyToOneBench.php index 1ac42da4..4b53642a 100644 --- a/tests/Performance/ManyToOneBench.php +++ b/tests/Performance/ManyToOneBench.php @@ -91,7 +91,7 @@ private static function generateDaosAndBeans(Connection $connection): void { $schemaManager = $connection->getSchemaManager(); $schemaAnalyzer = new SchemaAnalyzer($schemaManager); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($connection, new ArrayCache(), $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($connection, new ArrayCache(), $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $tdbmDaoGenerator = new TDBMDaoGenerator(self::createConfiguration(), $tdbmSchemaAnalyzer); $rootPath = __DIR__ . '/../'; self::recursiveDelete(__DIR__. '/../../src/Test/Dao/'); diff --git a/tests/TDBMDaoGeneratorTest.php b/tests/TDBMDaoGeneratorTest.php index 298d3430..1d923365 100644 --- a/tests/TDBMDaoGeneratorTest.php +++ b/tests/TDBMDaoGeneratorTest.php @@ -98,7 +98,7 @@ protected function setUp(): void parent::setUp(); $schemaManager = $this->tdbmService->getConnection()->getSchemaManager(); $schemaAnalyzer = new SchemaAnalyzer($schemaManager); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->tdbmService->getConnection(), new ArrayCache(), $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->tdbmService->getConnection(), new ArrayCache(), $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $this->tdbmDaoGenerator = new TDBMDaoGenerator($this->getConfiguration(), $tdbmSchemaAnalyzer); $this->rootPath = __DIR__ . '/../'; //$this->tdbmDaoGenerator->setComposerFile($this->rootPath.'composer.json'); @@ -107,13 +107,13 @@ protected function setUp(): void public function testGetSchemaCrashWithoutLock() { //let's delete the lock file - $schemaFilePath = TDBMSchemaAnalyzer::getLockFilePath(); + $schemaFilePath = Configuration::getDefaultLockFilePath(); if (file_exists($schemaFilePath)) { unlink($schemaFilePath); } //let's check we cannot call get schema without a lock file $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), new ArrayCache(), $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), new ArrayCache(), $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $this->expectException('TheCodingMachine\TDBM\TDBMException'); $schema1 = $tdbmSchemaAnalyzer->getSchema(true); } @@ -129,7 +129,7 @@ public function testDaoGeneration(): void $this->assertFileExists($dummyFile); //let's delete the lock file - $schemaFilePath = TDBMSchemaAnalyzer::getLockFilePath(); + $schemaFilePath = Configuration::getDefaultLockFilePath(); if (file_exists($schemaFilePath)) { unlink($schemaFilePath); } @@ -169,7 +169,7 @@ public function testGenerationException(): void $schemaManager = $this->tdbmService->getConnection()->getSchemaManager(); $schemaAnalyzer = new SchemaAnalyzer($schemaManager); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->tdbmService->getConnection(), new ArrayCache(), $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->tdbmService->getConnection(), new ArrayCache(), $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $tdbmDaoGenerator = new TDBMDaoGenerator($configuration, $tdbmSchemaAnalyzer); $this->rootPath = __DIR__ . '/../../../../'; //$tdbmDaoGenerator->setComposerFile($this->rootPath.'composer.json'); diff --git a/tests/TDBMSchemaAnalyzerTest.php b/tests/TDBMSchemaAnalyzerTest.php index 2111914a..0756facd 100644 --- a/tests/TDBMSchemaAnalyzerTest.php +++ b/tests/TDBMSchemaAnalyzerTest.php @@ -36,7 +36,7 @@ protected function setUp(): void { parent::setUp(); $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); - $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), new ArrayCache(), $schemaAnalyzer); + $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), new ArrayCache(), $schemaAnalyzer, Configuration::getDefaultLockFilePath()); } public function testSchemaLock(): void @@ -51,7 +51,7 @@ public function testSchemaLock(): void $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); - $tdbmSchemaAnalyzer1 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + $tdbmSchemaAnalyzer1 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $schemaFromAnalyser = $tdbmSchemaAnalyzer1->getSchema(true); $schemaFromAnalyserCached = $tdbmSchemaAnalyzer1->getSchema(); @@ -63,8 +63,8 @@ public function testGetSchema(): void { $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); - $tdbmSchemaAnalyzer1 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); - $tdbmSchemaAnalyzer2 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + $tdbmSchemaAnalyzer1 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); + $tdbmSchemaAnalyzer2 = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); // Why don't we go in all lines of code???? $schema1 = $tdbmSchemaAnalyzer1->getSchema(); @@ -77,7 +77,7 @@ public function testGetIncomingForeignKeys(): void { $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $fks = $tdbmSchemaAnalyzer->getIncomingForeignKeys('users'); $this->assertCount(1, $fks); @@ -87,7 +87,7 @@ public function testGetIncomingForeignKeys2(): void { $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $fks = $tdbmSchemaAnalyzer->getIncomingForeignKeys('contact'); $this->assertCount(1, $fks); @@ -97,7 +97,7 @@ public function testGetIncomingForeignKeys3(): void { $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $fks = $tdbmSchemaAnalyzer->getIncomingForeignKeys('country'); $this->assertCount(5, $fks); @@ -112,7 +112,7 @@ public function testGetPivotTableLinkedToTable(): void { $schemaAnalyzer = new SchemaAnalyzer(self::getConnection()->getSchemaManager(), new ArrayCache(), 'prefix_'); $cache = new ArrayCache(); - $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer); + $tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer(self::getConnection(), $cache, $schemaAnalyzer, Configuration::getDefaultLockFilePath()); $pivotTables = $tdbmSchemaAnalyzer->getPivotTableLinkedToTable('rights'); $this->assertCount(1, $pivotTables); diff --git a/tests/Utils/BeanDescriptorTest.php b/tests/Utils/BeanDescriptorTest.php index 2920d6fd..a7b3671a 100644 --- a/tests/Utils/BeanDescriptorTest.php +++ b/tests/Utils/BeanDescriptorTest.php @@ -26,6 +26,7 @@ use Doctrine\DBAL\Schema\Table; use Doctrine\DBAL\Types\Type; use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer; +use TheCodingMachine\TDBM\Configuration; use TheCodingMachine\TDBM\TDBMAbstractServiceTest; use TheCodingMachine\TDBM\TDBMException; use TheCodingMachine\TDBM\TDBMSchemaAnalyzer; @@ -53,7 +54,7 @@ protected function setUp(): void $schemaManager = $this->tdbmService->getConnection()->getSchemaManager(); $this->schemaAnalyzer = new SchemaAnalyzer($schemaManager); $this->schema = $schemaManager->createSchema(); - $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->tdbmService->getConnection(), new VoidCache(), $this->schemaAnalyzer); + $this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->tdbmService->getConnection(), new VoidCache(), $this->schemaAnalyzer, Configuration::getDefaultLockFilePath()); } public function testConstructor(): void From 21f3dbf7440c56b41e9ffd793da6f37e1051a420 Mon Sep 17 00:00:00 2001 From: kharhamel Date: Tue, 24 Sep 2019 17:31:50 +0200 Subject: [PATCH 08/10] updated brain-diminished/schema-version-control version --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 59c44b5e..50bdc70a 100644 --- a/composer.json +++ b/composer.json @@ -40,7 +40,7 @@ "ext-json": "*", "ext-hash": "*", "ext-filter": "*", - "brain-diminished/schema-version-control": "^1.0.1" + "brain-diminished/schema-version-control": "^1.0.2" }, "require-dev" : { "phpunit/phpunit": "^7.4.4 || ^8.0.0", From f4750d5174427d6db018708bf1131b3c4da8cb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 30 Sep 2019 10:41:40 +0200 Subject: [PATCH 09/10] Improing code coverage --- tests/Commands/AlteredConfigurationTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/Commands/AlteredConfigurationTest.php b/tests/Commands/AlteredConfigurationTest.php index 7e117dbd..bda794a6 100644 --- a/tests/Commands/AlteredConfigurationTest.php +++ b/tests/Commands/AlteredConfigurationTest.php @@ -36,6 +36,8 @@ public function testAlteredConfiguration(): void $this->assertSame($schemaAnalyzer, $alteredConfiguration->getSchemaAnalyzer()); $this->assertSame($configuration->getPathFinder(), $alteredConfiguration->getPathFinder()); $this->assertSame($configuration->getAnnotationParser(), $alteredConfiguration->getAnnotationParser()); + $this->assertSame($configuration->getLockFilePath(), $alteredConfiguration->getLockFilePath()); + $this->assertSame($configuration->getCodeGeneratorListener(), $alteredConfiguration->getCodeGeneratorListener()); $logger2 = new NullLogger(); $alteredConfiguration->setLogger($logger2); From d8a7b2568ccc58db149e9430ea8530037d489839 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20N=C3=A9grier?= Date: Mon, 30 Sep 2019 11:53:52 +0200 Subject: [PATCH 10/10] Adding @internal annotation --- src/Configuration.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Configuration.php b/src/Configuration.php index 9f39fee7..be01637c 100644 --- a/src/Configuration.php +++ b/src/Configuration.php @@ -249,6 +249,9 @@ public function getAnnotationParser(): AnnotationParser return $this->annotationParser; } + /** + * @internal + */ public static function getDefaultLockFilePath(): string { return RootProjectLocator::getRootLocationPath().'tdbm.lock.yml';