Skip to content

Commit 3b7d130

Browse files
authored
Merge pull request #171 from Kharhamel/lockFile
added a schema lock file to tdbm
2 parents 8120b7d + d8a7b25 commit 3b7d130

18 files changed

+203
-89
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ vendor/*
1616
.phpunit.result.cache
1717
/phpbench.sh
1818
/xdebug/
19+
.php_cs.cache
20+
tdbm.lock.yml

composer-require-checker.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
"TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestUserDaoTrait",
99
"TheCodingMachine\\TDBM\\Fixtures\\Interfaces\\TestUserInterface",
1010
"TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestUserTrait",
11-
"TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestOtherUserTrait"
11+
"TheCodingMachine\\TDBM\\Fixtures\\Traits\\TestOtherUserTrait",
12+
"Composer\\Autoload\\ClassLoader"
1213
],
1314
"php-core-extensions" : [
1415
"Core",

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@
3939
"ext-PDO": "*",
4040
"ext-json": "*",
4141
"ext-hash": "*",
42-
"ext-filter": "*"
42+
"ext-filter": "*",
43+
"brain-diminished/schema-version-control": "^1.0.2"
4344
},
4445
"require-dev" : {
4546
"phpunit/phpunit": "^7.4.4 || ^8.0.0",

src/Commands/AlteredConfiguration.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,4 +146,9 @@ public function getAnnotationParser(): AnnotationParser
146146
{
147147
return $this->configuration->getAnnotationParser();
148148
}
149+
150+
public function getLockFilePath(): string
151+
{
152+
return $this->configuration->getLockFilePath();
153+
}
149154
}

src/Commands/GenerateCommand.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace TheCodingMachine\TDBM\Commands;
55

6+
use Symfony\Component\Console\Input\InputOption;
67
use TheCodingMachine\TDBM\ConfigurationInterface;
78
use TheCodingMachine\TDBM\TDBMService;
89
use Mouf\Utils\Log\Psr\MultiLogger;
@@ -30,6 +31,13 @@ protected function configure()
3031
$this->setName('tdbm:generate')
3132
->setDescription('Generates DAOs and beans.')
3233
->setHelp('Use this command to generate or regenerate the DAOs and beans for your project.')
34+
->addOption(
35+
'from-lock',
36+
null,
37+
InputOption::VALUE_OPTIONAL,
38+
'Load the schema from the lock file instead of database',
39+
false
40+
)
3341
;
3442
}
3543

@@ -39,6 +47,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
3947

4048
$alteredConf = new AlteredConfiguration($this->configuration);
4149

50+
$fromLock = (bool) $input->getOption('from-lock');
4251

4352
$loggers = [ new ConsoleLogger($output) ];
4453

@@ -54,7 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output)
5463
$multiLogger->notice('Starting regenerating DAOs and beans');
5564

5665
$tdbmService = new TDBMService($this->configuration);
57-
$tdbmService->generateAllDaosAndBeans();
66+
$tdbmService->generateAllDaosAndBeans($fromLock);
5867

5968
$multiLogger->notice('Finished regenerating DAOs and beans');
6069
}

src/Configuration.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
use TheCodingMachine\TDBM\Utils\PathFinder\PathFinderInterface;
2222
use Psr\Log\LoggerInterface;
2323
use TheCodingMachine\TDBM\Utils\PathFinder\PathFinder;
24+
use TheCodingMachine\TDBM\Utils\RootProjectLocator;
2425

2526
class Configuration implements ConfigurationInterface
2627
{
@@ -71,6 +72,7 @@ class Configuration implements ConfigurationInterface
7172
* @var AnnotationParser
7273
*/
7374
private $annotationParser;
75+
private $lockFilePath;
7476

7577
/**
7678
* @param string $beanNamespace The namespace hosting the beans
@@ -84,6 +86,7 @@ class Configuration implements ConfigurationInterface
8486
* @param GeneratorListenerInterface[] $generatorListeners A list of listeners that will be triggered when beans/daos are generated
8587
* @param AnnotationParser|null $annotationParser
8688
* @param CodeGeneratorListenerInterface[] $codeGeneratorListeners A list of listeners that can alter code generation of each bean/dao
89+
* @param string|null $lockFilePath
8790
* @throws \Mouf\Database\SchemaAnalyzer\SchemaAnalyzerException
8891
*/
8992
public function __construct(
@@ -97,7 +100,8 @@ public function __construct(
97100
array $generatorListeners = [],
98101
AnnotationParser $annotationParser = null,
99102
array $codeGeneratorListeners = [],
100-
string $resultIteratorNamespace = null
103+
string $resultIteratorNamespace = null,
104+
string $lockFilePath = null
101105
) {
102106
$this->beanNamespace = rtrim($beanNamespace, '\\');
103107
$this->daoNamespace = rtrim($daoNamespace, '\\');
@@ -125,6 +129,7 @@ public function __construct(
125129
$this->annotationParser = $annotationParser ?: AnnotationParser::buildWithDefaultAnnotations([]);
126130
$this->codeGeneratorListener = new CodeGeneratorEventDispatcher($codeGeneratorListeners);
127131
$this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy($this->annotationParser, $this->connection->getSchemaManager());
132+
$this->lockFilePath = $lockFilePath;
128133
}
129134

130135
/**
@@ -243,4 +248,17 @@ public function getAnnotationParser(): AnnotationParser
243248
{
244249
return $this->annotationParser;
245250
}
251+
252+
/**
253+
* @internal
254+
*/
255+
public static function getDefaultLockFilePath(): string
256+
{
257+
return RootProjectLocator::getRootLocationPath().'tdbm.lock.yml';
258+
}
259+
260+
public function getLockFilePath(): string
261+
{
262+
return $this->lockFilePath ?: self::getDefaultLockFilePath();
263+
}
246264
}

src/ConfigurationInterface.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,6 @@ public function getPathFinder(): PathFinderInterface;
7878
* @return AnnotationParser
7979
*/
8080
public function getAnnotationParser(): AnnotationParser;
81+
82+
public function getLockFilePath(): string;
8183
}

src/TDBMSchemaAnalyzer.php

Lines changed: 28 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
namespace TheCodingMachine\TDBM;
55

6+
use BrainDiminished\SchemaVersionControl\SchemaVersionControlService;
67
use Doctrine\Common\Cache\Cache;
78
use Doctrine\DBAL\Connection;
89
use Doctrine\DBAL\Schema\Column;
@@ -12,12 +13,14 @@
1213
use Doctrine\DBAL\Types\DateType;
1314
use Doctrine\DBAL\Types\Type;
1415
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
16+
use TheCodingMachine\TDBM\Utils\ImmutableCaster;
1517

1618
/**
1719
* This class is used to analyze the schema and return valuable information / hints.
1820
*/
1921
class TDBMSchemaAnalyzer
2022
{
23+
private $lockFilePath;
2124
private $connection;
2225

2326
/**
@@ -41,16 +44,24 @@ class TDBMSchemaAnalyzer
4144
private $schemaAnalyzer;
4245

4346
/**
44-
* @param Connection $connection The DBAL DB connection to use
45-
* @param Cache $cache A cache service to be used
47+
* @var SchemaVersionControlService
48+
*/
49+
private $schemaVersionControlService;
50+
51+
/**
52+
* @param Connection $connection The DBAL DB connection to use
53+
* @param Cache $cache A cache service to be used
4654
* @param SchemaAnalyzer $schemaAnalyzer The schema analyzer that will be used to find shortest paths...
4755
* Will be automatically created if not passed
56+
* @param string $lockFilePath The path for the lock file which will store the database schema
4857
*/
49-
public function __construct(Connection $connection, Cache $cache, SchemaAnalyzer $schemaAnalyzer)
58+
public function __construct(Connection $connection, Cache $cache, SchemaAnalyzer $schemaAnalyzer, string $lockFilePath)
5059
{
5160
$this->connection = $connection;
5261
$this->cache = $cache;
5362
$this->schemaAnalyzer = $schemaAnalyzer;
63+
$this->lockFilePath = $lockFilePath;
64+
$this->schemaVersionControlService = new SchemaVersionControlService($this->connection, $this->lockFilePath);
5465
}
5566

5667
/**
@@ -67,53 +78,36 @@ public function getCachePrefix(): string
6778
return $this->cachePrefix;
6879
}
6980

81+
public function getLockFilePath(): string
82+
{
83+
return $this->lockFilePath;
84+
}
85+
7086
/**
7187
* Returns the (cached) schema.
72-
*
73-
* @return Schema
7488
*/
75-
public function getSchema(): Schema
89+
public function getSchema(bool $ignoreCache = false): Schema
7690
{
7791
if ($this->schema === null) {
7892
$cacheKey = $this->getCachePrefix().'_immutable_schema';
79-
if ($this->cache->contains($cacheKey)) {
93+
if (!$ignoreCache && $this->cache->contains($cacheKey)) {
8094
$this->schema = $this->cache->fetch($cacheKey);
95+
} elseif (!file_exists($this->getLockFilePath())) {
96+
throw new TDBMException('No tdbm lock file found. Please regenerate DAOs and Beans.');
8197
} else {
82-
$this->schema = $this->connection->getSchemaManager()->createSchema();
83-
$this->castSchemaToImmutable($this->schema);
98+
$this->schema = $this->schemaVersionControlService->loadSchemaFile();
99+
ImmutableCaster::castSchemaToImmutable($this->schema);
84100
$this->cache->save($cacheKey, $this->schema);
85101
}
86102
}
87103

88104
return $this->schema;
89105
}
90106

91-
private function castSchemaToImmutable(Schema $schema): void
107+
public function generateLockFile(): void
92108
{
93-
foreach ($schema->getTables() as $table) {
94-
foreach ($table->getColumns() as $column) {
95-
$this->toImmutableType($column);
96-
}
97-
}
98-
}
99-
100-
/**
101-
* Changes the type of a column to an immutable date type if the type is a date.
102-
* This is needed because by default, when reading a Schema, Doctrine assumes a mutable datetime.
103-
*/
104-
private function toImmutableType(Column $column): void
105-
{
106-
$mapping = [
107-
Type::DATE => Type::DATE_IMMUTABLE,
108-
Type::DATETIME => Type::DATETIME_IMMUTABLE,
109-
Type::DATETIMETZ => Type::DATETIMETZ_IMMUTABLE,
110-
Type::TIME => Type::TIME_IMMUTABLE
111-
];
112-
113-
$typeName = $column->getType()->getName();
114-
if (isset($mapping[$typeName])) {
115-
$column->setType(Type::getType($mapping[$typeName]));
116-
}
109+
$this->schemaVersionControlService->dumpSchema();
110+
\chmod($this->getLockFilePath(), 0664);
117111
}
118112

119113
/**

src/TDBMService.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,10 +187,11 @@ public function __construct(ConfigurationInterface $configuration)
187187
$this->connection = $configuration->getConnection();
188188
$this->cache = $configuration->getCache();
189189
$this->schemaAnalyzer = $configuration->getSchemaAnalyzer();
190+
$lockFilePath = $configuration->getLockFilePath();
190191

191192
$this->magicQuery = new MagicQuery($this->connection, $this->cache, $this->schemaAnalyzer);
192193

193-
$this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->connection, $this->cache, $this->schemaAnalyzer);
194+
$this->tdbmSchemaAnalyzer = new TDBMSchemaAnalyzer($this->connection, $this->cache, $this->schemaAnalyzer, $lockFilePath);
194195
$this->cachePrefix = $this->tdbmSchemaAnalyzer->getCachePrefix();
195196

196197
$this->toSaveObjects = new \SplObjectStorage();
@@ -527,15 +528,15 @@ public function _addToToSaveObjectList(DbRow $myObject): void
527528
/**
528529
* Generates all the daos and beans.
529530
*/
530-
public function generateAllDaosAndBeans() : void
531+
public function generateAllDaosAndBeans(bool $fromLock = false) : void
531532
{
532533
// Purge cache before generating anything.
533534
if ($this->cache instanceof ClearableCache) {
534535
$this->cache->deleteAll();
535536
}
536537

537538
$tdbmDaoGenerator = new TDBMDaoGenerator($this->configuration, $this->tdbmSchemaAnalyzer);
538-
$tdbmDaoGenerator->generateAllDaosAndBeans();
539+
$tdbmDaoGenerator->generateAllDaosAndBeans($fromLock);
539540
}
540541

541542
/**

src/Utils/ImmutableCaster.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
namespace TheCodingMachine\TDBM\Utils;
4+
5+
use Doctrine\DBAL\Schema\Column;
6+
use Doctrine\DBAL\Schema\Schema;
7+
use Doctrine\DBAL\Types\Type;
8+
9+
class ImmutableCaster
10+
{
11+
public static function castSchemaToImmutable(Schema $schema): void
12+
{
13+
foreach ($schema->getTables() as $table) {
14+
foreach ($table->getColumns() as $column) {
15+
self::toImmutableType($column);
16+
}
17+
}
18+
}
19+
20+
/**
21+
* Changes the type of a column to an immutable date type if the type is a date.
22+
* This is needed because by default, when reading a Schema, Doctrine assumes a mutable datetime.
23+
*/
24+
private static function toImmutableType(Column $column): void
25+
{
26+
$mapping = [
27+
Type::DATE => Type::DATE_IMMUTABLE,
28+
Type::DATETIME => Type::DATETIME_IMMUTABLE,
29+
Type::DATETIMETZ => Type::DATETIMETZ_IMMUTABLE,
30+
Type::TIME => Type::TIME_IMMUTABLE
31+
];
32+
33+
$typeName = $column->getType()->getName();
34+
if (isset($mapping[$typeName])) {
35+
$column->setType(Type::getType($mapping[$typeName]));
36+
}
37+
}
38+
}

0 commit comments

Comments
 (0)