caisse-bliss/vendor/doctrine/migrations/lib/Doctrine/Migrations/DbalMigrator.php

164 lines
5.0 KiB
PHP

<?php
declare(strict_types=1);
namespace Doctrine\Migrations;
use Doctrine\DBAL\Connection;
use Doctrine\Migrations\Exception\MigrationConfigurationConflict;
use Doctrine\Migrations\Metadata\MigrationPlanList;
use Doctrine\Migrations\Query\Query;
use Doctrine\Migrations\Tools\BytesFormatter;
use Doctrine\Migrations\Tools\TransactionHelper;
use Doctrine\Migrations\Version\Executor;
use Psr\Log\LoggerInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Stopwatch\StopwatchEvent;
use Throwable;
use function count;
use const COUNT_RECURSIVE;
/**
* The DbalMigrator class is responsible for generating and executing the SQL for a migration.
*
* @internal
*/
class DbalMigrator implements Migrator
{
private Stopwatch $stopwatch;
private LoggerInterface $logger;
private Executor $executor;
private Connection $connection;
private EventDispatcher $dispatcher;
public function __construct(
Connection $connection,
EventDispatcher $dispatcher,
Executor $executor,
LoggerInterface $logger,
Stopwatch $stopwatch
) {
$this->stopwatch = $stopwatch;
$this->logger = $logger;
$this->executor = $executor;
$this->connection = $connection;
$this->dispatcher = $dispatcher;
}
/**
* @return array<string, Query[]>
*/
private function executeMigrations(
MigrationPlanList $migrationsPlan,
MigratorConfiguration $migratorConfiguration
): array {
$allOrNothing = $migratorConfiguration->isAllOrNothing();
if ($allOrNothing) {
$this->assertAllMigrationsAreTransactional($migrationsPlan);
$this->connection->beginTransaction();
}
try {
$this->dispatcher->dispatchMigrationEvent(Events::onMigrationsMigrating, $migrationsPlan, $migratorConfiguration);
$sql = $this->executePlan($migrationsPlan, $migratorConfiguration);
$this->dispatcher->dispatchMigrationEvent(Events::onMigrationsMigrated, $migrationsPlan, $migratorConfiguration);
} catch (Throwable $e) {
if ($allOrNothing) {
TransactionHelper::rollbackIfInTransaction($this->connection);
}
throw $e;
}
if ($allOrNothing) {
TransactionHelper::commitIfInTransaction($this->connection);
}
return $sql;
}
private function assertAllMigrationsAreTransactional(MigrationPlanList $migrationsPlan): void
{
foreach ($migrationsPlan->getItems() as $plan) {
if (! $plan->getMigration()->isTransactional()) {
throw MigrationConfigurationConflict::migrationIsNotTransactional($plan->getMigration());
}
}
}
/**
* @return array<string, Query[]>
*/
private function executePlan(MigrationPlanList $migrationsPlan, MigratorConfiguration $migratorConfiguration): array
{
$sql = [];
$time = 0;
foreach ($migrationsPlan->getItems() as $plan) {
$versionExecutionResult = $this->executor->execute($plan, $migratorConfiguration);
// capture the to Schema for the migration so we have the ability to use
// it as the from Schema for the next migration when we are running a dry run
// $toSchema may be null in the case of skipped migrations
if (! $versionExecutionResult->isSkipped()) {
$migratorConfiguration->setFromSchema($versionExecutionResult->getToSchema());
}
$sql[(string) $plan->getVersion()] = $versionExecutionResult->getSql();
$time += $versionExecutionResult->getTime();
}
return $sql;
}
/**
* @param array<string, Query[]> $sql
*/
private function endMigrations(
StopwatchEvent $stopwatchEvent,
MigrationPlanList $migrationsPlan,
array $sql
): void {
$stopwatchEvent->stop();
$this->logger->notice(
'finished in {duration}ms, used {memory} memory, {migrations_count} migrations executed, {queries_count} sql queries',
[
'duration' => $stopwatchEvent->getDuration(),
'memory' => BytesFormatter::formatBytes($stopwatchEvent->getMemory()),
'migrations_count' => count($migrationsPlan),
'queries_count' => count($sql, COUNT_RECURSIVE) - count($sql),
]
);
}
/**
* {@inheritDoc}
*/
public function migrate(MigrationPlanList $migrationsPlan, MigratorConfiguration $migratorConfiguration): array
{
if (count($migrationsPlan) === 0) {
$this->logger->notice('No migrations to execute.');
return [];
}
$stopwatchEvent = $this->stopwatch->start('migrate');
$sql = $this->executeMigrations($migrationsPlan, $migratorConfiguration);
$this->endMigrations($stopwatchEvent, $migrationsPlan, $sql);
return $sql;
}
}