Skip to content
Snippets Groups Projects
Commit 0fae43bc authored by Laurent Lecluse's avatar Laurent Lecluse
Browse files

Commandes retravaillées

MigrationManager en place
Polish
parent 9c5806cf
Branches
Tags
No related merge requests found
......@@ -35,7 +35,7 @@ return [
],
'migration' => [
'dir' => null,
// array des classes ou services utilisés pour la migration [index => classe ou service, ...]
],
'id_column' => 'id',
......
......@@ -398,7 +398,8 @@ class Bdd
public function migration(): MigrationManager
{
if (!isset($this->migration)) {
$this->migration = new MigrationManager($this);
$this->migration = new MigrationManager();
$this->migration->setBdd($this);
$this->migration->setOptions($this->getOption(self::OPTION_MIGRATION, []));
}
......@@ -667,7 +668,6 @@ class Bdd
}
}
}
$this->compilerTout();
}
......@@ -685,9 +685,6 @@ class Bdd
$ddl = Ddl::normalize($ddl)->filter($filters);
}
$this->migration()->init($ddl, $filters);
$this->migration()->migration('before');
foreach ($this->changements as $changement => $label) {
[$ddlName, $action] = explode('.', $changement);
......@@ -718,13 +715,11 @@ class Bdd
}
}
$this->logEnd();
$this->compilerTout();
$this->migration()->migration('after');
}
public function drop(DdlFilters|array $filters = []): void
public function drop(DdlFilters|array $filters = []): self
{
$filters = DdlFilters::normalize($filters);
......@@ -753,7 +748,125 @@ class Bdd
}
}
}
$this->logEnd();
return $this;
}
public function clear(): self
{
$this->logTitle('Vidage complet de la base de données');
try {
$this->drop();
} catch (\Throwable $e) {
$this->logError($e);
}
$this->logSuccess('Base de données vidée complètement');
return $this;
}
public function install(): self
{
$this->logTitle('Installation de la base de données');
// Mise en place des objets
try {
$ddl = $this->getRefDdl();
$this->create($ddl);
$this->logSuccess('Objets en place');
} catch (\Throwable $e) {
$this->logError($e);
}
if (!empty($this->data()->getSources())) {
// Installation des données
$this->logTitle('Insertion du jeu de données données');
try {
$this->data()->run(DataManager::ACTION_INSTALL);
$this->logSuccess('Données écrites');
} catch (\Throwable $e) {
$this->logError($e);
}
}
return $this;
}
public function update(): self
{
$this->logTitle('Mise à jour de la base de données');
$ddl = $this->getRefDdl();
$filters = $this->getFiltersForUpdateBdd($ddl);
// Initialisation et lancement de la pré-migration
$migrationManager = $this->migration();
$migrationManager->init($ddl, $filters);
$migrationManager->run(MigrationManager::ACTION_BEFORE);
try {
$this->alter($ddl, $filters, true);
$this->logSuccess('Objets à jour');
} catch (\Throwable $e) {
$this->logError($e);
}
// On compile tout
$this->compilerTout();
// Mise à jour des séquences
$this->majSequences($ddl);
// Mise à jour des données
$this->updateData();
// Post-migration
$migrationManager->run(MigrationManager::ACTION_AFTER);
return $this;
}
public function updateData(): self
{
if (!empty($this->data()->getSources())) {
$this->logTitle('Contrôle et mise à jour des données');
try {
$this->data()->run(DataManager::ACTION_UPDATE);
$this->logSuccess('Données à jour');
} catch (\Throwable $e) {
$this->logError($e);
}
}
return $this;
}
public function updateDdl(): self
{
$this->logTitle('Génération de la DDL à partir de la base de données');
try {
$filters = $bdd->getFiltersForUpdateDdl();
$ddl = $bdd->getDdl($filters);
$ddl->saveToDir();
$this->logSuccess('DDL mise à jour');
} catch (\Throwable $e) {
$this->logError($e);
}
return $this;
}
......@@ -923,8 +1036,11 @@ class Bdd
public function copy(Bdd $source, DdlFilters|array $filters = [], array $fncs = []): self
public function copy(Bdd|string $source, DdlFilters|array $filters = [], array $fncs = []): self
{
if (is_string($source)) {
$source = $this->getBdd($source);
}
if ($this->getLogger() && !$source->getLogger()) {
$source->setLogger($this->getLogger());
}
......@@ -978,6 +1094,18 @@ class Bdd
public function copyTo(string|Bdd $destination, DdlFilters|array $filters = [], array $fncs = []): self
{
if (is_string($destination)) {
$destination = $this->getBdd($destination);
}
$destination->copy($this, $filters, $fncs);
return $this;
}
public function save(string $filename, DdlFilters|array $filters = [], array $fncs = []): void
{
$this->logBegin("Sauvegarde de la base de données");
......
......@@ -22,6 +22,11 @@ class BddFactory
*/
public function __invoke(ContainerInterface $container, $requestedName, $options = null): Bdd
{
if (Bdd::class == $requestedName){
$configKey = 'unicaen-bddadmin';
}else{
$configKey = $requestedName;
}
$config = $container->get('config')['unicaen-bddadmin'];
$bdd = new Bdd($this->prepareConfig($config, $container));
......@@ -31,8 +36,9 @@ class BddFactory
public function prepareConfig(array $config, ContainerInterface $container): array
protected function prepareConfig(array $config, ContainerInterface $container): array
{
// Chargement des sources de données depuis le ServiceManager si nécessaire
if (isset($config[Bdd::OPTION_DATA][DataManager::OPTION_SOURCES])){
$sources = &$config[Bdd::OPTION_DATA][DataManager::OPTION_SOURCES];
foreach( $sources as $index => $source){
......@@ -42,6 +48,16 @@ class BddFactory
}
}
// Chargement des scripts de migration depuis le ServiceManager si nécessaire
if (isset($config[Bdd::OPTION_MIGRATION])){
$sources = &$config[Bdd::OPTION_MIGRATION];
foreach( $sources as $index => $source){
if ($container->has($source)){
$sources[$index] = $container->get($source);
}
}
}
return $config;
}
}
\ No newline at end of file
......@@ -24,14 +24,7 @@ class ClearBddCommand extends Command
$io = new SymfonyStyle($input, $output);
$bdd = $this->getBdd()->setLogger($io);
$io->title('Vidage complet de la base de données');
try {
$bdd->drop();
$io->success('Base de données vidée complètement');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
return Command::SUCCESS;
}
......
......@@ -24,27 +24,7 @@ class InstallBddCommand extends Command
$io = new SymfonyStyle($input, $output);
$bdd = $this->getBdd()->setLogger($io);
$io->title('Installation de la base de données');
// Mise en place des objets
try {
$ddl = $bdd->getRefDdl();
$bdd->create($ddl);
$io->success('Objets en place');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
if (!empty($bdd->data()->getSources())) {
// Installation des données
$io->title('Insertion du jeu de données données');
try {
$bdd->data()->run(DataManager::ACTION_INSTALL);
$io->success('Données écrites');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
}
$bdd->install();
return Command::SUCCESS;
}
......
......@@ -9,6 +9,7 @@ use Symfony\Component\Console\Style\SymfonyStyle;
use Unicaen\BddAdmin\BddAwareTrait;
use Unicaen\BddAdmin\Data\DataManager;
use Unicaen\BddAdmin\Ddl\Ddl;
use Unicaen\BddAdmin\Migration\MigrationManager;
/**
* Description of UpdateBddCommand
......@@ -24,42 +25,7 @@ class UpdateBddCommand extends Command
$io = new SymfonyStyle($input, $output);
$bdd = $this->getBdd()->setLogger($io);
$io->title('Mise à jour de la base de données');
$ddl = $bdd->getRefDdl();
$filters = $bdd->getFiltersForUpdateBdd($ddl);
// Initialisation et lancement de la pré-migration
//$mm = new MigrationManager($oa, $ddl, $filters);
//$mm->migration('before');
try {
$bdd->alter($ddl, $filters, true);
$io->success('Objets à jour');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
// Mise à jour des séquences
$bdd->majSequences($ddl);
// Mise à jour des données
if (!empty($bdd->data()->getSources())) {
$io->title('Contrôle et mise à jour des données');
try {
$bdd->data()->run(DataManager::ACTION_UPDATE);
$io->success('Données à jour');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
}
// Post-migration
//$mm->migration('after');
$bdd->update();
return Command::SUCCESS;
}
......
......@@ -23,18 +23,7 @@ class UpdateDataCommand extends Command
$io = new SymfonyStyle($input, $output);
$bdd = $this->getBdd()->setLogger($io);
// Mise à jour des données
if (!empty($bdd->data()->getSources())) {
$io->title('Contrôle et mise à jour des données');
try {
$bdd->data()->run('update');
$io->success('Données à jour');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
}else{
$io->error('Aucune source de donnée fournie');
}
$bdd->updateData();
return Command::SUCCESS;
}
......
......@@ -22,16 +22,7 @@ class UpdateDdlCommand extends Command
$io = new SymfonyStyle($input, $output);
$bdd = $this->getBdd()->setLogger($io);
$io->title('Génération de la DDL à partir de la base de données');
try {
$filters = $bdd->getFiltersForUpdateDdl();
$ddl = $bdd->getDdl($filters);
$ddl->saveToDir();
$io->success('DDL mise à jour');
} catch (\Throwable $e) {
$io->error($e->getMessage());
}
$bdd->updateDdl();
return Command::SUCCESS;
}
......
......@@ -7,6 +7,7 @@ class DefaultLogger implements LoggerInterface
{
const COLOR_LIGHT_RED = '1;31';
const COLOR_LIGHT_PURPLE = '1;35';
const COLOR_LIGHT_GREEN = '1;32';
protected ?string $lastMessage = null;
......@@ -15,7 +16,7 @@ class DefaultLogger implements LoggerInterface
public function print($text, $color = null, $bgColor = null)
public function print($text, $color = null, $bgColor = null): void
{
if ($bgColor) $bgColor = ';' . $bgColor;
......@@ -28,7 +29,7 @@ class DefaultLogger implements LoggerInterface
public function println($text, $color = null, $bgColor = null)
public function println($text, $color = null, $bgColor = null): void
{
$this->print($text, $color, $bgColor);
echo "\n";
......@@ -36,7 +37,7 @@ class DefaultLogger implements LoggerInterface
public function msg($message, bool $rewrite = false)
public function msg($message, bool $rewrite = false): void
{
if ($rewrite) {
if ($this->lastMessage) {
......@@ -54,7 +55,32 @@ class DefaultLogger implements LoggerInterface
public function error(Throwable|string $e)
public function title(string $title): void
{
$spaces = 1;
$pstr = str_repeat(' ', $spaces);
$t = $pstr . $title . $pstr;
$len = mb_strlen($t);
echo '╔' . str_repeat('═', $len) . "╗\n";
echo '║' . str_repeat(' ', $len) . "║\n";
echo "║" . $t . "║\n";
echo '║' . str_repeat(' ', $len) . "║\n";
echo '╚' . str_repeat('═', $len) . "╝\n\n";
}
public function success(string $message): void
{
if ($this->lastRewrite) $this->println('');
$this->println($message, self::COLOR_LIGHT_GREEN);
}
public function error(Throwable|string $e): void
{
if ($e instanceof \Throwable) {
$e = $e->getMessage();
......@@ -65,7 +91,7 @@ class DefaultLogger implements LoggerInterface
public function begin(string $title)
public function begin(string $title): void
{
if ($this->lastMessage) {
$title .= str_pad('', strlen($this->lastMessage) - strlen($title) + 2);
......
......@@ -38,28 +38,40 @@ trait LoggerAwareTrait
public function logError($e)
public function logTitle(string $title): void
{
if ($this->logger) $this->logger->title($title);
}
public function logSuccess(string $message): void
{
if ($this->logger) $this->logger->success($message);
}
public function logError(string|\Throwable $e): void
{
if ($this->logger) $this->logger->error($e);
}
public function logBegin(string $title)
public function logBegin(string $title): void
{
if ($this->logger) $this->logger->begin($title);
}
public function logEnd(?string $msg = null)
public function logEnd(?string $msg = null): void
{
if ($this->logger) $this->logger->end($msg);
}
public function logMsg($message, bool $rewrite = false)
public function logMsg(string $message, bool $rewrite = false): void
{
if ($this->logger) $this->logger->msg($message, $rewrite);
}
......
......@@ -4,17 +4,25 @@ namespace Unicaen\BddAdmin\Logger;
interface LoggerInterface
{
public function error(Throwable|string $e);
public function title(string $title): void;
public function begin(string $title);
public function success(string $message): void;
public function end(?string $msg = null);
public function error(Throwable|string $e): void;
public function msg($message, bool $rewrite = false);
public function begin(string $title): void;
public function end(?string $msg = null): void;
public function msg($message, bool $rewrite = false): void;
}
\ No newline at end of file
......@@ -22,21 +22,21 @@ class SymfonyStyleLogger implements LoggerInterface
public function print($text, $color = null, $bgColor = null)
public function print($text, $color = null, $bgColor = null): void
{
$this->symfonyStyle->write($text);
}
public function println($text, $color = null, $bgColor = null)
public function println($text, $color = null, $bgColor = null): void
{
$this->symfonyStyle->writeln($text);
}
public function msg($message, bool $rewrite = false)
public function msg($message, bool $rewrite = false): void
{
if ($rewrite) {
if ($this->lastMessage) {
......@@ -54,7 +54,22 @@ class SymfonyStyleLogger implements LoggerInterface
public function error(Throwable|string $e)
public function title(string $title): void
{
$this->symfonyStyle->title($title);
}
public function success(string $message): void
{
if ($this->lastRewrite) $this->println('');
$this->symfonyStyle->success($message);
}
public function error(Throwable|string $e): void
{
if ($e instanceof \Throwable) {
$e = $e->getMessage();
......@@ -65,7 +80,7 @@ class SymfonyStyleLogger implements LoggerInterface
public function begin(string $title)
public function begin(string $title): void
{
if ($this->lastMessage) {
$title .= str_pad('', strlen($this->lastMessage) - strlen($title) + 2);
......
......@@ -3,19 +3,30 @@
namespace Unicaen\BddAdmin\Migration;
abstract class AbstractMigration
use Unicaen\BddAdmin\BddAwareTrait;
use Unicaen\BddAdmin\Logger\LoggerAwareTrait;
abstract class MigrationAction
{
use BddAwareTrait;
use LoggerAwareTrait;
/**
* @var MigrationManager
*/
protected $manager;
private MigrationManager $manager;
public function __construct(MigrationManager $manager)
{
$this->manager = $manager;
$this->setBdd($this->manager->getBdd());
$this->setLogger($this->getBdd()->getLogger());
}
protected function manager(): MigrationManager
{
return $this->manager;
}
......
......@@ -3,6 +3,7 @@
namespace Unicaen\BddAdmin\Migration;
use Unicaen\BddAdmin\Bdd;
use Unicaen\BddAdmin\BddAwareTrait;
use Unicaen\BddAdmin\Ddl\Ddl;
use Unicaen\BddAdmin\Ddl\DdlFilters;
use Unicaen\BddAdmin\Trait\OptionsTrait;
......@@ -10,8 +11,10 @@ use Unicaen\BddAdmin\Trait\OptionsTrait;
class MigrationManager
{
use OptionsTrait;
use BddAwareTrait;
const OPTION_DIR = 'dir';
const ACTION_BEFORE = 'before';
const ACTION_AFTER = 'after';
protected Ddl $ref;
......@@ -19,40 +22,10 @@ class MigrationManager
protected DdlFilters $filters;
protected Bdd $bdd;
private array $actions = [];
public function __construct(Bdd $bdd)
{
$this->bdd = $bdd;
}
public function getDir(): ?string
{
return $this->getOption(self::OPTION_DIR);
}
public function setDir(?string $dir): MigrationManager
{
return $this->setOption(self::OPTION_DIR, $dir);
}
public function getBdd(): Bdd
{
return $this->bdd;
}
/**
* Retourne la nouvelle DDL de la base de données
*/
......@@ -172,97 +145,66 @@ class MigrationManager
protected function getMigrationDir(): ?string
public function init(Ddl $ref, DdlFilters|array $filters = [])
{
$migrationDir = $this->getBdd()->getOption(self::OPTION_DIR);
return $migrationDir;
$this->ref = $ref;
$this->filters = DdlFilters::normalize($filters);
$this->old = $this->getBdd()->getDdl($this->filters);
}
protected function getMigrationObject(string $action): ?AbstractMigration
{
if (!array_key_exists($action, $this->actions)) {
$file = $this->getMigrationDir() . $action . '.php';
require_once $file;
/**
* @var $object AbstractMigration
* @return array|MigrationAction[]
* @throws \Exception
*/
$object = new $action($this, $this);
if ($object->utile()) {
$this->actions[$action] = $object;
} else {
$this->actions[$action] = null;
}
}
public function getScripts(): array
{
$scripts = $this->getOptions();
return $this->actions[$action];
foreach ($scripts as $index => $script) {
if (is_string($script) && class_exists($script)) {
$script = new $script($this);
$scripts[$index] = $script;
}
protected function runMigrationAction(string $contexte, string $action): void
{
$logger = $this->getBdd()->getLogger();
$migration = $this->getMigrationObject($action);
if (
$migration
&& $migration instanceof AbstractMigration
&& (method_exists($migration, $contexte))
) {
$traducs = [
'before' => 'AVANT',
'after' => 'APRES',
];
$contexteLib = $traducs[$contexte] ?? $contexte;
$logger->msg("[$contexteLib MIGRATION] " . $migration->description() . ' ... ');
try {
$migration->$contexte();
$logger->msg("OK\n");
} catch (\Throwable $e) {
$logger->error($e);
if (!$script instanceof MigrationAction) {
throw new \Exception('Le script de migration ' . $script::class . ' doit correspondre à une classe héritée de ' . MigrationAction::class);
}
if (!method_exists($script, self::ACTION_BEFORE) && !method_exists($script, self::ACTION_AFTER)) {
throw new \Exception('Le script de migration ' . $script::class . ' doit avoir une ou des méthodes ' . self::ACTION_BEFORE . ' et/ou ' . self::ACTION_AFTER);
}
}
public function testUtile($action): bool
{
$migration = $this->getMigrationObject($action);
return $migration instanceof AbstractMigration;
return $scripts;
}
public function init(Ddl $ref, DdlFilters|array $filters = [])
public function run(string $context): void
{
$this->ref = $ref;
$this->filters = DdlFilters::normalize($filters);
$this->old = $this->getBdd()->getDdl($this->filters);
if ($context != self::ACTION_BEFORE && $context != self::ACTION_AFTER) {
throw new \Exception('Le contexte de migration ' . $context . ' est non conforme');
}
$scripts = $this->getScripts();
$traducs = [
self::ACTION_BEFORE => 'AVANT',
self::ACTION_AFTER => 'APRES',
];
public function migration(string $context = 'pre', string $action = null): void
{
$migrationDir = $this->getMigrationDir();
if (!is_dir($migrationDir ?? '')) return;
$files = scandir($migrationDir);
sort($files);
foreach ($files as $i => $file) {
if ($file == '.' || $file == '..') {
continue;
foreach ($scripts as $object) {
if (method_exists($object, $context)) {
if ($object->utile()) {
$object->logMsg("[" . $traducs[$context] . " MIGRATION] " . $object->description() . ' ... ');
try {
$object->$context();
$object->logMsg("OK\n");
} catch (\Throwable $e) {
$object->logError($e);
}
}
$fileAction = substr($file, 0, -4); // on supprime l'extension PHP
if ($action === null || $fileAction === $action) {
$this->runMigrationAction($context, $fileAction);
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment