Loading config/module.config.php +3 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ use UnicaenDbfakator\Controller\IndexController; use UnicaenDbfakator\Controller\IndexControllerFactory; use UnicaenDbfakator\Service\DbfakatorService; use UnicaenDbfakator\Service\DbfakatorServiceFactory; use UnicaenDbfakator\Service\DbService; use UnicaenDbfakator\Service\DbServiceFactory; return [ 'router' => [ Loading Loading @@ -150,6 +152,7 @@ return [ ], 'service_manager' => [ 'factories' => [ DbService::class => DbServiceFactory::class, DbfakatorService::class => DbfakatorServiceFactory::class, ], ], Loading sql/schema.postgres.sql 0 → 100644 +12 −0 Original line number Diff line number Diff line -- -- Création si nécessaire de la table des métadonnées de la bdd. -- create table if not exists _METADATA ( key varchar(64) not null, value text, extra text, description varchar(128) ); -- Création du témoin d'anonymisation insert into _METADATA (key, value, description) values ('BDD_ANONYMISEE', '0', 'Indique si les données de cette bdd ont été anonymisées (1) ou non (0)'); src/UnicaenDbfakator/Controller/ConsoleController.php +11 −11 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ class ConsoleController extends AbstractConsoleController $anonymisationScriptPath = $this->dbfakatorService->getAnonymisationScriptPath(); $restaurationScriptPath = $this->dbfakatorService->getRestaurationScriptPath(); try { $gen = $this->dbfakatorService->generer($anonymisationScriptPath, $restaurationScriptPath); $gen = $this->dbfakatorService->generer(); foreach ($gen as ['table' => $table, 'fields' => $fields, 'count' => $count]) { $this->console->writeLine( sprintf("- Table %s (colonnes %s) : %d lignes", $table, implode(', ', $fields), $count) Loading @@ -49,9 +49,15 @@ class ConsoleController extends AbstractConsoleController $this->console->writeLine("Lancement du script d'anonymisation '$scriptPath'..."); $start = microtime(true); $this->lancerAction($scriptPath); try { $result = $this->dbfakatorService->anonymiser(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } $end = microtime(true); $this->console->writeLine("> Résultat : " . ($result->isSuccess() ? 'Succès' : 'Échec')); $this->console->writeLine("> Log file : " . $result->getLogFilePath()); $this->console->writeLine(sprintf("Duree : %.2f s", $end - $start)); } Loading @@ -62,21 +68,15 @@ class ConsoleController extends AbstractConsoleController $this->console->writeLine("Lancement du script de restauration '$scriptPath'..."); $start = microtime(true); $this->lancerAction($scriptPath); $end = microtime(true); $this->console->writeLine(sprintf("Duree : %.2f s", $end - $start)); } protected function lancerAction(string $scriptPath) { try { $result = $this->dbfakatorService->lancer($scriptPath); $result = $this->dbfakatorService->restaurer(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } $end = microtime(true); $this->console->writeLine("> Résultat : " . ($result->isSuccess() ? 'Succès' : 'Échec')); $this->console->writeLine("> Log file : " . $result->getLogFilePath()); $this->console->writeLine(sprintf("Duree : %.2f s", $end - $start)); } } No newline at end of file src/UnicaenDbfakator/Controller/IndexController.php +5 −9 Original line number Diff line number Diff line Loading @@ -3,12 +3,11 @@ namespace UnicaenDbfakator\Controller; use Application\Controller\AbstractController; use Exception; use Laminas\View\Model\ViewModel; use UnicaenApp\Exception\RuntimeException; use UnicaenApp\Service\SQL\RunSQLResult; use UnicaenDbfakator\Service\DbfakatorServiceAwareTrait; use Exception; use UnicaenApp\Exception\RuntimeException; use Webmozart\Assert\InvalidArgumentException; class IndexController extends AbstractController { Loading @@ -16,9 +15,6 @@ class IndexController extends AbstractController public function indexAction(): array { // $action = $this->params()->fromQuery('action'); // $this->url()->fromRoute('', [], ['query' => ['redirect' => ]], true); $anonymisationScriptPath = $this->dbfakatorService->getAnonymisationScriptPath(); $restaurationScriptPath = $this->dbfakatorService->getRestaurationScriptPath(); Loading @@ -41,7 +37,7 @@ class IndexController extends AbstractController $messages = []; try { $gen = $this->dbfakatorService->generer($anonymisationScriptPath, $restaurationScriptPath); $gen = $this->dbfakatorService->generer(); foreach ($gen as ['table' => $table, 'fields' => $fields, 'count' => $count]) { $messages[] = sprintf("- Table %s (colonnes %s) : %d lignes", $table, implode(', ', $fields), $count); } Loading @@ -61,7 +57,7 @@ class IndexController extends AbstractController $scriptPath = $this->dbfakatorService->getAnonymisationScriptPath(); try { $result = $this->dbfakatorService->lancerAnonymisation($scriptPath); $result = $this->dbfakatorService->anonymiser(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } Loading @@ -74,7 +70,7 @@ class IndexController extends AbstractController $scriptPath = $this->dbfakatorService->getRestaurationScriptPath(); try { $result = $this->dbfakatorService->lancerRestauration($scriptPath); $result = $this->dbfakatorService->restaurer(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } Loading src/UnicaenDbfakator/Service/DbService.php 0 → 100644 +187 −0 Original line number Diff line number Diff line <?php namespace UnicaenDbfakator\Service; use Doctrine\DBAL\ConnectionException; use Doctrine\DBAL\Exception; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\ClassMetadata; use Faker\Factory; use Laminas\Log\Logger; use Laminas\Log\Writer\Stream; use Locale; use RuntimeException; use Throwable; use UnicaenApp\Service\SQL\RunSQLProcess; use UnicaenApp\Service\SQL\RunSQLResult; use Webmozart\Assert\Assert; class DbService { const METADATA_KEY_ANONYMISEE = 'BDD_ANONYMISEE'; /** * @var \Doctrine\ORM\EntityManager */ protected $entityManager; /** * @var \Doctrine\DBAL\Platforms\AbstractPlatform */ protected $databasePlatform; /** * @var string */ protected $updateSQLTemplate = 'update %s set %s where id = %d ;'; /** * @var \Faker\Generator $faker */ protected $faker; public function __construct() { $this->faker = Factory::create(Locale::getDefault()); } /** * @param \Doctrine\ORM\EntityManager $entityManager * @throws \Doctrine\DBAL\Exception */ public function setEntityManager(EntityManager $entityManager): void { $this->entityManager = $entityManager; $this->databasePlatform = $this->entityManager->getConnection()->getDatabasePlatform(); } public function isBddAnonymisee(): bool { $sqlTemplate = "select value from _METADATA where key = '%s'"; $sql = sprintf($sqlTemplate, self::METADATA_KEY_ANONYMISEE); try { /** @var string|false $result */ $result = $this->entityManager->getConnection()->executeQuery($sql)->fetchOne(); } catch (Throwable $e) { throw new RuntimeException( "Erreur lors de l'interrogation du témoin d'anonymisation dans la table des metadata", null, $e); } if ($result === false) { throw new RuntimeException(sprintf( "Le témoin d'anonymisation '%s' est introuvable dans la table des metadata", self::METADATA_KEY_ANONYMISEE )); } return $result === '1'; } public function setBddAnonymisee(bool $bddAnonymisee) { $sqlTemplate = "update _METADATA set value = '%d' where key = '%s'"; $sql = sprintf($sqlTemplate, $bddAnonymisee ? '1' : '0', self::METADATA_KEY_ANONYMISEE); try { $this->entityManager->getConnection()->executeQuery($sql); } catch (Exception $e) { throw new RuntimeException( "Erreur lors de la modification du témoin d'anonymisation dans la table des metadata", null, $e); } } public function fetchEntityRecords(string $entityName, array $fields, array $except): array { $qb = $this->entityManager->createQueryBuilder() ->select("partial t.{id," . implode(',', $fields) . "}") ->from($entityName, 't'); foreach ($except as $field => $values) { $qb->andWhere($qb->expr()->notIn('t.' . $field, (array)$values)); } return $qb->getQuery()->getArrayResult(); } public function getEntityClassMetadata(string $entityName): ClassMetadata { return $this->entityManager->getClassMetadata($entityName); } public function genUpdateForAnonymiser(array $record, array $mapping, ClassMetadata $metadata): string { $tableName = $metadata->getTableName(); $sets = []; foreach ($mapping as $fieldName => $fakerConfig) { $fakerConfig = (array)$fakerConfig; $method = array_shift($fakerConfig); if ($method === 'null') { $fakeValue = 'NULL'; } else { $fakeValue = $this->faker->$method(...$fakerConfig); $fakeValue = $this->databasePlatform->quoteStringLiteral($fakeValue); } $columnName = $metadata->getColumnName($fieldName); $sets[] = "$columnName = $fakeValue"; } return sprintf($this->updateSQLTemplate, $tableName, implode(', ', $sets), $record['id'] ); } public function genUpdateForRestaurer(array $record, array $mapping, ClassMetadata $metadata): string { $tableName = $metadata->getTableName(); $sets = []; foreach ($mapping as $fieldName => $fakerConfig) { $value = $this->databasePlatform->quoteStringLiteral($record[$fieldName]); $columnName = $metadata->getColumnName($fieldName); $sets[] = "$columnName = $value"; } return sprintf($this->updateSQLTemplate, $tableName, implode(', ', $sets), $record['id'] ); } /** * @throws \Doctrine\DBAL\ConnectionException */ public function lancerScript(string $scriptPath): RunSQLResult { Assert::readable($scriptPath, "Le script '$scriptPath' n'existe pas ou n'est pas lisible"); $conn = $this->entityManager->getConnection(); $conn->beginTransaction(); $p = new RunSQLProcess(); $p->setConnection($conn); $p->setScriptPath($scriptPath); $p->setQueriesSplitPattern("#;\n#m"); // point virgule puis un retour $p->setLogFilePath($scriptPath . '.log'); $p->setLogger((new Logger())->addWriter(new Stream('php://stdout'))); $result = $p->executeScript(); try { $conn->commit(); } catch (ConnectionException $e) { $conn->rollBack(); throw $e; } return $result; } } No newline at end of file Loading
config/module.config.php +3 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ use UnicaenDbfakator\Controller\IndexController; use UnicaenDbfakator\Controller\IndexControllerFactory; use UnicaenDbfakator\Service\DbfakatorService; use UnicaenDbfakator\Service\DbfakatorServiceFactory; use UnicaenDbfakator\Service\DbService; use UnicaenDbfakator\Service\DbServiceFactory; return [ 'router' => [ Loading Loading @@ -150,6 +152,7 @@ return [ ], 'service_manager' => [ 'factories' => [ DbService::class => DbServiceFactory::class, DbfakatorService::class => DbfakatorServiceFactory::class, ], ], Loading
sql/schema.postgres.sql 0 → 100644 +12 −0 Original line number Diff line number Diff line -- -- Création si nécessaire de la table des métadonnées de la bdd. -- create table if not exists _METADATA ( key varchar(64) not null, value text, extra text, description varchar(128) ); -- Création du témoin d'anonymisation insert into _METADATA (key, value, description) values ('BDD_ANONYMISEE', '0', 'Indique si les données de cette bdd ont été anonymisées (1) ou non (0)');
src/UnicaenDbfakator/Controller/ConsoleController.php +11 −11 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ class ConsoleController extends AbstractConsoleController $anonymisationScriptPath = $this->dbfakatorService->getAnonymisationScriptPath(); $restaurationScriptPath = $this->dbfakatorService->getRestaurationScriptPath(); try { $gen = $this->dbfakatorService->generer($anonymisationScriptPath, $restaurationScriptPath); $gen = $this->dbfakatorService->generer(); foreach ($gen as ['table' => $table, 'fields' => $fields, 'count' => $count]) { $this->console->writeLine( sprintf("- Table %s (colonnes %s) : %d lignes", $table, implode(', ', $fields), $count) Loading @@ -49,9 +49,15 @@ class ConsoleController extends AbstractConsoleController $this->console->writeLine("Lancement du script d'anonymisation '$scriptPath'..."); $start = microtime(true); $this->lancerAction($scriptPath); try { $result = $this->dbfakatorService->anonymiser(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } $end = microtime(true); $this->console->writeLine("> Résultat : " . ($result->isSuccess() ? 'Succès' : 'Échec')); $this->console->writeLine("> Log file : " . $result->getLogFilePath()); $this->console->writeLine(sprintf("Duree : %.2f s", $end - $start)); } Loading @@ -62,21 +68,15 @@ class ConsoleController extends AbstractConsoleController $this->console->writeLine("Lancement du script de restauration '$scriptPath'..."); $start = microtime(true); $this->lancerAction($scriptPath); $end = microtime(true); $this->console->writeLine(sprintf("Duree : %.2f s", $end - $start)); } protected function lancerAction(string $scriptPath) { try { $result = $this->dbfakatorService->lancer($scriptPath); $result = $this->dbfakatorService->restaurer(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } $end = microtime(true); $this->console->writeLine("> Résultat : " . ($result->isSuccess() ? 'Succès' : 'Échec')); $this->console->writeLine("> Log file : " . $result->getLogFilePath()); $this->console->writeLine(sprintf("Duree : %.2f s", $end - $start)); } } No newline at end of file
src/UnicaenDbfakator/Controller/IndexController.php +5 −9 Original line number Diff line number Diff line Loading @@ -3,12 +3,11 @@ namespace UnicaenDbfakator\Controller; use Application\Controller\AbstractController; use Exception; use Laminas\View\Model\ViewModel; use UnicaenApp\Exception\RuntimeException; use UnicaenApp\Service\SQL\RunSQLResult; use UnicaenDbfakator\Service\DbfakatorServiceAwareTrait; use Exception; use UnicaenApp\Exception\RuntimeException; use Webmozart\Assert\InvalidArgumentException; class IndexController extends AbstractController { Loading @@ -16,9 +15,6 @@ class IndexController extends AbstractController public function indexAction(): array { // $action = $this->params()->fromQuery('action'); // $this->url()->fromRoute('', [], ['query' => ['redirect' => ]], true); $anonymisationScriptPath = $this->dbfakatorService->getAnonymisationScriptPath(); $restaurationScriptPath = $this->dbfakatorService->getRestaurationScriptPath(); Loading @@ -41,7 +37,7 @@ class IndexController extends AbstractController $messages = []; try { $gen = $this->dbfakatorService->generer($anonymisationScriptPath, $restaurationScriptPath); $gen = $this->dbfakatorService->generer(); foreach ($gen as ['table' => $table, 'fields' => $fields, 'count' => $count]) { $messages[] = sprintf("- Table %s (colonnes %s) : %d lignes", $table, implode(', ', $fields), $count); } Loading @@ -61,7 +57,7 @@ class IndexController extends AbstractController $scriptPath = $this->dbfakatorService->getAnonymisationScriptPath(); try { $result = $this->dbfakatorService->lancerAnonymisation($scriptPath); $result = $this->dbfakatorService->anonymiser(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } Loading @@ -74,7 +70,7 @@ class IndexController extends AbstractController $scriptPath = $this->dbfakatorService->getRestaurationScriptPath(); try { $result = $this->dbfakatorService->lancerRestauration($scriptPath); $result = $this->dbfakatorService->restaurer(); } catch (Exception $e) { throw new RuntimeException("Une erreur est survenue lors du lancement du script '$scriptPath'.", null, $e); } Loading
src/UnicaenDbfakator/Service/DbService.php 0 → 100644 +187 −0 Original line number Diff line number Diff line <?php namespace UnicaenDbfakator\Service; use Doctrine\DBAL\ConnectionException; use Doctrine\DBAL\Exception; use Doctrine\ORM\EntityManager; use Doctrine\ORM\Mapping\ClassMetadata; use Faker\Factory; use Laminas\Log\Logger; use Laminas\Log\Writer\Stream; use Locale; use RuntimeException; use Throwable; use UnicaenApp\Service\SQL\RunSQLProcess; use UnicaenApp\Service\SQL\RunSQLResult; use Webmozart\Assert\Assert; class DbService { const METADATA_KEY_ANONYMISEE = 'BDD_ANONYMISEE'; /** * @var \Doctrine\ORM\EntityManager */ protected $entityManager; /** * @var \Doctrine\DBAL\Platforms\AbstractPlatform */ protected $databasePlatform; /** * @var string */ protected $updateSQLTemplate = 'update %s set %s where id = %d ;'; /** * @var \Faker\Generator $faker */ protected $faker; public function __construct() { $this->faker = Factory::create(Locale::getDefault()); } /** * @param \Doctrine\ORM\EntityManager $entityManager * @throws \Doctrine\DBAL\Exception */ public function setEntityManager(EntityManager $entityManager): void { $this->entityManager = $entityManager; $this->databasePlatform = $this->entityManager->getConnection()->getDatabasePlatform(); } public function isBddAnonymisee(): bool { $sqlTemplate = "select value from _METADATA where key = '%s'"; $sql = sprintf($sqlTemplate, self::METADATA_KEY_ANONYMISEE); try { /** @var string|false $result */ $result = $this->entityManager->getConnection()->executeQuery($sql)->fetchOne(); } catch (Throwable $e) { throw new RuntimeException( "Erreur lors de l'interrogation du témoin d'anonymisation dans la table des metadata", null, $e); } if ($result === false) { throw new RuntimeException(sprintf( "Le témoin d'anonymisation '%s' est introuvable dans la table des metadata", self::METADATA_KEY_ANONYMISEE )); } return $result === '1'; } public function setBddAnonymisee(bool $bddAnonymisee) { $sqlTemplate = "update _METADATA set value = '%d' where key = '%s'"; $sql = sprintf($sqlTemplate, $bddAnonymisee ? '1' : '0', self::METADATA_KEY_ANONYMISEE); try { $this->entityManager->getConnection()->executeQuery($sql); } catch (Exception $e) { throw new RuntimeException( "Erreur lors de la modification du témoin d'anonymisation dans la table des metadata", null, $e); } } public function fetchEntityRecords(string $entityName, array $fields, array $except): array { $qb = $this->entityManager->createQueryBuilder() ->select("partial t.{id," . implode(',', $fields) . "}") ->from($entityName, 't'); foreach ($except as $field => $values) { $qb->andWhere($qb->expr()->notIn('t.' . $field, (array)$values)); } return $qb->getQuery()->getArrayResult(); } public function getEntityClassMetadata(string $entityName): ClassMetadata { return $this->entityManager->getClassMetadata($entityName); } public function genUpdateForAnonymiser(array $record, array $mapping, ClassMetadata $metadata): string { $tableName = $metadata->getTableName(); $sets = []; foreach ($mapping as $fieldName => $fakerConfig) { $fakerConfig = (array)$fakerConfig; $method = array_shift($fakerConfig); if ($method === 'null') { $fakeValue = 'NULL'; } else { $fakeValue = $this->faker->$method(...$fakerConfig); $fakeValue = $this->databasePlatform->quoteStringLiteral($fakeValue); } $columnName = $metadata->getColumnName($fieldName); $sets[] = "$columnName = $fakeValue"; } return sprintf($this->updateSQLTemplate, $tableName, implode(', ', $sets), $record['id'] ); } public function genUpdateForRestaurer(array $record, array $mapping, ClassMetadata $metadata): string { $tableName = $metadata->getTableName(); $sets = []; foreach ($mapping as $fieldName => $fakerConfig) { $value = $this->databasePlatform->quoteStringLiteral($record[$fieldName]); $columnName = $metadata->getColumnName($fieldName); $sets[] = "$columnName = $value"; } return sprintf($this->updateSQLTemplate, $tableName, implode(', ', $sets), $record['id'] ); } /** * @throws \Doctrine\DBAL\ConnectionException */ public function lancerScript(string $scriptPath): RunSQLResult { Assert::readable($scriptPath, "Le script '$scriptPath' n'existe pas ou n'est pas lisible"); $conn = $this->entityManager->getConnection(); $conn->beginTransaction(); $p = new RunSQLProcess(); $p->setConnection($conn); $p->setScriptPath($scriptPath); $p->setQueriesSplitPattern("#;\n#m"); // point virgule puis un retour $p->setLogFilePath($scriptPath . '.log'); $p->setLogger((new Logger())->addWriter(new Stream('php://stdout'))); $result = $p->executeScript(); try { $conn->commit(); } catch (ConnectionException $e) { $conn->rollBack(); throw $e; } return $result; } } No newline at end of file