diff --git a/KVA/Migration.Tool.Source/Mappers/ContentItemMapper.cs b/KVA/Migration.Tool.Source/Mappers/ContentItemMapper.cs index 231259b6..eab7a346 100644 --- a/KVA/Migration.Tool.Source/Mappers/ContentItemMapper.cs +++ b/KVA/Migration.Tool.Source/Mappers/ContentItemMapper.cs @@ -522,7 +522,7 @@ IClassMapping mapping foreach (string targetColumnName in newColumnNames) { string targetFieldName = null!; - Func valueConvertor = sourceValue => sourceValue; + Func valueConvertor = (sourceValue, _) => sourceValue; switch (mapping?.GetMapping(targetColumnName, sourceNodeClass.ClassName)) { case FieldMappingWithConversion fieldMappingWithConversion: @@ -534,13 +534,13 @@ IClassMapping mapping case FieldMapping fieldMapping: { targetFieldName = fieldMapping.TargetFieldName; - valueConvertor = sourceValue => sourceValue; + valueConvertor = (sourceValue, _) => sourceValue; break; } case null: { targetFieldName = targetColumnName; - valueConvertor = sourceValue => sourceValue; + valueConvertor = (sourceValue, _) => sourceValue; break; } @@ -587,7 +587,8 @@ IClassMapping mapping string? controlName = field.Settings[CLASS_FIELD_CONTROL_NAME]?.ToString()?.ToLowerInvariant(); object? sourceValue = getSourceValue(sourceFieldName); - target[targetFieldName] = valueConvertor.Invoke(sourceValue); + var convertorContext = new ConvertorTreeNodeContext(cmsTree.NodeGUID, cmsTree.NodeSiteID, documentId, migratingFromVersionHistory); + target[targetFieldName] = valueConvertor.Invoke(sourceValue, convertorContext); var fvmc = new FieldMigrationContext(field.DataType, controlName, targetColumnName, new DocumentSourceObjectContext(cmsTree, sourceNodeClass, site, oldFormInfo, newFormInfo, documentId)); var fmb = fieldMigrationService.GetFieldMigration(fvmc); if (fmb is FieldMigration fieldMigration) @@ -600,12 +601,12 @@ IClassMapping mapping var convertedRelation = relationshipService.GetNodeRelationships(cmsTree.NodeID, sourceNodeClass.ClassName, field.Guid) .Select(r => new WebPageRelatedItem { WebPageGuid = spoiledGuidContext.EnsureNodeGuid(r.RightNode.NodeGUID, r.RightNode.NodeSiteID, r.RightNode.NodeID) }); - target.SetValueAsJson(targetFieldName, valueConvertor.Invoke(convertedRelation)); + target.SetValueAsJson(targetFieldName, valueConvertor.Invoke(convertedRelation, convertorContext)); } else { // leave as is - target[targetFieldName] = valueConvertor.Invoke(sourceValue); + target[targetFieldName] = valueConvertor.Invoke(sourceValue, convertorContext); } if (fieldMigration.TargetFormComponent == "webpages") @@ -622,13 +623,13 @@ IClassMapping mapping } } - target[targetFieldName] = valueConvertor.Invoke(parsed.ToString().Replace("\"NodeGuid\"", "\"WebPageGuid\"")); + target[targetFieldName] = valueConvertor.Invoke(parsed.ToString().Replace("\"NodeGuid\"", "\"WebPageGuid\""), convertorContext); } } } else { - target[targetFieldName] = valueConvertor.Invoke(sourceValue); + target[targetFieldName] = valueConvertor.Invoke(sourceValue, convertorContext); } } else if (fmb != null) @@ -637,7 +638,7 @@ IClassMapping mapping { case { Success: true } result: { - target[targetFieldName] = valueConvertor.Invoke(result.MigratedValue); + target[targetFieldName] = valueConvertor.Invoke(result.MigratedValue, convertorContext); break; } case { Success: false }: @@ -652,7 +653,7 @@ IClassMapping mapping } else { - target[targetFieldName] = valueConvertor?.Invoke(sourceValue); + target[targetFieldName] = valueConvertor?.Invoke(sourceValue, convertorContext); } diff --git a/Migration.Tool.Common/Builders/ClassMapper.cs b/Migration.Tool.Common/Builders/ClassMapper.cs index 818d618c..6e3ff67a 100644 --- a/Migration.Tool.Common/Builders/ClassMapper.cs +++ b/Migration.Tool.Common/Builders/ClassMapper.cs @@ -32,7 +32,7 @@ public interface IFieldMapping public record FieldMapping(string TargetFieldName, string SourceClassName, string SourceFieldName, bool IsTemplate) : IFieldMapping; -public record FieldMappingWithConversion(string TargetFieldName, string SourceClassName, string SourceFieldName, bool IsTemplate, Func Converter) : IFieldMapping; +public record FieldMappingWithConversion(string TargetFieldName, string SourceClassName, string SourceFieldName, bool IsTemplate, Func Converter) : IFieldMapping; public class MultiClassMapping(string targetClassName, Action classPatcher) : IClassMapping { @@ -93,6 +93,9 @@ public void UseResusableSchema(string reusableSchemaName) IList IClassMapping.ReusableSchemaNames => reusableSchemaNames; } +public interface IConvertorContext; +public record ConvertorTreeNodeContext(Guid NodeGuid, int NodeSiteId, int? DocumentId, bool MigratingFromVersionHistory): IConvertorContext; + public class FieldBuilder(MultiClassMapping multiClassMapping, string targetFieldName) { private IFieldMapping? currentFieldMapping; @@ -105,7 +108,7 @@ public FieldBuilder SetFrom(string sourceClassName, string sourceFieldName, bool return this; } - public FieldBuilder ConvertFrom(string sourceClassName, string sourceFieldName, bool isTemplate, Func converter) + public FieldBuilder ConvertFrom(string sourceClassName, string sourceFieldName, bool isTemplate, Func converter) { currentFieldMapping = new FieldMappingWithConversion(targetFieldName, sourceClassName, sourceFieldName, isTemplate, converter); multiClassMapping.Mappings.Add(currentFieldMapping); diff --git a/Migration.Tool.Extensions/ClassMappings/ClassMappingSample.cs b/Migration.Tool.Extensions/ClassMappings/ClassMappingSample.cs index fa0c0026..383f033d 100644 --- a/Migration.Tool.Extensions/ClassMappings/ClassMappingSample.cs +++ b/Migration.Tool.Extensions/ClassMappings/ClassMappingSample.cs @@ -168,8 +168,18 @@ public static IServiceCollection AddClassMergeExample(this IServiceCollection se startDate.SetFrom(sourceClassName1, "EventDateStart", true); // if needed use value conversion to adapt value startDate.ConvertFrom(sourceClassName2, "EventStartDateAsText", false, - v => v?.ToString() is { } av && !string.IsNullOrWhiteSpace(av) ? DateTime.Parse(av) : null - ); + (v, context) => + { + if (context is ConvertorTreeNodeContext(var nodeGuid, var nodeSiteId, var documentId, var migratingFromVersionHistory)) + { + // here you can use available treenode context + } + else + { + // no context is available (possibly when tool is extended with other conversion possibilities) + } + return v?.ToString() is { } av && !string.IsNullOrWhiteSpace(av) ? DateTime.Parse(av) : null; + }); startDate.WithFieldPatch(f => f.Caption = "Event start date"); serviceCollection.AddSingleton(m);