daikon-cqrs/dbal

View on GitHub
src/Migration/Migration.php

Summary

Maintainability
A
0 mins
Test Coverage
F
0%
<?php declare(strict_types=1);
/**
 * This file is part of the daikon-cqrs/dbal project.
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Daikon\Dbal\Migration;

use Daikon\Dbal\Connector\ConnectorInterface;
use Daikon\Interop\Assertion;
use Daikon\Interop\RuntimeException;
use DateTimeImmutable;
use ReflectionClass;

abstract class Migration implements MigrationInterface
{
    private ?DateTimeImmutable $executedAt;

    protected ConnectorInterface $connector;

    abstract protected function up(): void;

    abstract protected function down(): void;

    public function __construct(DateTimeImmutable $executedAt = null)
    {
        $this->executedAt = $executedAt;
    }

    public function __invoke(ConnectorInterface $connector, string $direction = MigrationInterface::MIGRATE_UP): void
    {
        $this->connector = $connector;

        if ($direction === MigrationInterface::MIGRATE_DOWN) {
            Assertion::true($this->isReversible(), 'Migration cannot be reversed.');
            Assertion::true($this->hasExecuted(), 'Migration has not previously been executed.');
            $this->down();
            $this->executedAt = null;
        } else {
            Assertion::false($this->hasExecuted(), 'Migration has already been executed.');
            $this->up();
            $this->executedAt = new DateTimeImmutable;
        }
    }

    public function getName(): string
    {
        $shortName = (new ReflectionClass(static::class))->getShortName();
        if (!preg_match('/^(?<name>.+?)\d+$/', $shortName, $matches)) {
            throw new RuntimeException('Unexpected migration name in '.$shortName);
        }
        return $matches['name'];
    }

    public function getVersion(): int
    {
        $shortName= (new ReflectionClass(static::class))->getShortName();
        if (!preg_match('/(?<version>\d{14})$/', $shortName, $matches)) {
            throw new RuntimeException('Unexpected migration version in '.$shortName);
        }
        return intval($matches['version']);
    }

    public function hasExecuted(): bool
    {
        return $this->executedAt instanceof DateTimeImmutable;
    }

    public function toNative(): array
    {
        $state = [
            '@type' => static::class,
            'name' => $this->getName(),
            'version' => $this->getVersion(),
            'description' => $this->getDescription()
        ];

        if ($this->hasExecuted()) {
            $state['executedAt']  = $this->executedAt->format('c');
        }

        return $state;
    }
}