From 5e7648ba955898ad42fdd839bbf3d21467b4037f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Laurent=20L=C3=A9cluse?= <laurent.lecluse@unicaen.fr> Date: Tue, 15 Oct 2024 16:31:50 +0200 Subject: [PATCH] =?UTF-8?q?nouvelles=20commandes=20et=20am=C3=A9liorations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 38 ++++---- config/module.config.php | 12 ++- src/Command/UpdateBddCommand.php | 80 ++++++++++++++++ src/Command/UpdateBddCommandFactory.php | 31 +++++++ src/Command/UpdateDdlCommand.php | 36 ++++++++ src/Command/UpdateDdlCommandFactory.php | 32 +++++++ src/Ddl/Ddl.php | 8 +- src/Driver/Postgresql/FunctionManager.php | 6 ++ .../Postgresql/MaterializedViewManager.php | 7 +- src/Driver/Postgresql/ProcedureManager.php | 6 ++ src/Driver/Postgresql/TableManager.php | 12 +-- src/Driver/Postgresql/TriggerManager.php | 6 ++ src/Driver/Postgresql/ViewManager.php | 6 ++ src/Logger/DefaultLogger.php | 2 +- src/Logger/LoggerAwareTrait.php | 7 +- src/Logger/LoggerInterface.php | 2 +- src/Logger/SymfonyStyleLogger.php | 92 +++++++++++++++++++ src/Migration/MigrationManager.php | 4 +- 18 files changed, 353 insertions(+), 34 deletions(-) create mode 100644 src/Command/UpdateBddCommand.php create mode 100644 src/Command/UpdateBddCommandFactory.php create mode 100644 src/Command/UpdateDdlCommand.php create mode 100644 src/Command/UpdateDdlCommandFactory.php create mode 100644 src/Logger/SymfonyStyleLogger.php diff --git a/composer.json b/composer.json index 8f9ad1f..6f1db68 100644 --- a/composer.json +++ b/composer.json @@ -1,22 +1,22 @@ { - "name" : "unicaen/bddadmin", - "description" : "Module pour administrer des bases de données Postgresql et Oracle", - "repositories": [ - { - "type": "composer", - "url" : "https://dev.unicaen.fr/packagist" - } - ], - "require": { - "php": ">=8.2" - }, - "autoload" : { - "psr-4" : { - "Unicaen\\BddAdmin\\" : "src/", - "Unicaen\\BddAdmin\\Tests\\" : "tests/" - }, - "classmap": [ - "./Module.php" - ] + "name": "unicaen/bddadmin", + "description": "Module pour administrer des bases de données Postgresql et Oracle", + "repositories": [ + { + "type": "composer", + "url": "https://dev.unicaen.fr/packagist" } + ], + "require": { + "php": ">=8.2" + }, + "autoload": { + "psr-4": { + "Unicaen\\BddAdmin\\": "src/", + "Unicaen\\BddAdmin\\Tests\\": "tests/" + }, + "classmap": [ + "./Module.php" + ] + } } diff --git a/config/module.config.php b/config/module.config.php index 7d4bc09..bb7f738 100644 --- a/config/module.config.php +++ b/config/module.config.php @@ -54,7 +54,17 @@ return [ 'service_manager' => [ 'factories' => [ - Bdd::class => BddFactory::class, + Bdd::class => BddFactory::class, + Command\UpdateBddCommand::class => Command\UpdateBddCommandFactory::class, + Command\UpdateDdlCommand::class => Command\UpdateDdlCommandFactory::class, + ], + ], + + + 'laminas-cli' => [ + 'commands' => [ + 'bddadmin:update-bdd' => Command\UpdateBddCommand::class, + 'bddadmin:update-ddl' => Command\UpdateDdlCommand::class, ], ], ]; \ No newline at end of file diff --git a/src/Command/UpdateBddCommand.php b/src/Command/UpdateBddCommand.php new file mode 100644 index 0000000..7e75b26 --- /dev/null +++ b/src/Command/UpdateBddCommand.php @@ -0,0 +1,80 @@ +<?php + +namespace Unicaen\BddAdmin\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Unicaen\BddAdmin\BddAwareTrait; +use Unicaen\BddAdmin\Ddl\Ddl; + +/** + * Description of UpdateBddCommand + * + * @author Laurent Lécluse <laurent.lecluse at unicaen.fr> + */ +class UpdateBddCommand extends Command +{ + use BddAwareTrait; + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $bdd = $this->getBdd()->setLogger($io); + + $io->title('Mise à jour de la base de données'); + $io->info('Mise à jour des définitions de la base de données. Merci de patienter ...'); + + $ref = $bdd->getRefDdl(); + + // Construction de la config de DDL pour filtrer + $filters = []; + foreach ($ref as $ddlClass => $objects) { + foreach ($objects as $object => $objectDdl) { + $filters[$ddlClass]['includes'][] = $object; + } + } + + $tablesDep = [ + Ddl::INDEX, + Ddl::PRIMARY_CONSTRAINT, + Ddl::REF_CONSTRAINT, + Ddl::UNIQUE_CONSTRAINT, + ]; + + foreach ($tablesDep as $tableDep) { + $objects = $bdd->manager($tableDep)->get(); + foreach ($objects as $obj) { + if (in_array($obj['table'], $filters['table']['includes'])) { + $filters[$tableDep]['includes'][] = $obj['name']; + } + } + } + + // Initialisation et lancement de la pré-migration + //$mm = new MigrationManager($oa, $ref, $filters); + //$mm->migration('before'); + + + // Mise à jour de la BDD (structures) + $bdd->alter($ref, $filters, true); + + + // Mise à jour des séquences + $bdd->majSequences($ref); + + + // Mise à jour des données + //$bdd->logBegin('Contrôle et mise à jour des données'); + //$bdd->dataUpdater()->run('update'); + //$bdd->logEnd('Données à jour'); + + + + // Post-migration + //$mm->migration('after'); + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Command/UpdateBddCommandFactory.php b/src/Command/UpdateBddCommandFactory.php new file mode 100644 index 0000000..4b5ef7d --- /dev/null +++ b/src/Command/UpdateBddCommandFactory.php @@ -0,0 +1,31 @@ +<?php + +namespace Unicaen\BddAdmin\Command; + +use Psr\Container\ContainerInterface; +use Unicaen\BddAdmin\Bdd; + + +/** + * Description of UpdateBddCommandFactory + * + * @author Laurent Lécluse <laurent.lecluse at unicaen.fr> + */ +class UpdateBddCommandFactory +{ + + /** + * @param ContainerInterface $container + * @param string $requestedName + * @param array|null $options + * + * @return UpdateBddCommand + */ + public function __invoke(ContainerInterface $container, $requestedName, $options = null): UpdateBddCommand + { + $command = new UpdateBddCommand; + $command->setBdd($container->get(Bdd::class)); + + return $command; + } +} \ No newline at end of file diff --git a/src/Command/UpdateDdlCommand.php b/src/Command/UpdateDdlCommand.php new file mode 100644 index 0000000..9fdeecf --- /dev/null +++ b/src/Command/UpdateDdlCommand.php @@ -0,0 +1,36 @@ +<?php + +namespace Unicaen\BddAdmin\Command; + +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\InputInterface; +use Symfony\Component\Console\Output\OutputInterface; +use Symfony\Component\Console\Style\SymfonyStyle; +use Unicaen\BddAdmin\BddAwareTrait; + +/** + * Description of UpdateDdlCommand + * + * @author Laurent Lécluse <laurent.lecluse at unicaen.fr> + */ +class UpdateDdlCommand extends Command +{ + use BddAwareTrait; + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $io = new SymfonyStyle($input, $output); + $bdd = $this->getBdd()->setLogger($io); + + $filters = [ + ]; + + $io->title('Génération de la DDL à partir de la base de données'); + + $ddl = $bdd->getDdl($filters); + + $ddl->saveToDir(); + + return Command::SUCCESS; + } +} \ No newline at end of file diff --git a/src/Command/UpdateDdlCommandFactory.php b/src/Command/UpdateDdlCommandFactory.php new file mode 100644 index 0000000..c6402da --- /dev/null +++ b/src/Command/UpdateDdlCommandFactory.php @@ -0,0 +1,32 @@ +<?php + +namespace Unicaen\BddAdmin\Command; + +use Psr\Container\ContainerInterface; +use Unicaen\BddAdmin\Bdd; + + +/** + * Description of UpdateDdlCommandFactory + * + * @author Laurent Lécluse <laurent.lecluse at unicaen.fr> + */ +class UpdateDdlCommandFactory +{ + + + /** + * @param ContainerInterface $container + * @param string $requestedName + * @param array|null $options + * + * @return UpdateBddCommand + */ + public function __invoke(ContainerInterface $container, $requestedName, $options = null): UpdateDdlCommand + { + $command = new UpdateDdlCommand; + $command->setBdd($container->get(Bdd::class)); + + return $command; + } +} \ No newline at end of file diff --git a/src/Ddl/Ddl.php b/src/Ddl/Ddl.php index c35c2b8..582da1e 100644 --- a/src/Ddl/Ddl.php +++ b/src/Ddl/Ddl.php @@ -488,7 +488,13 @@ class Ddl implements Iterator, ArrayAccess if ($name != '.' && $name != '..') { $def = file_get_contents($dir . $type . '/' . $name); $name = substr($name, 0, -4); - $this->data[$type][$name] = ['name' => $name, 'definition' => $def]; + if (str_contains($name, '.')) { + [$schema, $vmname] = Util::explodedFullObjectName($name); + $this->data[$type][$name] = ['schema' => $schema, 'name' => $vmname, 'definition' => $def]; + }else{ + $this->data[$type][$name] = ['name' => $name, 'definition' => $def]; + } + } } } diff --git a/src/Driver/Postgresql/FunctionManager.php b/src/Driver/Postgresql/FunctionManager.php index 413b862..06161dc 100644 --- a/src/Driver/Postgresql/FunctionManager.php +++ b/src/Driver/Postgresql/FunctionManager.php @@ -106,6 +106,12 @@ class FunctionManager extends AbstractManager implements FunctionManagerInteface public function alter(array $old, array $new): void { + if (!isset($old['schema'])){ + $old['schema'] = 'public'; + } + if (!isset($new['schema'])){ + $new['schema'] = 'public'; + } if ($old != $new) { if ($this->sendEvent()->getReturn('no-exec')) return; diff --git a/src/Driver/Postgresql/MaterializedViewManager.php b/src/Driver/Postgresql/MaterializedViewManager.php index 3bbf40a..cafef3b 100644 --- a/src/Driver/Postgresql/MaterializedViewManager.php +++ b/src/Driver/Postgresql/MaterializedViewManager.php @@ -78,7 +78,12 @@ class MaterializedViewManager extends AbstractManager implements MaterializedVie public function alter(array $old, array $new): void { if ($this->sendEvent()->getReturn('no-exec')) return; - + if (!isset($old['schema'])){ + $old['schema'] = 'public'; + } + if (!isset($new['schema'])){ + $new['schema'] = 'public'; + } if ($old != $new) { $this->drop($old); $this->create($new); diff --git a/src/Driver/Postgresql/ProcedureManager.php b/src/Driver/Postgresql/ProcedureManager.php index 3405c33..e37d230 100644 --- a/src/Driver/Postgresql/ProcedureManager.php +++ b/src/Driver/Postgresql/ProcedureManager.php @@ -79,6 +79,12 @@ class ProcedureManager extends AbstractManager implements ProcedureManagerIntefa public function alter(array $old, array $new): void { + if (!isset($old['schema'])){ + $old['schema'] = 'public'; + } + if (!isset($new['schema'])){ + $new['schema'] = 'public'; + } if ($old != $new) { if ($this->sendEvent()->getReturn('no-exec')) return; diff --git a/src/Driver/Postgresql/TableManager.php b/src/Driver/Postgresql/TableManager.php index 8b30de0..9208502 100644 --- a/src/Driver/Postgresql/TableManager.php +++ b/src/Driver/Postgresql/TableManager.php @@ -80,8 +80,7 @@ class TableManager extends AbstractManager implements TableManagerInterface $q = "SELECT ns.nspname \"schema\", t.relname \"name\", - 'N' \"temporary\", - 'NO' logging, + t.relpersistence relpersistence, c.column_name cname, c.data_type \"type\", c.character_maximum_length length, @@ -113,8 +112,8 @@ class TableManager extends AbstractManager implements TableManagerInterface $data[$name] = [ 'schema' => $paq['schema'], 'name' => $paq['name'], - 'temporary' => $paq['temporary'] == 'YES', - 'logging' => $paq['logging'] == 'YES', + 'temporary' => $paq['relpersistence'] == 't', + 'logging' => $paq['relpersistence'] == 'p', 'commentaire' => $paq['commentaire'], 'sequence' => $paq['sequence'], 'columns' => [], @@ -578,9 +577,8 @@ class TableManager extends AbstractManager implements TableManagerInterface if ($this->sendEvent()->getReturn('no-exec')) return; if ($old['logging'] !== $new['logging']) { - throw new BddException("Il n'est pas possible actuellement de supprimer le logging d'une table ou de faire l'opération inverse"); - //$log = $new['logging'] ? 'LOGGING' : 'NOLOGGING'; - //$this->addQuery("ALTER TABLE $name $log", 'Modification du logging de la table ' . $name); + $sql = "ALTER TABLE $name SET ".($new['logging'] ? 'LOGGED' : 'UNLOGGED'); + $this->addQuery($sql, 'Modification du logging de la table ' . $name); } $newCols = array_diff(array_keys($new['columns']), array_keys($old['columns'])); diff --git a/src/Driver/Postgresql/TriggerManager.php b/src/Driver/Postgresql/TriggerManager.php index e420783..20a681c 100644 --- a/src/Driver/Postgresql/TriggerManager.php +++ b/src/Driver/Postgresql/TriggerManager.php @@ -153,6 +153,12 @@ class TriggerManager extends AbstractManager implements TriggerManagerInterface public function alter(array $old, array $new): void { + if (!isset($old['schema'])){ + $old['schema'] = 'public'; + } + if (!isset($new['schema'])){ + $new['schema'] = 'public'; + } if ($old != $new) { if ($this->sendEvent()->getReturn('no-exec')) return; diff --git a/src/Driver/Postgresql/ViewManager.php b/src/Driver/Postgresql/ViewManager.php index a69159d..d8917d8 100644 --- a/src/Driver/Postgresql/ViewManager.php +++ b/src/Driver/Postgresql/ViewManager.php @@ -75,6 +75,12 @@ class ViewManager extends AbstractManager implements ViewManagerInterface public function alter(array $old, array $new): void { + if (!isset($old['schema'])){ + $old['schema'] = 'public'; + } + if (!isset($new['schema'])){ + $new['schema'] = 'public'; + } if ($old != $new) { if ($this->sendEvent()->getReturn('no-exec')) return; diff --git a/src/Logger/DefaultLogger.php b/src/Logger/DefaultLogger.php index cb82ff1..4846a49 100644 --- a/src/Logger/DefaultLogger.php +++ b/src/Logger/DefaultLogger.php @@ -54,7 +54,7 @@ class DefaultLogger implements LoggerInterface - public function error($e) + public function error(Throwable|string $e) { if ($e instanceof \Throwable) { $e = $e->getMessage(); diff --git a/src/Logger/LoggerAwareTrait.php b/src/Logger/LoggerAwareTrait.php index 6c33541..399a64e 100644 --- a/src/Logger/LoggerAwareTrait.php +++ b/src/Logger/LoggerAwareTrait.php @@ -2,6 +2,8 @@ namespace Unicaen\BddAdmin\Logger; +use Symfony\Component\Console\Style\SymfonyStyle; + trait LoggerAwareTrait { @@ -24,8 +26,11 @@ trait LoggerAwareTrait * * @return self */ - public function setLogger(?LoggerInterface $logger): self + public function setLogger(null|LoggerInterface|SymfonyStyle $logger): self { + if ($logger instanceof SymfonyStyle){ + $logger = new SymfonyStyleLogger($logger); + } $this->logger = $logger; return $this; diff --git a/src/Logger/LoggerInterface.php b/src/Logger/LoggerInterface.php index 51b7b43..0d0aa4b 100644 --- a/src/Logger/LoggerInterface.php +++ b/src/Logger/LoggerInterface.php @@ -4,7 +4,7 @@ namespace Unicaen\BddAdmin\Logger; interface LoggerInterface { - public function error($e); + public function error(Throwable|string $e); diff --git a/src/Logger/SymfonyStyleLogger.php b/src/Logger/SymfonyStyleLogger.php new file mode 100644 index 0000000..15307cf --- /dev/null +++ b/src/Logger/SymfonyStyleLogger.php @@ -0,0 +1,92 @@ +<?php + +namespace Unicaen\BddAdmin\Logger; + + +use Symfony\Component\Console\Style\SymfonyStyle; + +class SymfonyStyleLogger implements LoggerInterface +{ + protected ?string $lastMessage = null; + + protected bool $lastRewrite = false; + + protected SymfonyStyle $symfonyStyle; + + + + public function __construct(SymfonyStyle $symfonyStyle) + { + $this->symfonyStyle = $symfonyStyle; + } + + + + public function print($text, $color = null, $bgColor = null) + { + $this->symfonyStyle->write($text); + } + + + + public function println($text, $color = null, $bgColor = null) + { + $this->symfonyStyle->writeln($text); + } + + + + public function msg($message, bool $rewrite = false) + { + if ($rewrite) { + if ($this->lastMessage) { + $m = $message . str_pad('', strlen($this->lastMessage) - strlen($message) + 2) . "\r"; + } else { + $m = $message . "\r"; + } + $this->print($m); + } else { + $this->println($message); + } + $this->lastMessage = $message; + $this->lastRewrite = $rewrite; + } + + + + public function error(Throwable|string $e) + { + if ($e instanceof \Throwable) { + $e = $e->getMessage(); + } + if ($this->lastRewrite) $this->println(''); + $this->symfonyStyle->error($e); + } + + + + public function begin(string $title) + { + if ($this->lastMessage) { + $title .= str_pad('', strlen($this->lastMessage) - strlen($title) + 2); + } + $this->lastRewrite = false; + $this->lastMessage = null; + $this->symfonyStyle->title($title); + } + + + + public function end(?string $msg = null): void + { + if ($this->lastMessage && $this->lastRewrite) { + $msg .= str_pad('', strlen($this->lastMessage) - strlen($msg ?? '') + 2); + } + if (trim($msg)) { + $this->symfonyStyle->comment($msg); + } else { + $this->println(''); + } + } + +} \ No newline at end of file diff --git a/src/Migration/MigrationManager.php b/src/Migration/MigrationManager.php index 9edc1b0..f0b5569 100644 --- a/src/Migration/MigrationManager.php +++ b/src/Migration/MigrationManager.php @@ -11,7 +11,7 @@ class MigrationManager { use OptionsTrait; - const string OPTION_DIR = 'dir'; + const OPTION_DIR = 'dir'; protected Ddl $ref; @@ -174,7 +174,7 @@ class MigrationManager protected function getMigrationDir(): ?string { - $migrationDir = $this->getBdd()->getOption(Bdd::OPTION_MIGRATION_DIR); + $migrationDir = $this->getBdd()->getOption(self::OPTION_DIR); return $migrationDir; } -- GitLab