From b5fd9cf4afc27b72824da5d7c4a5d94ba87e6ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julien=20Fastr=C3=A9?= Date: Sat, 5 Apr 2025 00:35:16 +0200 Subject: [PATCH] Add SavedExportOptionsMigrator for migrating export options Introduced SavedExportOptionsMigrator to handle the migration of saved export options with structures ensuring versioning. Added unit tests to validate transformation logic and edge cases for better reliability. --- .../Migrator/SavedExportOptionsMigrator.php | 124 ++++ .../SavedExportOptionsMigratorTest.php | 586 ++++++++++++++++++ .../migrations/Version20250404123326.php | 49 ++ 3 files changed, 759 insertions(+) create mode 100644 src/Bundle/ChillMainBundle/Export/Migrator/SavedExportOptionsMigrator.php create mode 100644 src/Bundle/ChillMainBundle/Tests/Export/Migrator/SavedExportOptionsMigratorTest.php create mode 100644 src/Bundle/ChillMainBundle/migrations/Version20250404123326.php diff --git a/src/Bundle/ChillMainBundle/Export/Migrator/SavedExportOptionsMigrator.php b/src/Bundle/ChillMainBundle/Export/Migrator/SavedExportOptionsMigrator.php new file mode 100644 index 000000000..1e6570b55 --- /dev/null +++ b/src/Bundle/ChillMainBundle/Export/Migrator/SavedExportOptionsMigrator.php @@ -0,0 +1,124 @@ + array_map( + self::mapFormData(...), + array_filter( + $fromOptions['export']['export']['export'] ?? [], + static fn (string $key) => !in_array($key, ['filters', 'aggregators', 'pick_formatter'], true), + ARRAY_FILTER_USE_KEY, + ), + ), + 'version' => 1, + ]; + + $to['pick_formatter'] = $fromOptions['export']['export']['pick_formatter']['alias'] ?? null; + $to['centers'] = [ + 'centers' => array_values(array_map(static fn ($id) => (int) $id, $fromOptions['centers']['centers']['c'] ?? $fromOptions['centers']['centers']['center'] ?? [])), + 'regroupments' => array_values(array_map(static fn ($id) => (int) $id, $fromOptions['centers']['centers']['regroupment'] ?? [])), + ]; + $to['formatter'] = [ + 'form' => $fromOptions['formatter']['formatter'] ?? [], + 'version' => 1, + ]; + + return $to; + } + + private static function mapEnabledStatus(array $modifiersData): array + { + if ('1' === ($modifiersData['enabled'] ?? '0')) { + return [ + 'form' => array_map(self::mapFormData(...), $modifiersData['form'] ?? []), + 'version' => 1, + 'enabled' => true, + ]; + } + + return ['enabled' => false]; + } + + private static function mapFormData(array|string $formData): array|string|null + { + if (is_array($formData) && array_key_exists('roll', $formData)) { + return self::refactorRollingDate($formData); + } + + if (is_string($formData)) { + // we try different date formats + if (false !== \DateTimeImmutable::createFromFormat('d-m-Y', $formData)) { + return $formData; + } + if (false !== \DateTimeImmutable::createFromFormat('Y-m-d', $formData)) { + return $formData; + } + + // we try json content + try { + $data = json_decode($formData, true, 512, JSON_THROW_ON_ERROR); + + if (is_array($data)) { + if (array_key_exists('type', $data) && array_key_exists('id', $data) && in_array($data['type'], ['person', 'thirdParty', 'user'], true)) { + return $data['id']; + } + $response = []; + foreach ($data as $item) { + if (array_key_exists('type', $item) && array_key_exists('id', $item) && in_array($item['type'], ['person', 'thirdParty', 'user'], true)) { + $response[] = $item['id']; + } + } + if ([] !== $response) { + return $response; + } + } + } catch (\JsonException $e) { + return $formData; + } + } + + return $formData; + } + + private static function refactorRollingDate(array $formData): ?array + { + if ('' === $formData['roll']) { + return null; + } + + $fixedDate = null !== ($formData['fixedDate'] ?? null) ? + \DateTimeImmutable::createFromFormat('Y-m-d H:i:s', sprintf('%s 00:00:00', $formData['fixedDate']), new \DateTimeZone(date_default_timezone_get())) : null; + + return (new RollingDate( + $formData['roll'], + $fixedDate, + ))->normalize(); + } +} diff --git a/src/Bundle/ChillMainBundle/Tests/Export/Migrator/SavedExportOptionsMigratorTest.php b/src/Bundle/ChillMainBundle/Tests/Export/Migrator/SavedExportOptionsMigratorTest.php new file mode 100644 index 000000000..6cfa21faa --- /dev/null +++ b/src/Bundle/ChillMainBundle/Tests/Export/Migrator/SavedExportOptionsMigratorTest.php @@ -0,0 +1,586 @@ +addSql('ALTER TABLE chill_main_saved_export ADD COLUMN options_backup JSONB default \'[]\''); + $this->addSql('UPDATE chill_main_saved_export SET options_backup = options'); + + $result = $this->connection->executeQuery('SELECT id, options FROM chill_main_saved_export'); + + foreach ($result->iterateAssociative() as $row) { + $options = json_decode($row['options'], true, 512, JSON_THROW_ON_ERROR); + $this->addSql( + 'UPDATE chill_main_saved_export SET options = :new_options WHERE id = :id', + ['id' => $row['id'], 'new_options' => SavedExportOptionsMigrator::migrate($options)], + ['id' => Types::STRING, 'new_options' => Types::JSON], + ); + } + + } + + public function down(Schema $schema): void + { + $this->addSql('UPDATE chill_main_saved_export SET options = options_backup'); + $this->addSql('ALTER TABLE chill_main_saved_export DROP COLUMN options_backup'); + } +}