welcome back to dyb-tech
This commit is contained in:
+25
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeZone;
|
||||
|
||||
/*final */class ClassNameGenerator
|
||||
{
|
||||
public const VERSION_FORMAT = 'YmdHis';
|
||||
|
||||
public function generateClassName(string $namespace): string
|
||||
{
|
||||
return $namespace . '\\Version' . $this->generateVersionNumber();
|
||||
}
|
||||
|
||||
private function generateVersionNumber(): string
|
||||
{
|
||||
$now = new DateTimeImmutable('now', new DateTimeZone('UTC'));
|
||||
|
||||
return $now->format(self::VERSION_FORMAT);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator;
|
||||
|
||||
use DateTimeImmutable;
|
||||
use DateTimeInterface;
|
||||
use Doctrine\Migrations\Query\Query;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
/**
|
||||
* The ConcatenationFileBuilder class is responsible for building a migration SQL file from an array of queries per version.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class ConcatenationFileBuilder implements FileBuilder
|
||||
{
|
||||
/** @param array<string,Query[]> $queriesByVersion */
|
||||
public function buildMigrationFile(
|
||||
array $queriesByVersion,
|
||||
string $direction,
|
||||
DateTimeInterface|null $now = null,
|
||||
): string {
|
||||
$now ??= new DateTimeImmutable();
|
||||
$string = sprintf("-- Doctrine Migration File Generated on %s\n", $now->format('Y-m-d H:i:s'));
|
||||
|
||||
foreach ($queriesByVersion as $version => $queries) {
|
||||
$string .= "\n-- Version " . $version . "\n";
|
||||
|
||||
foreach ($queries as $query) {
|
||||
$string .= $query->getStatement() . ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator;
|
||||
|
||||
use Doctrine\DBAL\Configuration as DBALConfiguration;
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\DBAL\Schema\AbstractAsset;
|
||||
use Doctrine\DBAL\Schema\AbstractSchemaManager;
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\Generator\Exception\NoChangesDetected;
|
||||
use Doctrine\Migrations\Provider\SchemaProvider;
|
||||
|
||||
use function preg_match;
|
||||
use function strpos;
|
||||
use function substr;
|
||||
|
||||
/**
|
||||
* The DiffGenerator class is responsible for comparing two Doctrine\DBAL\Schema\Schema instances and generating a
|
||||
* migration class with the SQL statements needed to migrate from one schema to the other.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class DiffGenerator
|
||||
{
|
||||
/** @param AbstractSchemaManager<AbstractPlatform> $schemaManager */
|
||||
public function __construct(
|
||||
private readonly DBALConfiguration $dbalConfiguration,
|
||||
private readonly AbstractSchemaManager $schemaManager,
|
||||
private readonly SchemaProvider $schemaProvider,
|
||||
private readonly AbstractPlatform $platform,
|
||||
private readonly Generator $migrationGenerator,
|
||||
private readonly SqlGenerator $migrationSqlGenerator,
|
||||
private readonly SchemaProvider $emptySchemaProvider,
|
||||
) {
|
||||
}
|
||||
|
||||
/** @throws NoChangesDetected */
|
||||
public function generate(
|
||||
string $fqcn,
|
||||
string|null $filterExpression,
|
||||
bool $formatted = false,
|
||||
int $lineLength = 120,
|
||||
bool $checkDbPlatform = true,
|
||||
bool $fromEmptySchema = false,
|
||||
): string {
|
||||
if ($filterExpression !== null) {
|
||||
$this->dbalConfiguration->setSchemaAssetsFilter(
|
||||
static function ($assetName) use ($filterExpression) {
|
||||
if ($assetName instanceof AbstractAsset) {
|
||||
$assetName = $assetName->getName();
|
||||
}
|
||||
|
||||
return preg_match($filterExpression, $assetName);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
$fromSchema = $fromEmptySchema
|
||||
? $this->createEmptySchema()
|
||||
: $this->createFromSchema();
|
||||
|
||||
$toSchema = $this->createToSchema();
|
||||
|
||||
$comparator = $this->schemaManager->createComparator();
|
||||
|
||||
$upSql = $this->platform->getAlterSchemaSQL($comparator->compareSchemas($fromSchema, $toSchema));
|
||||
|
||||
$up = $this->migrationSqlGenerator->generate(
|
||||
$upSql,
|
||||
$formatted,
|
||||
$lineLength,
|
||||
$checkDbPlatform,
|
||||
);
|
||||
|
||||
$downSql = $this->platform->getAlterSchemaSQL($comparator->compareSchemas($toSchema, $fromSchema));
|
||||
|
||||
$down = $this->migrationSqlGenerator->generate(
|
||||
$downSql,
|
||||
$formatted,
|
||||
$lineLength,
|
||||
$checkDbPlatform,
|
||||
);
|
||||
|
||||
if ($up === '' && $down === '') {
|
||||
throw NoChangesDetected::new();
|
||||
}
|
||||
|
||||
return $this->migrationGenerator->generateMigration(
|
||||
$fqcn,
|
||||
$up,
|
||||
$down,
|
||||
);
|
||||
}
|
||||
|
||||
private function createEmptySchema(): Schema
|
||||
{
|
||||
return $this->emptySchemaProvider->createSchema();
|
||||
}
|
||||
|
||||
private function createFromSchema(): Schema
|
||||
{
|
||||
return $this->schemaManager->introspectSchema();
|
||||
}
|
||||
|
||||
private function createToSchema(): Schema
|
||||
{
|
||||
$toSchema = $this->schemaProvider->createSchema();
|
||||
|
||||
$schemaAssetsFilter = $this->dbalConfiguration->getSchemaAssetsFilter();
|
||||
|
||||
if ($schemaAssetsFilter !== null) {
|
||||
foreach ($toSchema->getTables() as $table) {
|
||||
$tableName = $table->getName();
|
||||
|
||||
if ($schemaAssetsFilter($this->resolveTableName($tableName))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$toSchema->dropTable($tableName);
|
||||
}
|
||||
}
|
||||
|
||||
return $toSchema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a table name from its fully qualified name. The `$name` argument
|
||||
* comes from Doctrine\DBAL\Schema\Table#getName which can sometimes return
|
||||
* a namespaced name with the form `{namespace}.{tableName}`. This extracts
|
||||
* the table name from that.
|
||||
*/
|
||||
private function resolveTableName(string $name): string
|
||||
{
|
||||
$pos = strpos($name, '.');
|
||||
|
||||
return $pos === false ? $name : substr($name, $pos + 1);
|
||||
}
|
||||
}
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator\Exception;
|
||||
|
||||
use Doctrine\Migrations\Exception\MigrationException;
|
||||
|
||||
interface GeneratorException extends MigrationException
|
||||
{
|
||||
}
|
||||
Vendored
+27
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator\Exception;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function sprintf;
|
||||
|
||||
final class InvalidTemplateSpecified extends InvalidArgumentException implements GeneratorException
|
||||
{
|
||||
public static function notFoundOrNotReadable(string $path): self
|
||||
{
|
||||
return new self(sprintf('The specified template "%s" cannot be found or is not readable.', $path));
|
||||
}
|
||||
|
||||
public static function notReadable(string $path): self
|
||||
{
|
||||
return new self(sprintf('The specified template "%s" could not be read.', $path));
|
||||
}
|
||||
|
||||
public static function empty(string $path): self
|
||||
{
|
||||
return new self(sprintf('The specified template "%s" is empty.', $path));
|
||||
}
|
||||
}
|
||||
Vendored
+15
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
final class NoChangesDetected extends RuntimeException implements GeneratorException
|
||||
{
|
||||
public static function new(): self
|
||||
{
|
||||
return new self('No changes detected in your mapping information.');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator;
|
||||
|
||||
use DateTimeInterface;
|
||||
use Doctrine\Migrations\Query\Query;
|
||||
|
||||
/**
|
||||
* The ConcatenationFileBuilder class is responsible for building a migration SQL file from an array of queries per version.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
interface FileBuilder
|
||||
{
|
||||
/** @param array<string,Query[]> $queriesByVersion */
|
||||
public function buildMigrationFile(array $queriesByVersion, string $direction, DateTimeInterface|null $now = null): string;
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator;
|
||||
|
||||
use Doctrine\Migrations\Configuration\Configuration;
|
||||
use Doctrine\Migrations\Generator\Exception\InvalidTemplateSpecified;
|
||||
use Doctrine\Migrations\Tools\Console\Helper\MigrationDirectoryHelper;
|
||||
use InvalidArgumentException;
|
||||
|
||||
use function explode;
|
||||
use function file_get_contents;
|
||||
use function file_put_contents;
|
||||
use function implode;
|
||||
use function is_file;
|
||||
use function is_readable;
|
||||
use function preg_match;
|
||||
use function preg_replace;
|
||||
use function sprintf;
|
||||
use function strtr;
|
||||
use function trim;
|
||||
|
||||
/**
|
||||
* The Generator class is responsible for generating a migration class.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class Generator
|
||||
{
|
||||
private const MIGRATION_TEMPLATE = <<<'TEMPLATE'
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace <namespace>;
|
||||
|
||||
use Doctrine\DBAL\Schema\Schema;
|
||||
use Doctrine\Migrations\AbstractMigration;
|
||||
|
||||
/**
|
||||
* Auto-generated Migration: Please modify to your needs!
|
||||
*/
|
||||
final class <className> extends AbstractMigration
|
||||
{
|
||||
public function getDescription(): string
|
||||
{
|
||||
return '';
|
||||
}
|
||||
|
||||
public function up(Schema $schema): void
|
||||
{
|
||||
// this up() migration is auto-generated, please modify it to your needs
|
||||
<up>
|
||||
}
|
||||
|
||||
public function down(Schema $schema): void
|
||||
{
|
||||
// this down() migration is auto-generated, please modify it to your needs
|
||||
<down>
|
||||
}<override>
|
||||
}
|
||||
|
||||
TEMPLATE;
|
||||
|
||||
private string|null $template = null;
|
||||
|
||||
public function __construct(private readonly Configuration $configuration)
|
||||
{
|
||||
}
|
||||
|
||||
public function generateMigration(
|
||||
string $fqcn,
|
||||
string|null $up = null,
|
||||
string|null $down = null,
|
||||
): string {
|
||||
$mch = [];
|
||||
if (preg_match('~(.*)\\\\([^\\\\]+)~', $fqcn, $mch) === 0) {
|
||||
throw new InvalidArgumentException(sprintf('Invalid FQCN'));
|
||||
}
|
||||
|
||||
[$fqcn, $namespace, $className] = $mch;
|
||||
|
||||
$dirs = $this->configuration->getMigrationDirectories();
|
||||
if (! isset($dirs[$namespace])) {
|
||||
throw new InvalidArgumentException(sprintf('Path not defined for the namespace "%s"', $namespace));
|
||||
}
|
||||
|
||||
$dir = $dirs[$namespace];
|
||||
|
||||
$replacements = [
|
||||
'<namespace>' => $namespace,
|
||||
'<className>' => $className,
|
||||
'<up>' => $up !== null ? ' ' . implode("\n ", explode("\n", $up)) : null,
|
||||
'<down>' => $down !== null ? ' ' . implode("\n ", explode("\n", $down)) : null,
|
||||
'<override>' => $this->configuration->isTransactional() ? '' : <<<'METHOD'
|
||||
|
||||
|
||||
public function isTransactional(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
METHOD
|
||||
,
|
||||
];
|
||||
|
||||
$code = strtr($this->getTemplate(), $replacements);
|
||||
$code = preg_replace('/^ +$/m', '', $code);
|
||||
|
||||
$directoryHelper = new MigrationDirectoryHelper();
|
||||
$dir = $directoryHelper->getMigrationDirectory($this->configuration, $dir);
|
||||
$path = $dir . '/' . $className . '.php';
|
||||
|
||||
file_put_contents($path, $code);
|
||||
|
||||
return $path;
|
||||
}
|
||||
|
||||
private function getTemplate(): string
|
||||
{
|
||||
if ($this->template === null) {
|
||||
$this->template = $this->loadCustomTemplate();
|
||||
|
||||
if ($this->template === null) {
|
||||
$this->template = self::MIGRATION_TEMPLATE;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
/** @throws InvalidTemplateSpecified */
|
||||
private function loadCustomTemplate(): string|null
|
||||
{
|
||||
$customTemplate = $this->configuration->getCustomTemplate();
|
||||
|
||||
if ($customTemplate === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (! is_file($customTemplate) || ! is_readable($customTemplate)) {
|
||||
throw InvalidTemplateSpecified::notFoundOrNotReadable($customTemplate);
|
||||
}
|
||||
|
||||
$content = file_get_contents($customTemplate);
|
||||
|
||||
if ($content === false) {
|
||||
throw InvalidTemplateSpecified::notReadable($customTemplate);
|
||||
}
|
||||
|
||||
if (trim($content) === '') {
|
||||
throw InvalidTemplateSpecified::empty($customTemplate);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Doctrine\Migrations\Generator;
|
||||
|
||||
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||
use Doctrine\Migrations\Configuration\Configuration;
|
||||
use Doctrine\Migrations\Metadata\Storage\TableMetadataStorageConfiguration;
|
||||
use Doctrine\SqlFormatter\NullHighlighter;
|
||||
use Doctrine\SqlFormatter\SqlFormatter;
|
||||
|
||||
use function array_unshift;
|
||||
use function count;
|
||||
use function get_class;
|
||||
use function implode;
|
||||
use function sprintf;
|
||||
use function stripos;
|
||||
use function strlen;
|
||||
use function var_export;
|
||||
|
||||
/**
|
||||
* The SqlGenerator class is responsible for generating the body of the up() and down() methods for a migration
|
||||
* from an array of SQL queries.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
class SqlGenerator
|
||||
{
|
||||
public function __construct(
|
||||
private readonly Configuration $configuration,
|
||||
private readonly AbstractPlatform $platform,
|
||||
) {
|
||||
}
|
||||
|
||||
/** @param string[] $sql */
|
||||
public function generate(
|
||||
array $sql,
|
||||
bool $formatted = false,
|
||||
int $lineLength = 120,
|
||||
bool $checkDbPlatform = true,
|
||||
): string {
|
||||
$code = [];
|
||||
|
||||
$storageConfiguration = $this->configuration->getMetadataStorageConfiguration();
|
||||
foreach ($sql as $query) {
|
||||
if (
|
||||
$storageConfiguration instanceof TableMetadataStorageConfiguration
|
||||
&& stripos($query, $storageConfiguration->getTableName()) !== false
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($formatted) {
|
||||
$maxLength = $lineLength - 18 - 8; // max - php code length - indentation
|
||||
|
||||
if (strlen($query) > $maxLength) {
|
||||
$query = (new SqlFormatter(new NullHighlighter()))->format($query);
|
||||
}
|
||||
}
|
||||
|
||||
$code[] = sprintf('$this->addSql(%s);', var_export($query, true));
|
||||
}
|
||||
|
||||
if (count($code) !== 0 && $checkDbPlatform && $this->configuration->isDatabasePlatformChecked()) {
|
||||
$currentPlatform = '\\' . get_class($this->platform);
|
||||
|
||||
array_unshift(
|
||||
$code,
|
||||
sprintf(
|
||||
<<<'PHP'
|
||||
$this->abortIf(
|
||||
!$this->connection->getDatabasePlatform() instanceof %s,
|
||||
"Migration can only be executed safely on '%s'."
|
||||
);
|
||||
PHP
|
||||
,
|
||||
$currentPlatform,
|
||||
$currentPlatform,
|
||||
),
|
||||
'',
|
||||
);
|
||||
}
|
||||
|
||||
return implode("\n", $code);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user