Skip to content

Commit

Permalink
Merge pull request #171 from Kharhamel/lockFile
Browse files Browse the repository at this point in the history
added a schema lock file to tdbm
  • Loading branch information
moufmouf authored Sep 30, 2019
2 parents 8120b7d + d8a7b25 commit 3b7d130
Show file tree
Hide file tree
Showing 18 changed files with 203 additions and 89 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,5 @@ vendor/*
.phpunit.result.cache
/phpbench.sh
/xdebug/
.php_cs.cache
tdbm.lock.yml
3 changes: 2 additions & 1 deletion composer-require-checker.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@
"ext-PDO": "*",
"ext-json": "*",
"ext-hash": "*",
"ext-filter": "*"
"ext-filter": "*",
"brain-diminished/schema-version-control": "^1.0.2"
},
"require-dev" : {
"phpunit/phpunit": "^7.4.4 || ^8.0.0",
Expand Down
5 changes: 5 additions & 0 deletions src/Commands/AlteredConfiguration.php
Original file line number Diff line number Diff line change
Expand Up @@ -146,4 +146,9 @@ public function getAnnotationParser(): AnnotationParser
{
return $this->configuration->getAnnotationParser();
}

public function getLockFilePath(): string
{
return $this->configuration->getLockFilePath();
}
}
11 changes: 10 additions & 1 deletion src/Commands/GenerateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -30,6 +31,13 @@ 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
)
;
}

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

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

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

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

Expand All @@ -54,7 +63,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');
}
Expand Down
20 changes: 19 additions & 1 deletion src/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -71,6 +72,7 @@ class Configuration implements ConfigurationInterface
* @var AnnotationParser
*/
private $annotationParser;
private $lockFilePath;

/**
* @param string $beanNamespace The namespace hosting the beans
Expand All @@ -84,6 +86,7 @@ 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(
Expand All @@ -97,7 +100,8 @@ public function __construct(
array $generatorListeners = [],
AnnotationParser $annotationParser = null,
array $codeGeneratorListeners = [],
string $resultIteratorNamespace = null
string $resultIteratorNamespace = null,
string $lockFilePath = null
) {
$this->beanNamespace = rtrim($beanNamespace, '\\');
$this->daoNamespace = rtrim($daoNamespace, '\\');
Expand Down Expand Up @@ -125,6 +129,7 @@ public function __construct(
$this->annotationParser = $annotationParser ?: AnnotationParser::buildWithDefaultAnnotations([]);
$this->codeGeneratorListener = new CodeGeneratorEventDispatcher($codeGeneratorListeners);
$this->namingStrategy = $namingStrategy ?: new DefaultNamingStrategy($this->annotationParser, $this->connection->getSchemaManager());
$this->lockFilePath = $lockFilePath;
}

/**
Expand Down Expand Up @@ -243,4 +248,17 @@ public function getAnnotationParser(): AnnotationParser
{
return $this->annotationParser;
}

/**
* @internal
*/
public static function getDefaultLockFilePath(): string
{
return RootProjectLocator::getRootLocationPath().'tdbm.lock.yml';
}

public function getLockFilePath(): string
{
return $this->lockFilePath ?: self::getDefaultLockFilePath();
}
}
2 changes: 2 additions & 0 deletions src/ConfigurationInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,6 @@ public function getPathFinder(): PathFinderInterface;
* @return AnnotationParser
*/
public function getAnnotationParser(): AnnotationParser;

public function getLockFilePath(): string;
}
62 changes: 28 additions & 34 deletions src/TDBMSchemaAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -12,12 +13,14 @@
use Doctrine\DBAL\Types\DateType;
use Doctrine\DBAL\Types\Type;
use Mouf\Database\SchemaAnalyzer\SchemaAnalyzer;
use TheCodingMachine\TDBM\Utils\ImmutableCaster;

/**
* This class is used to analyze the schema and return valuable information / hints.
*/
class TDBMSchemaAnalyzer
{
private $lockFilePath;
private $connection;

/**
Expand All @@ -41,16 +44,24 @@ class TDBMSchemaAnalyzer
private $schemaAnalyzer;

/**
* @param Connection $connection The DBAL DB connection to use
* @param Cache $cache A cache service to be used
* @var SchemaVersionControlService
*/
private $schemaVersionControlService;

/**
* @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->lockFilePath = $lockFilePath;
$this->schemaVersionControlService = new SchemaVersionControlService($this->connection, $this->lockFilePath);
}

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

public function getLockFilePath(): string
{
return $this->lockFilePath;
}

/**
* 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($this->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);
}
}

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();
\chmod($this->getLockFilePath(), 0664);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions src/TDBMService.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -527,15 +528,15 @@ 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) {
$this->cache->deleteAll();
}

$tdbmDaoGenerator = new TDBMDaoGenerator($this->configuration, $this->tdbmSchemaAnalyzer);
$tdbmDaoGenerator->generateAllDaosAndBeans();
$tdbmDaoGenerator->generateAllDaosAndBeans($fromLock);
}

/**
Expand Down
38 changes: 38 additions & 0 deletions src/Utils/ImmutableCaster.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

namespace TheCodingMachine\TDBM\Utils;

use Doctrine\DBAL\Schema\Column;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Type;

class ImmutableCaster
{
public static function castSchemaToImmutable(Schema $schema): void
{
foreach ($schema->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]));
}
}
}
13 changes: 13 additions & 0 deletions src/Utils/RootProjectLocator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php


namespace TheCodingMachine\TDBM\Utils;

class RootProjectLocator
{
public static function getRootLocationPath(): string
{
$reflection = new \ReflectionClass(\Composer\Autoload\ClassLoader::class);
return dirname($reflection->getFileName(), 3).'/';
}
}
18 changes: 8 additions & 10 deletions src/Utils/TDBMDaoGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,6 @@
*/
class TDBMDaoGenerator
{
/**
* @var Schema
*/
private $schema;

/**
* @var TDBMSchemaAnalyzer
*/
Expand Down Expand Up @@ -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();
Expand All @@ -77,11 +71,15 @@ public function __construct(ConfigurationInterface $configuration, TDBMSchemaAna
*
* @throws TDBMException
*/
public function generateAllDaosAndBeans(): void
public function generateAllDaosAndBeans(bool $fromLock = false): void
{
// TODO: check that no class name ends with "Base". Otherwise, there will be name clash.
if (!$fromLock) {
$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);
Expand All @@ -97,7 +95,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);
}
Expand Down
Loading

0 comments on commit 3b7d130

Please sign in to comment.