-
Notifications
You must be signed in to change notification settings - Fork 26
refactor: migration validation #117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: feature/migration-logging-refactor
Are you sure you want to change the base?
refactor: migration validation #117
Conversation
…r-optional-database-field
…r-optional-database-field
80b2502 to
534d4d1
Compare
| } | ||
|
|
||
| // key points to a list, apply to all items in the list | ||
| if (isset($data[$key]) && \is_array($data[$key]) && \array_is_list($data[$key])) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
example case for this:
entity number_range with converted data like this:
[
'id' => 'uuid'
// ...
'numberRangeSalesChannels' => [
[
// ...
'typeId' => null // (invalid, has to be set)
],
[
'typeId' => null
]
]
]with this solution the fix would be applied for all sub child of numberRangeSalesChannels.
To support individual fixes for sub childs we would have to rebuild quite a lot of the error resolution to a path syntax like parent.sub.[index].property which we currently are not supporting and would cause problems in the ui (because we group by fieldname).
What do you think? Leave it like this or maybe not support it at all for the moment (would mean these entities can not be migrated, like before anyway)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a realistic scenario with the number ranges?
Im fine with this solution but we should make it clear that this will happen to the user with a warning or tooltip
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it just feels not completely right, but it seemed quite common. The problem is that if we don't to this adjustment we ask the user to provide a fix that we actually are not supporting to fix. So we would need new extra logic to prevent them to appear "fixable"
tests/integration/Migration/Validation/MigrationEntityValidationServiceTest.php
Outdated
Show resolved
Hide resolved
…or' into feat/add-validation-of-resolution-values
| /** | ||
| * @param array<int|string, array<int|string, mixed>> $data | ||
| * | ||
| * @throws Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@throws Exception can be removed. In the function is no throw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fetchAllAssociative() inside of loadFixes() can throw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, but normaly annotate exceptions if its realy thrown in the mehtod. So fetchAllAssociative need the @throw tag
| /** | ||
| * Loads fixes from the database and populates them in the context. | ||
| * | ||
| * @throws Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
| */ | ||
| public function apply(array &$item): void | ||
| { | ||
| /* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should keep this I think
| * @param array<string|int, mixed> $data | ||
| * @param array<int, string> $remainingPath | ||
| */ | ||
| private function applyToPath(array &$data, array $remainingPath, mixed $value): void |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe better to call the function param simply $path and set $remainingPath inside the function
| /** | ||
| * Validates that all required fields are present in the converted data. | ||
| * | ||
| * @throws \Exception|Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? Same question for all methods in this class 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i mean technically definitely not, but documenting the most ide's will highlight the usage of the method "this can throw..." and that's not unrelevant for the validation, cause all thrown errors should be catched to create logs / fixes. But I can also live with removing them 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For me, this line resulted in a "Why both \Exception and Exception?" question 😄
nevermind 😅
use Doctrine\DBAL\Exception;
| * @param array<string, mixed>|null $convertedEntity | ||
| * @param array<string, mixed> $sourceData | ||
| * | ||
| * @throws \Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed?
| * Resolves a potentially nested field path (e.g., "prices.shippingMethodId") to its target. | ||
| * Traverses through association fields to find the final entity definition and field. | ||
| * | ||
| * @throws \Exception |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this needed? Same question for the other methods where @throws is used
vintagesucks
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚀🚀🚀
| return new self( | ||
| Response::HTTP_INTERNAL_SERVER_ERROR, | ||
| self::VALIDATION_INVALID_ID, | ||
| 'The id "{{ entityId }}" for entity "{{ entityName }}" is not a valid Uuid', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| 'The id "{{ entityId }}" for entity "{{ entityName }}" is not a valid Uuid', | |
| 'The id "{{ entityId }}" for entity "{{ entityName }}" is not a valid UUID', |
| } | ||
|
|
||
| public function getCode(): string | ||
| { | ||
| return 'SWAG_MIGRATION_VALIDATION_UNEXPECTED_FIELD'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Snippets are still present
| class MigrationEntityValidationService implements ResetInterface | ||
| { | ||
| /** | ||
| * System managed that managed by Shopware and should not be validated as required fields |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| * System managed that managed by Shopware and should not be validated as required fields | |
| * System managed fields are managed by Shopware and should not be validated as required fields |
or
| * System managed that managed by Shopware and should not be validated as required fields | |
| * System managed fields that are managed by Shopware and should not be validated as required fields |
| return value; | ||
| } catch { | ||
| this.error = { | ||
| detail: this.$tc('swag-migration.index.error-resolution.errors.invalidJsonInput'), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Snippets are still present
| : $field->getReferenceDefinition(); | ||
|
|
||
| foreach ($value as $nestedEntityData) { | ||
| $this->validateNestedEntityData( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we not use the same method validateFieldValues here? From the docblocks it seems to me that these two methods do a similar job.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some tests are missing for validating association structures
|
Looks good! Great job! |
Overall refactor of the migration validation behavior. Should lead to much less needed fixes and more accurate / actually fixable errors.
sorry, for the big pr, but refactor was needed 😅. Reach out if I can explain anything and please give me your ideas for better validation!
Changes (file by file)
src/Controller/DataProviderController.php,src/Controller/HistoryController.php,src/Controller/PremappingController.php,src/Controller/StatusController.php:Introduced all common route definition constants to unify with platform
[Added]
src/Controller/ErrorResolutionController.php:Added two new routes:
/error-resolution/validate: provides validation for user created fixes to make sure the fix matches original migration validation/error-resolution/example-field-structure: in case we can not determine the field type in the administration this route provides an example field structure of json association fields, so the user can follow this structure to create a valid fix.src/Migration/ErrorResolution/MigrationErrorResolutionService.php: added missing early return if no fixes could be loaded to avoid event spam and unnecessary code execution[Added]
src/Migration/ErrorResolution/MigrationFieldExampleGenerator.php: the generator used for the example field structure route. It takes in a field and tries to build a accurate example structure for the user[!!!]
src/Migration/ErrorResolution/MigrationFix.php: see the commentsrc/Migration/Mapping/MappingService.php: removed the mapping lookup. We decided to not validate of a given association is actually existing and just validate the given datasrc/Migration/Service/MediaFileProcessorService.php: add where clause to only fetch unprocessed mediasrc/Migration/Service/MigrationDataWriter.php: change to->count()to return number of entities that are processed in the current batch, not the absolute total[!!!]
src/Migration/Validation/MigrationEntityValidationService.php:[!!!]
src/Migration/Validation/MigrationFieldValidationService.php:src/Migration/Validation/MigrationValidationResult.php: added log key generation to avoid multiple log for the same invalidation (avoid multiple fixes for same issue)src/Profile/Shopware/Converter/OrderConverter.php: bug fix (custom field was set tonullbefore, instead of just not adding it to the converted data)src/Resources/app/administration/src/module/swag-migration/component/swag-migration-error-resolution/swag-migration-error-resolution-field/swag-migration-error-resolution-field-scalar/index.ts: added display of error messages that are provides by the validation routesrc/Resources/app/administration/src/module/swag-migration/component/swag-migration-error-resolution/swag-migration-error-resolution-field/swag-migration-error-resolution-field/index.ts: added auto fetch of example field structure in case the admin could not determine a specific field typesrc/Resources/app/administration/src/module/swag-migration/service/swag-migration-error-resolution.service.ts: support of nested field paths and overall simplification