welcome back to dyb-tech

This commit is contained in:
Daniel Guzman
2024-05-18 02:28:01 +02:00
parent 9513cdba09
commit 9f30bc98c7
6149 changed files with 668407 additions and 0 deletions
@@ -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);
}
}
@@ -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;
}
}
@@ -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);
}
}
@@ -0,0 +1,11 @@
<?php
declare(strict_types=1);
namespace Doctrine\Migrations\Generator\Exception;
use Doctrine\Migrations\Exception\MigrationException;
interface GeneratorException extends MigrationException
{
}
@@ -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));
}
}
@@ -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;
}
}
@@ -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);
}
}