Commit d468a735 authored by Bertrand Gauthier's avatar Bertrand Gauthier
Browse files

Possibilité de spécifier la version d'API visée (ex : 'V3') dans la ligne de...

Possibilité de spécifier la version d'API visée (ex : 'V3') dans la ligne de commande update-service-tables
parent d14a1865
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -115,7 +115,7 @@ return [
            'routes' => [
                'update-service-tables' => [
                    'options' => [
                        'route'    => 'update-service-tables [--services=] [--verbose]',
                        'route'    => 'update-service-tables [--services=] [--version=] [--verbose]',
                        'defaults' => [
                            /**
                             * @see ConsoleController::updateServiceTablesAction()
+8 −12
Original line number Diff line number Diff line
@@ -18,23 +18,19 @@ class ConsoleController extends AbstractConsoleController
{
    use LoggerAwareTrait;

    /**
     * @var TableService
     */
    private $tableService;
    private TableService $tableService;

    /**
     * @param TableService $tableService
     */
    public function setTableService(TableService $tableService)
    public function setTableService(TableService $tableService): void
    {
        $this->tableService = $tableService;
    }

    public function updateServiceTablesAction()
    public function updateServiceTablesAction(): void
    {
        /** @var \Unicaen\Console\Request $request */
        $request = $this->getRequest();
        $services = $request->getParam('services');
        $version = $request->getParam('version');
        $verbose = $request->getParam('verbose');

        $priority = $verbose ? Logger::DEBUG : Logger::INFO;
@@ -46,9 +42,9 @@ class ConsoleController extends AbstractConsoleController

        if ($services !== null) {
            $services = explode(',', $services);
            $this->tableService->updateTablesForServices($services);
            $this->tableService->updateTablesForServices($services, $version);
        } else {
            $this->tableService->updateTablesForAllServices();
            $this->tableService->updateTablesForAllServices($version);
        }

        $this->logger->info("Terminé.");
+7 −1
Original line number Diff line number Diff line
@@ -14,7 +14,7 @@ class Module
    public function getConsoleUsage(Console $console)
    {
        return [
            'update-service-tables [--services=] [--verbose]' =>
            'update-service-tables [--services=] [--version] [--verbose]' =>
                "Mettre à jour les données des tables sources des services.",
            [
                '--services',
@@ -22,6 +22,12 @@ class Module
                "Liste des services concernés séparés par des virgules. " . PHP_EOL .
                "Ex: 'structure,etablissement,unite-rech,ecole-doct'",
            ],
            [
                '--version',
                "Facultatif. " . PHP_EOL .
                "Version d'API concernée. " . PHP_EOL .
                "Ex: 'V2'",
            ],
            [
                '--verbose',
                "Facultatif. " . PHP_EOL .
+61 −69
Original line number Diff line number Diff line
@@ -2,11 +2,12 @@

namespace Application\Service;

use Doctrine\DBAL\ConnectionException;
use Doctrine\DBAL\DBALException;
use Doctrine\DBAL\Exception;
use Doctrine\ORM\EntityManager;
use RuntimeException;
use Laminas\Log\LoggerAwareTrait;
use LogicException;
use RuntimeException;
use Webmozart\Assert\Assert;

class TableService
{
@@ -15,62 +16,42 @@ class TableService
    const DELETE_TEMPLATE = "delete from %s ;";
    const INSERT_TEMPLATE = "insert into %s (%s) select %s from V_%s ;";

    /**
     * @var EntityManager
     */
    private $entityManager;

    /**
     * @var array
     */
    private $servicesToEntityClassesConfig;

    /**
     * @var array
     */
    private $servicesPreSql = [];
    private EntityManager $entityManager;
    private array $servicesToEntityClassesConfig;
    private array $servicesPreSql = [];

    /**
     * Liste des colonnes à exclure lors de la mise à jour des tables sources.
     *
     * @var array
     */
    private $excludedColumnNames = [
    private array $excludedColumnNames = [
        'SOURCE_INSERT_DATE',
    ];

    /**
     * @param EntityManager $entityManager
     */
    public function setEntityManager(EntityManager $entityManager)
    public function setEntityManager(EntityManager $entityManager): void
    {
        $this->entityManager = $entityManager;
    }

    /**
     * @param array $servicesToEntityClassesConfig
     */
    public function setServicesToEntityClassesConfig(array $servicesToEntityClassesConfig)
    public function setServicesToEntityClassesConfig(array $servicesToEntityClassesConfig): void
    {
        $this->servicesToEntityClassesConfig = $servicesToEntityClassesConfig;
    }

    /**
     * @param array $servicesPreSql
     */
    public function setServicesPreSql(array $servicesPreSql)
    public function setServicesPreSql(array $servicesPreSql): void
    {
        $this->servicesPreSql = $servicesPreSql;
    }

    /**
     * Lance la mise à jour des tables sources pour tous les services.
     *
     * @param string|null $version Version d'API concernée éventuelle, ex : 'V2'
     */
    public function updateTablesForAllServices()
    public function updateTablesForAllServices(?string $version = null): void
    {
        $services = array_keys($this->servicesToEntityClassesConfig);

        $this->updateTablesForServices($services);
        $this->updateTablesForServices($services, $version);
    }

    /**
@@ -78,23 +59,24 @@ class TableService
     *
     * @param array $services Liste des noms de services dont on veut mettre à jour les tables sources.
     * Exemple : ['structure', 'etablissement']
     * @param string|null $version Version d'API concernée éventuelle, ex : 'V2'
     */
    public function updateTablesForServices(array $services)
    public function updateTablesForServices(array $services, ?string $version = null): void
    {
        $conn = $this->entityManager->getConnection();
        $sql = $this->generateSQLUpdatesForServices($services);
        $sql = $this->generateSQLUpdatesForServices($services, $version);

        $this->logger->debug("SQL généré : " . $sql);

        $conn->beginTransaction();
        try {
            $conn->beginTransaction();
            $conn->executeQuery($sql);
            $conn->commit();
        } catch (DBALException $e) {
        } catch (Exception $e) {
            $message = "Erreur lors de la requête SQL de mise à jour des tables";
            try {
                $conn->rollBack();
            } catch (ConnectionException $e) {
            } catch (Exception $e) {
                $message .= " et en plus rollback impossible";
                $this->logger->err($message);
                throw new RuntimeException($message, null, $e);
@@ -110,32 +92,21 @@ class TableService
    }

    /**
     * Génère le SQL permettant de mettre à jour le contenu des tables sources pour les services spécifiés.
     * Génère le SQL permettant de màj le contenu des tables sources pour les services et la version spécifiés.
     *
     * @param array $services Liste des noms de services dont on veut mettre à jour les tables sources.
     * Exemple : ['structure', 'etablissement']
     * @param array $services Liste des noms de services dont on veut mettre à jour les tables sources,
     * ex : ['structure', 'etablissement']
     * @param string|null $version Version d'API concernée éventuelle, ex : 'V2'
     *
     * @return string SQL généré, exemple :
     * <pre>
     * begin
     * delete from SYGAL_STRUCTURE ;
     * insert into SYGAL_STRUCTURE (SOURCE_ID, ...) select SOURCE_ID, ... from V_SYGAL_STRUCTURE ;
     * delete from SYGAL_STRUCTURE_V2 ;
     * insert into SYGAL_STRUCTURE_V2 (SOURCE_CODE, ...) select SOURCE_CODE, ... from V_SYGAL_STRUCTURE_V2 ;
     * delete from SYGAL_ETABLISSEMENT
     * insert into SYGAL_ETABLISSEMENT (SOURCE_ID, ...) select SOURCE_ID, ... from V_SYGAL_ETABLISSEMENT ;
     * delete from SYGAL_ETABLISSEMENT_V2 ;
     * insert into SYGAL_ETABLISSEMENT_V2 (SOURCE_CODE, ...) select SOURCE_CODE, ... from V_SYGAL_ETABLISSEMENT_V2 ;
     * end;
     * </pre>
     * @return string SQL généré
     */
    private function generateSQLUpdatesForServices(array $services): string
    private function generateSQLUpdatesForServices(array $services, ?string $version = null): string
    {
        $sqlParts = [];

        $sqlParts[] = 'begin';
        foreach ($services as $service) {
            $sqlParts[] = $this->generateSQLUpdatesForService($service);
            $sqlParts[] = $this->generateSQLUpdatesForServiceAndVersion($service, $version);
        }
        $sqlParts[] = 'end;';

@@ -143,20 +114,20 @@ class TableService
    }

    /**
     * Génère le SQL permettant de mettre à jour le contenu des tables sources pour un service.
     * Génère le SQL permettant de mettre à jour le contenu de la table source pour un service et une version donnés.
     *
     * @param string $service Nom du service dont on veut mettre à jour les tables sources.
     * Exemple : 'structure'
     * @param string $service Nom du service dont on veut màj la table source, ex : 'these', 'titre-acces'
     * @param string|null $version Version d'API concernée éventuelle, ex : 'V2'
     *
     * @return string SQL généré, exemple :
     * <pre>
     * delete from SYGAL_STRUCTURE ;
     * insert into SYGAL_STRUCTURE (SOURCE_ID, ...) select SOURCE_ID, ... from V_SYGAL_STRUCTURE ;
     * delete from SYGAL_STRUCTURE_V2 ;
     * insert into SYGAL_STRUCTURE_V2 (SOURCE_CODE, ...) select SOURCE_CODE, ... from V_SYGAL_STRUCTURE_V2 ;
     * delete from SYGAL_ETABLISSEMENT_V2 ;
     * insert into SYGAL_ETABLISSEMENT_V2 (SOURCE_CODE, ...) select SOURCE_CODE, ... from V_SYGAL_ETABLISSEMENT_V2 ;
     * </pre>
     */
    private function generateSQLUpdatesForService(string $service): string
    private function generateSQLUpdatesForServiceAndVersion(string $service, ?string $version = null): string
    {
        $sqlParts = [];

@@ -165,7 +136,7 @@ class TableService
            $sqlParts[] = $this->servicesPreSql[$service];
        }

        $classNames = $this->getEntityClassNamesForService($service);
        $classNames = $this->getEntityClassNamesForServiceAndVersion($service, $version);
        // NB : Il y a une classe d'entité Doctrine par version de l'API.

        foreach ($classNames as $className) {
@@ -185,18 +156,39 @@ class TableService
    }

    /**
     * Retourne les classes d'entité Doctrine correspondant au service spécifié.
     * Retourne les classes d'entité Doctrine correspondant au service et à la version spécifiés.
     * NB : Il y a une classe par version de l'API.
     *
     * @param string $service
     * @param string $service Nom du service, ex : 'these', 'titre-acces'
     * @param string|null $version Version d'API concernée éventuelle, ex : 'V1', 'V2', 'V3'
     *
     * @return array
     */
    private function getEntityClassNamesForService(string $service): array
    private function getEntityClassNamesForServiceAndVersion(string $service, ?string $version = null): array
    {
        if (! isset($this->servicesToEntityClassesConfig[$service])) {
            throw new \LogicException("Service inconnu : '$service'");
            throw new LogicException("Service inconnu : '$service'");
        }

        if ($version !== null) {
            $classMatchesVersion = fn(string $fqdn) => str_contains($fqdn, sprintf("\\%s\\", $version));
            $entityClasses = array_filter($this->servicesToEntityClassesConfig[$service], $classMatchesVersion);

            Assert::notEmpty($entityClasses, sprintf(
                "Aucune classe d'entité trouvée dans la config pour le service '%s' et la version '%s'.",
                $service,
                $version
            ));
            Assert::count($entityClasses, 1, sprintf(
                "Plus d'1 classe d'entité trouvée dans la config pour le service '%s' et la version '%s'.",
                $service,
                $version
            ));

            return $entityClasses;
        }

        return $this->servicesToEntityClassesConfig[$service];
        // on prend la dernière ligne, sensée correspondre à la version la plus récente de l'API
        return array_slice($this->servicesToEntityClassesConfig[$service], -1);
    }
}