diff --git a/uSync.Core/Extensions/ObjectPropertyExtensions.cs b/uSync.Core/Extensions/ObjectPropertyExtensions.cs new file mode 100644 index 00000000..e7bcc9a2 --- /dev/null +++ b/uSync.Core/Extensions/ObjectPropertyExtensions.cs @@ -0,0 +1,85 @@ +using System.Diagnostics.CodeAnalysis; +using System.Reflection; + +using Umbraco.Extensions; + +namespace uSync.Core.Extensions; + +/// +/// extension methods to get and set properties on objects, using reflection. +/// +public static class ObjectPropertyExtensions +{ + /// + /// Determines whether the specified object contains a public property with the given name. + /// + /// This method uses reflection to examine the object's type at runtime. Frequent use may have + /// performance implications. + /// The object to inspect for the presence of the specified property. Cannot be null. + /// The name of the property to search for. The comparison is case-sensitive. + /// true if the object has a public property with the specified name; otherwise, false. + public static bool HasProperty(this object obj, string propertyName) + => obj.GetType().GetProperty(propertyName) != null; + + /// + /// Retrieves the value of a specified property from the given object, or returns a default value if the property + /// does not exist or cannot be accessed. + /// + /// This method uses reflection to access the property. If the property is not found or cannot be + /// accessed, no exception is thrown and the default value is returned. + /// The type of the property value to retrieve. + /// The object from which to retrieve the property value. Cannot be null. + /// The name of the property whose value is to be retrieved. The search is case-sensitive. + /// The value to return if the specified property does not exist or cannot be accessed. + /// The value of the specified property if it exists and can be accessed; otherwise, the provided default value. + public static T GetPropertyValue(this object obj, string propertyName, T defaultValue) + { + var propertyInfo = obj.GetType().GetProperty(propertyName); + if (propertyInfo == null) return defaultValue; + + return GetPropertyAs(propertyInfo, obj, defaultValue); + } + + /// + /// Sets the value of the specified property on the given object. + /// + /// If the specified property does not exist on the object, the method returns the provided value + /// without making any changes. + /// The type of the value to assign to the property. + /// The object whose property value is to be set. This parameter cannot be null. + /// The name of the property to set. This must correspond to a public property on the object. + /// The value to assign to the specified property. + /// The value that was assigned to the property. + public static T SetPropertyValue(this object obj, string propertyName, T value) + { + var propertyInfo = obj.GetType().GetProperty(propertyName); + if (propertyInfo == null) return value; + propertyInfo.SetValue(obj, value); + return value; + } + + /// + /// Retrieves the value of the specified property and attempts to convert it to the specified type. + /// + /// If the property is not found or the conversion fails, the method returns the default value + /// provided. + /// The type to which the property value is converted. + /// The PropertyInfo object representing the property to retrieve the value from. + /// The object instance from which to retrieve the property value. + /// The value to return if the property is null or cannot be converted to the specified type. + /// The converted value of the property if successful; otherwise, the specified default value. + private static TValue GetPropertyAs(PropertyInfo info, object property, TValue defaultValue) + { + if (info == null) return defaultValue; + + var value = info.GetValue(property); + if (value == null) return defaultValue; + + var result = value.TryConvertTo(); + if (result.Success) + return result.Result ?? defaultValue; + + return defaultValue; + + } +} diff --git a/uSync.Core/Serialization/Serializers/ContentSerializer.cs b/uSync.Core/Serialization/Serializers/ContentSerializer.cs index 53360238..8e269b7b 100644 --- a/uSync.Core/Serialization/Serializers/ContentSerializer.cs +++ b/uSync.Core/Serialization/Serializers/ContentSerializer.cs @@ -24,7 +24,21 @@ public class ContentSerializer : ContentSerializerBase, ISyncSerialize protected readonly IUserService userService; protected readonly ITemplateService _templateService; - protected readonly ISyncDocumentUrlCleaner _urlCleaner; + protected readonly ISyncDocumentUrlCleaner? _urlCleaner; + + [Obsolete("Use the constructor with urlCleaner, will be removed in v19")] + public ContentSerializer( + IEntityService entityService, + ILanguageService languageService, + IRelationService relationService, + IShortStringHelper shortStringHelper, + ILogger logger, + IContentService contentService, + SyncValueMapperCollection syncMappers, + IUserService userService, + ITemplateService templateService + ) : this(entityService, languageService, relationService, shortStringHelper, logger, contentService, syncMappers, userService, templateService, null) + { } public ContentSerializer( IEntityService entityService, @@ -802,7 +816,7 @@ public override Task DeleteItemAsync(IContent item) protected override Task OnKeyChange(IContent item, Guid oldKey, Guid newKey) { // key changes need to clean the DocumentUrl cache. - _urlCleaner.CleanUrlsForDocument(oldKey); + _urlCleaner?.CleanUrlsForDocument(oldKey); return Task.CompletedTask; } } diff --git a/uSync.Extend/readme.md b/uSync.Extend/readme.md index 4e7d84f7..bd325599 100644 --- a/uSync.Extend/readme.md +++ b/uSync.Extend/readme.md @@ -7,6 +7,8 @@ having to write the whole thing from scratch. The extend package contains two base classes that simplfiy Handler and serializer creation for uSync. +Look in the [./Example](./Example) folder for a working example of how to use these base classes to create your own handlers and serializers. + ### SyncObjectHandler In uSync a handler is the thing that controlls the Input/Output of data to and from the file system. its the thing that is called when an item is saved or when uSync exports or imports anything.