diff --git a/src/Umbraco.Core/Models/PublishedContent/IPublishedContentModelFactory.cs b/src/Umbraco.Core/Models/PublishedContent/IPublishedContentModelFactory.cs index 3e8edd4b74..7eb8909878 100644 --- a/src/Umbraco.Core/Models/PublishedContent/IPublishedContentModelFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/IPublishedContentModelFactory.cs @@ -1,25 +1,27 @@ -namespace Umbraco.Core.Models.PublishedContent +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.Models.PublishedContent { /// /// Provides the model creation service. /// - public interface IPublishedContentModelFactory + public interface IPublishedContentModelFactory // fixme rename IFacadeModelFactory { /// - /// Creates a strongly-typed model representing a published content. + /// Creates a strongly-typed model representing a property set. /// - /// The original published content. - /// The strongly-typed model representing the published content, or the published content + /// The original property set. + /// The strongly-typed model representing the property set, or the property set /// itself it the factory has no model for that content type. - IPublishedContent CreateModel(IPublishedContent content); + IPropertySet CreateModel(IPropertySet set); - // temp - dont break MB - //T CreateModel(IPublishedFragment content); + /// + /// Gets the model type map. + /// + Dictionary ModelTypeMap { get; } // fixme - // and we'd need a - // PublishedContentModel = ContentModel : ContentWrapper - // PublishedFragmentModel = FragmentModel : FragmentWrapper // // ModelFactory.Meta.Model("thing").ClrType (find the our post?) // diff --git a/src/Umbraco.Core/Models/PublishedContent/ModelType.cs b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs new file mode 100644 index 0000000000..93ba2e1788 --- /dev/null +++ b/src/Umbraco.Core/Models/PublishedContent/ModelType.cs @@ -0,0 +1,296 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Reflection; + +namespace Umbraco.Core.Models.PublishedContent +{ + // create a simple model type: + // ModelType.For("alias") + // use in a generic type: + // typeof (IEnumerable<>).MakeGenericType(ModelType.For("alias")) + // use in an array: + // ModelType.For("alias").MakeArrayType() + + public class ModelType : Type + { + private ModelType(string contentTypeAlias) + { + ContentTypeAlias = contentTypeAlias; + Name = "{" + ContentTypeAlias + "}"; + } + + public string ContentTypeAlias { get; } + + public override string ToString() + => Name; + + public static ModelType For(string alias) + => new ModelType(alias); + + public static Type Map(Type type, Dictionary modelTypes) + { + if (type is ModelType modelType) + { + if (modelTypes.TryGetValue(modelType.ContentTypeAlias, out Type actualType)) + return actualType; + throw new InvalidOperationException($"Don't know how to map ModelType with content type alias \"{modelType.ContentTypeAlias}\"."); + } + + if (type is ModelTypeArrayType arrayType) + { + if (modelTypes.TryGetValue(arrayType.ContentTypeAlias, out Type actualType)) + return actualType.MakeArrayType(); + throw new InvalidOperationException($"Don't know how to map ModelType with content type alias \"{arrayType.ContentTypeAlias}\"."); + } + + if (type.IsGenericType == false) + return type; + + var args = type.GetGenericArguments().Select(x => Map(x, modelTypes)).ToArray(); + + return type.GetGenericTypeDefinition().MakeGenericType(args); + } + + public static bool Equals(Type t1, Type t2) + { + if (t1 == t2) + return true; + + if (t1 is ModelType m1 && t2 is ModelType m2) + return m1.ContentTypeAlias == m2.ContentTypeAlias; + + if (t1 is ModelTypeArrayType a1 && t2 is ModelTypeArrayType a2) + return a1.ContentTypeAlias == a2.ContentTypeAlias; + + if (t1.IsGenericType == false || t2.IsGenericType == false) + return false; + + var args1 = t1.GetGenericArguments(); + var args2 = t2.GetGenericArguments(); + if (args1.Length != args2.Length) return false; + + for (var i = 0; i < args1.Length; i++) + { + // ReSharper disable once CheckForReferenceEqualityInstead.2 + if (Equals(args1[i], args2[i]) == false) return false; + } + + return true; + } + + protected override TypeAttributes GetAttributeFlagsImpl() + => TypeAttributes.Class; + + public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) + => Array.Empty(); + + protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) + => null; + + public override Type[] GetInterfaces() + => Array.Empty(); + + public override Type GetInterface(string name, bool ignoreCase) + => null; + + public override EventInfo[] GetEvents(BindingFlags bindingAttr) + => Array.Empty(); + + public override EventInfo GetEvent(string name, BindingFlags bindingAttr) + => null; + + public override Type[] GetNestedTypes(BindingFlags bindingAttr) + => Array.Empty(); + + public override Type GetNestedType(string name, BindingFlags bindingAttr) + => null; + + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) + => Array.Empty(); + + protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) + => null; + + public override MethodInfo[] GetMethods(BindingFlags bindingAttr) + => Array.Empty(); + + protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) + => null; + + public override FieldInfo[] GetFields(BindingFlags bindingAttr) + => Array.Empty(); + + public override FieldInfo GetField(string name, BindingFlags bindingAttr) + => null; + + public override MemberInfo[] GetMembers(BindingFlags bindingAttr) + => Array.Empty(); + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + => Array.Empty(); + + public override object[] GetCustomAttributes(bool inherit) + => Array.Empty(); + + public override bool IsDefined(Type attributeType, bool inherit) + => false; + + public override Type GetElementType() + => null; + + protected override bool HasElementTypeImpl() + => false; + + protected override bool IsArrayImpl() + => false; + + protected override bool IsByRefImpl() + => false; + + protected override bool IsPointerImpl() + => false; + + protected override bool IsPrimitiveImpl() + => false; + + protected override bool IsCOMObjectImpl() + => false; + + public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) + { + throw new NotSupportedException(); + } + + public override Type UnderlyingSystemType => this; + public override Type BaseType => null; + + public override string Name { get; } + public override Guid GUID { get; } = Guid.NewGuid(); + public override Module Module => throw new NotSupportedException(); + public override Assembly Assembly => throw new NotSupportedException(); + public override string FullName => Name; + public override string Namespace => string.Empty; + public override string AssemblyQualifiedName => Name; + + public override Type MakeArrayType() + { + return new ModelTypeArrayType(this); + } + } + + internal class ModelTypeArrayType : Type + { + private readonly Type _elementType; + + public ModelTypeArrayType(ModelType type) + { + _elementType = type; + ContentTypeAlias = type.ContentTypeAlias; + Name = "{" + type.ContentTypeAlias + "}[*]"; + } + + public string ContentTypeAlias { get; } + + public override string ToString() + => Name; + + protected override TypeAttributes GetAttributeFlagsImpl() + => TypeAttributes.Class; + + public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) + => Array.Empty(); + + protected override ConstructorInfo GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) + => null; + + public override Type[] GetInterfaces() + => Array.Empty(); + + public override Type GetInterface(string name, bool ignoreCase) + => null; + + public override EventInfo[] GetEvents(BindingFlags bindingAttr) + => Array.Empty(); + + public override EventInfo GetEvent(string name, BindingFlags bindingAttr) + => null; + + public override Type[] GetNestedTypes(BindingFlags bindingAttr) + => Array.Empty(); + + public override Type GetNestedType(string name, BindingFlags bindingAttr) + => null; + + public override PropertyInfo[] GetProperties(BindingFlags bindingAttr) + => Array.Empty(); + + protected override PropertyInfo GetPropertyImpl(string name, BindingFlags bindingAttr, Binder binder, Type returnType, Type[] types, ParameterModifier[] modifiers) + => null; + + public override MethodInfo[] GetMethods(BindingFlags bindingAttr) + => Array.Empty(); + + protected override MethodInfo GetMethodImpl(string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers) + => null; + + public override FieldInfo[] GetFields(BindingFlags bindingAttr) + => Array.Empty(); + + public override FieldInfo GetField(string name, BindingFlags bindingAttr) + => null; + + public override MemberInfo[] GetMembers(BindingFlags bindingAttr) + => Array.Empty(); + + public override object[] GetCustomAttributes(Type attributeType, bool inherit) + => Array.Empty(); + + public override object[] GetCustomAttributes(bool inherit) + => Array.Empty(); + + public override bool IsDefined(Type attributeType, bool inherit) + => false; + + public override Type GetElementType() + => _elementType; + + protected override bool HasElementTypeImpl() + => true; + + protected override bool IsArrayImpl() + => true; + + protected override bool IsByRefImpl() + => false; + + protected override bool IsPointerImpl() + => false; + + protected override bool IsPrimitiveImpl() + => false; + + protected override bool IsCOMObjectImpl() + => false; + + public override object InvokeMember(string name, BindingFlags invokeAttr, Binder binder, object target, object[] args, ParameterModifier[] modifiers, CultureInfo culture, string[] namedParameters) + { + throw new NotSupportedException(); + } + + public override Type UnderlyingSystemType => this; + public override Type BaseType => null; + + public override string Name { get; } + public override Guid GUID { get; } = Guid.NewGuid(); + public override Module Module => throw new NotSupportedException(); + public override Assembly Assembly => throw new NotSupportedException(); + public override string FullName => Name; + public override string Namespace => string.Empty; + public override string AssemblyQualifiedName => Name; + + public override int GetArrayRank() + => 1; + } +} diff --git a/src/Umbraco.Core/Models/PublishedContent/NoopPublishedContentModelFactory.cs b/src/Umbraco.Core/Models/PublishedContent/NoopPublishedContentModelFactory.cs index 965c01aae3..16cd3a69d1 100644 --- a/src/Umbraco.Core/Models/PublishedContent/NoopPublishedContentModelFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/NoopPublishedContentModelFactory.cs @@ -1,15 +1,13 @@ -namespace Umbraco.Core.Models.PublishedContent +using System; +using System.Collections.Generic; + +namespace Umbraco.Core.Models.PublishedContent { public class NoopPublishedContentModelFactory : IPublishedContentModelFactory { - public IPublishedContent CreateModel(IPublishedContent content) - { - return content; - } + public IPropertySet CreateModel(IPropertySet set) + => set; - public T CreateModel(IPropertySet content) - { - throw new System.NotImplementedException(); - } + public Dictionary ModelTypeMap { get; } = new Dictionary(); } } diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs index 6f293a5dc6..3eca9f025d 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentExtensionsForModels.cs @@ -22,9 +22,14 @@ namespace Umbraco.Core.Models.PublishedContent // if factory returns nothing, throw var model = Current.PublishedContentModelFactory.CreateModel(content); if (model == null) - throw new Exception("IPublishedContentFactory returned null."); + throw new Exception("Factory returned null."); - return model; + // if factory returns a different type, throw + var publishedContent = model as IPublishedContent; + if (publishedContent == null) + throw new Exception($"Factory returned model of type {model.GetType().FullName} which does not implement IPublishedContent."); + + return publishedContent; } } } diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedContentModelFactory.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedContentModelFactory.cs index d2c5507fc8..c04aa7116a 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedContentModelFactory.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedContentModelFactory.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; -using System.Linq.Expressions; +using System.Reflection; +using System.Reflection.Emit; namespace Umbraco.Core.Models.PublishedContent { @@ -9,10 +10,16 @@ namespace Umbraco.Core.Models.PublishedContent /// public class PublishedContentModelFactory : IPublishedContentModelFactory { - //private readonly Dictionary _constructors - // = new Dictionary(); + private readonly Dictionary _modelInfos; - private readonly Dictionary> _constructors; + private class ModelInfo + { + public Type ParameterType { get; set; } + public Func Ctor { get; set; } + public Type ModelType { get; set; } + } + + public Dictionary ModelTypeMap { get; } /// /// Initializes a new instance of the class with types. @@ -30,61 +37,79 @@ namespace Umbraco.Core.Models.PublishedContent /// public PublishedContentModelFactory(IEnumerable types) { - var ctorArgTypes = new[] { typeof(IPublishedContent) }; - var constructors = new Dictionary>(StringComparer.InvariantCultureIgnoreCase); + var ctorArgTypes = new[] { typeof(IPropertySet) }; + var modelInfos = new Dictionary(StringComparer.InvariantCultureIgnoreCase); + + ModelTypeMap = new Dictionary(StringComparer.InvariantCultureIgnoreCase); foreach (var type in types) { - var constructor = type.GetConstructor(ctorArgTypes); + ConstructorInfo constructor = null; + Type parameterType = null; + + foreach (var ctor in type.GetConstructors()) + { + var parms = ctor.GetParameters(); + if (parms.Length == 1 && typeof (IPropertySet).IsAssignableFrom(parms[0].ParameterType)) + { + if (constructor != null) + throw new InvalidOperationException($"Type {type.FullName} has more than one public constructor with one argument of type, or implementing, IPropertySet."); + constructor = ctor; + parameterType = parms[0].ParameterType; + } + } + if (constructor == null) - throw new InvalidOperationException($"Type {type.FullName} is missing a public constructor with one argument of type IPublishedContent."); - var attribute = type.GetCustomAttribute(false); + throw new InvalidOperationException($"Type {type.FullName} is missing a public constructor with one argument of type, or implementing, IPropertySet."); + + var attribute = type.GetCustomAttribute(false); // fixme rename FacadeModelAttribute var typeName = attribute == null ? type.Name : attribute.ContentTypeAlias; - if (constructors.ContainsKey(typeName)) - throw new InvalidOperationException($"More that one type want to be a model for content type {typeName}."); + if (modelInfos.TryGetValue(typeName, out ModelInfo modelInfo)) + throw new InvalidOperationException($"Both types {type.FullName} and {modelInfo.ModelType.FullName} want to be a model type for content type with alias \"{typeName}\"."); - // should work everywhere, but slow - //_constructors[typeName] = constructor; + // see Umbraco.Tests.Benchmarks.CtorInvokeBenchmarks + // using ctor.Invoke is horrible, cannot even consider it, + // then expressions are 6-10x slower than direct ctor, and + // dynamic methods are 2-3x slower than direct ctor = best - // much faster with a dynamic method but potential MediumTrust issues + // much faster with a dynamic method but potential MediumTrust issues - which we don't support // here http://stackoverflow.com/questions/16363838/how-do-you-call-a-constructor-via-an-expression-tree-on-an-existing-object + var meth = new DynamicMethod(string.Empty, typeof(IPropertySet), ctorArgTypes, type.Module, true); + var gen = meth.GetILGenerator(); + gen.Emit(OpCodes.Ldarg_0); + gen.Emit(OpCodes.Newobj, constructor); + gen.Emit(OpCodes.Ret); + var func = (Func) meth.CreateDelegate(typeof (Func)); - // fast enough and works in MediumTrust + // fast enough and works in MediumTrust - but we don't // read http://boxbinary.com/2011/10/how-to-run-a-unit-test-in-medium-trust-with-nunitpart-three-umbraco-framework-testing/ - var exprArg = Expression.Parameter(typeof(IPublishedContent), "content"); - var exprNew = Expression.New(constructor, exprArg); - var expr = Expression.Lambda>(exprNew, exprArg); - var func = expr.Compile(); - constructors[typeName] = func; + //var exprArg = Expression.Parameter(typeof(IPropertySet), "content"); + //var exprNew = Expression.New(constructor, exprArg); + //var expr = Expression.Lambda>(exprNew, exprArg); + //var func = expr.Compile(); + + modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, Ctor = func, ModelType = type }; + ModelTypeMap[typeName] = type; } - _constructors = constructors.Count > 0 ? constructors : null; + _modelInfos = modelInfos.Count > 0 ? modelInfos : null; } - public IPublishedContent CreateModel(IPublishedContent content) + public IPropertySet CreateModel(IPropertySet set) { // fail fast - if (_constructors == null) - return content; + if (_modelInfos == null) + return set; - // be case-insensitive - var contentTypeAlias = content.DocumentTypeAlias; + if (_modelInfos.TryGetValue(set.ContentType.Alias, out ModelInfo modelInfo) == false) + return set; - //ConstructorInfo constructor; - //return _constructors.TryGetValue(contentTypeAlias, out constructor) - // ? (IPublishedContent) constructor.Invoke(new object[] { content }) - // : content; + // ReSharper disable once UseMethodIsInstanceOfType + if (modelInfo.ParameterType.IsAssignableFrom(set.GetType()) == false) + throw new InvalidOperationException($"Model {modelInfo.ModelType} expects argument of type {modelInfo.ParameterType.FullName}, but got {set.GetType().FullName}."); - Func constructor; - return _constructors.TryGetValue(contentTypeAlias, out constructor) - ? constructor(content) - : content; - } - - public T CreateModel(IPropertySet content) - { - throw new NotImplementedException(); + return modelInfo.Ctor(set); } } } diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyBase.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyBase.cs index 64917564a6..e4cacb0972 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyBase.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyBase.cs @@ -11,8 +11,7 @@ namespace Umbraco.Core.Models.PublishedContent { protected PublishedPropertyBase(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel) { - if (propertyType == null) throw new ArgumentNullException(nameof(propertyType)); - PropertyType = propertyType; + PropertyType = propertyType ?? throw new ArgumentNullException(nameof(propertyType)); ReferenceCacheLevel = referenceCacheLevel; } diff --git a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs index 497331e584..aa81dbde7b 100644 --- a/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs +++ b/src/Umbraco.Core/Models/PublishedContent/PublishedPropertyType.cs @@ -1,5 +1,4 @@ using System; -using System.Linq; using System.Xml.Linq; using System.Xml.XPath; using Umbraco.Core.Composing; @@ -34,24 +33,6 @@ namespace Umbraco.Core.Models.PublishedContent PropertyEditorAlias = propertyType.PropertyEditorAlias; } - - // fixme remove - /* - /// - /// Initializes a new instance of the class with an existing - /// and a new property type alias. - /// - /// The new property type alias. - /// The existing published property type. - /// - /// The new published property type does not belong to a published content type. - /// It is a copy of the initial published property type, with a different alias. - /// - internal PublishedPropertyType(string propertyTypeAlias, PublishedPropertyType propertyType) - : this(propertyTypeAlias, propertyType.DataTypeId, propertyType.PropertyEditorAlias) - { } - */ - /// /// Initializes a new instance of the class with a property type alias and a property editor alias. /// @@ -69,20 +50,6 @@ namespace Umbraco.Core.Models.PublishedContent : this(propertyTypeAlias, 0, propertyEditorAlias) { } - /* - /// - /// Initializes a new instance of the class with a property type alias and a datatype definition. - /// - /// The property type alias. - /// The datatype definition. - /// - /// The new published property type does not belong to a published content type. - /// - internal PublishedPropertyType(string propertyTypeAlias, IDataTypeDefinition dataTypeDefinition) - : this(propertyTypeAlias, dataTypeDefinition.Id, dataTypeDefinition.PropertyEditorAlias) - { } - */ - /// /// Initializes a new instance of the class with a property type alias, /// a datatype definition identifier, and a property editor alias. @@ -147,7 +114,8 @@ namespace Umbraco.Core.Models.PublishedContent private IPropertyValueConverter _converter; private PropertyCacheLevel _cacheLevel; - private Type _clrType = typeof (object); + private Type _modelClrType; + private Type _clrType; private void EnsureInitialized() { @@ -162,69 +130,73 @@ namespace Umbraco.Core.Models.PublishedContent private void InitializeConverters() { - //TODO: Look at optimizing this method, it gets run for every property type for the document being rendered at startup, - // every precious second counts! - - var converters = Current.PropertyValueConverters.ToArray(); - var defaultConvertersWithAttributes = Current.PropertyValueConverters.DefaultConverters; - _converter = null; + var isdefault = false; - //get all converters for this property type - var foundConverters = converters.Where(x => x.IsConverter(this)).ToArray(); - if (foundConverters.Length == 1) + var converterCollection = Current.PropertyValueConverters; + foreach (var converter in converterCollection) { - _converter = foundConverters[0]; - } - else if (foundConverters.Length > 1) - { - //more than one was found, we need to first figure out if one of these is an Umbraco default value type converter - //get the non-default and see if we have one - var nonDefault = foundConverters.Except(defaultConvertersWithAttributes.Select(x => x.Item1)).ToArray(); - if (nonDefault.Length == 1) + if (converter.IsConverter(this) == false) + continue; + + if (_converter == null) { - //there's only 1 custom converter registered that so use it - _converter = nonDefault[0]; + _converter = converter; + isdefault = converterCollection.IsDefault(converter); + continue; } - else if (nonDefault.Length > 1) + + if (isdefault) { - //this is not allowed, there cannot be more than 1 custom converter - throw new InvalidOperationException( - string.Format("Type '{2}' cannot be an IPropertyValueConverter" - + " for property '{1}' of content type '{0}' because type '{3}' has already been detected as a converter" - + " for that property, and only one converter can exist for a property.", - ContentType.Alias, PropertyTypeAlias, - nonDefault[1].GetType().FullName, nonDefault[0].GetType().FullName)); + if (converterCollection.IsDefault(converter)) + { + // previous was default, and got another default + if (converterCollection.Shadows(_converter, converter)) + { + // previous shadows, ignore + } + else if (converterCollection.Shadows(converter, _converter)) + { + // shadows previous, replace + _converter = converter; + } + else + { + // no shadow - bad + throw new InvalidOperationException(string.Format("Type '{2}' cannot be an IPropertyValueConverter" + + " for property '{1}' of content type '{0}' because type '{3}' has already been detected as a converter" + + " for that property, and only one converter can exist for a property.", + ContentType.Alias, PropertyTypeAlias, + converter.GetType().FullName, _converter.GetType().FullName)); + } + } + else + { + // previous was default, replaced by non-default + _converter = converter; + isdefault = false; + } } else { - //we need to remove any converters that have been shadowed by another converter - var foundDefaultConvertersWithAttributes = defaultConvertersWithAttributes.Where(x => foundConverters.Contains(x.Item1)); - var shadowedTypes = foundDefaultConvertersWithAttributes.SelectMany(x => x.Item2.DefaultConvertersToShadow); - var shadowedDefaultConverters = foundConverters.Where(x => shadowedTypes.Contains(x.GetType())); - var nonShadowedDefaultConverters = foundConverters.Except(shadowedDefaultConverters).ToArray(); - - if (nonShadowedDefaultConverters.Length == 1) + if (converterCollection.IsDefault(converter)) { - //assign to the single default converter - _converter = nonShadowedDefaultConverters[0]; + // previous was non-default, ignore default } - else if (nonShadowedDefaultConverters.Length > 1) + else { - //this is not allowed, there cannot be more than 1 custom converter - throw new InvalidOperationException( - string.Format("Type '{2}' cannot be an IPropertyValueConverter" - + " for property '{1}' of content type '{0}' because type '{3}' has already been detected as a converter" - + " for that property, and only one converter can exist for a property.", - ContentType.Alias, PropertyTypeAlias, - nonShadowedDefaultConverters[1].GetType().FullName, nonShadowedDefaultConverters[0].GetType().FullName)); + // previous was non-default, and got another non-default - bad + throw new InvalidOperationException(string.Format("Type '{2}' cannot be an IPropertyValueConverter" + + " for property '{1}' of content type '{0}' because type '{3}' has already been detected as a converter" + + " for that property, and only one converter can exist for a property.", + ContentType.Alias, PropertyTypeAlias, + converter.GetType().FullName, _converter.GetType().FullName)); } } - } _cacheLevel = _converter?.GetPropertyCacheLevel(this) ?? PropertyCacheLevel.Facade; - _clrType = _converter?.GetPropertyValueType(this) ?? typeof(object); + _modelClrType = _converter == null ? typeof (object) : _converter.GetPropertyValueType(this); } // gets the cache level @@ -241,13 +213,13 @@ namespace Umbraco.Core.Models.PublishedContent // uses converters, else falls back to dark (& performance-wise expensive) magic // source: the property source value // preview: whether we are previewing or not - public object ConvertSourceToInter(object source, bool preview) + public object ConvertSourceToInter(IPropertySet owner, object source, bool preview) { EnsureInitialized(); - // use the converter else use dark (& performance-wise expensive) magic + // use the converter if any, else just return the source value return _converter != null - ? _converter.ConvertSourceToInter(this, source, preview) + ? _converter.ConvertSourceToInter(owner, this, source, preview) : source; } @@ -255,14 +227,13 @@ namespace Umbraco.Core.Models.PublishedContent // uses converters, else returns the inter value // inter: the property inter value // preview: whether we are previewing or not - public object ConvertInterToObject(PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public object ConvertInterToObject(IPropertySet owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { EnsureInitialized(); - // use the converter if any - // else just return the inter value + // use the converter if any, else just return the inter value return _converter != null - ? _converter.ConvertInterToObject(this, referenceCacheLevel, inter, preview) + ? _converter.ConvertInterToObject(owner, this, referenceCacheLevel, inter, preview) : inter; } @@ -271,13 +242,13 @@ namespace Umbraco.Core.Models.PublishedContent // if successful, returns either a string or an XPathNavigator // inter: the property inter value // preview: whether we are previewing or not - public object ConvertInterToXPath(PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public object ConvertInterToXPath(IPropertySet owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { EnsureInitialized(); // use the converter if any if (_converter != null) - return _converter.ConvertInterToXPath(this, referenceCacheLevel, inter, preview); + return _converter.ConvertInterToXPath(owner, this, referenceCacheLevel, inter, preview); // else just return the inter value as a string or an XPathNavigator if (inter == null) return null; @@ -288,12 +259,25 @@ namespace Umbraco.Core.Models.PublishedContent } // gets the property CLR type + // may contain some ModelType types + public Type ModelClrType + { + get + { + EnsureInitialized(); + return _modelClrType; + } + } + + // gets the property CLR type + // with mapped ModelType types (may throw) + // fixme - inject the factory? public Type ClrType { get { EnsureInitialized(); - return _clrType; + return _clrType ?? (_clrType = ModelType.Map(_modelClrType, Current.PublishedContentModelFactory.ModelTypeMap)); } } diff --git a/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs b/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs index a4fb3fb298..4099979da3 100644 --- a/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs +++ b/src/Umbraco.Core/PropertyEditors/DefaultPropertyValueConverterAttribute.cs @@ -1,6 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; namespace Umbraco.Core.PropertyEditors { @@ -12,7 +10,7 @@ namespace Umbraco.Core.PropertyEditors { public DefaultPropertyValueConverterAttribute() { - DefaultConvertersToShadow = Enumerable.Empty(); + DefaultConvertersToShadow = Array.Empty(); } public DefaultPropertyValueConverterAttribute(params Type[] convertersToShadow) @@ -30,7 +28,6 @@ namespace Umbraco.Core.PropertyEditors /// is a very generic converter and the RelatedLiksEditorValueConverter is more specific than it, so the RelatedLiksEditorValueConverter /// can specify that it 'shadows' the JsonValueConverter. /// - public IEnumerable DefaultConvertersToShadow { get; private set; } - + public Type[] DefaultConvertersToShadow { get; } } } diff --git a/src/Umbraco.Core/PropertyEditors/IPropertyValueConverter.cs b/src/Umbraco.Core/PropertyEditors/IPropertyValueConverter.cs index 2c5c1eef13..a28fd7abef 100644 --- a/src/Umbraco.Core/PropertyEditors/IPropertyValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/IPropertyValueConverter.cs @@ -21,6 +21,8 @@ namespace Umbraco.Core.PropertyEditors /// /// The property type. /// The CLR type of values returned by the converter. + /// Some of the CLR types may be generated, therefore this method cannot directly return + /// a Type object (which may not exist yet). In which case it needs to return a ModelType instance. Type GetPropertyValueType(PublishedPropertyType propertyType); /// @@ -33,6 +35,7 @@ namespace Umbraco.Core.PropertyEditors /// /// Converts a property source value to an intermediate value. /// + /// The property set owning the property. /// The property type. /// The source value. /// A value indicating whether conversion should take place in preview mode. @@ -48,11 +51,12 @@ namespace Umbraco.Core.PropertyEditors /// strings, and xml-whitespace strings appropriately, ie it should know whether to preserve /// whitespaces. /// - object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview); + object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview); /// /// Converts a property intermediate value to an Object value. /// + /// The property set owning the property. /// The property type. /// The reference cache level. /// The intermediate value. @@ -66,11 +70,12 @@ namespace Umbraco.Core.PropertyEditors /// passed to eg a PublishedFragment constructor. It is used by the fragment and the properties to manage /// the cache levels of property values. It is not meant to be used by the converter. /// - object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview); + object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview); /// /// Converts a property intermediate value to an XPath value. /// + /// The property set owning the property. /// The property type. /// The reference cache level. /// The intermediate value. @@ -89,6 +94,6 @@ namespace Umbraco.Core.PropertyEditors /// passed to eg a PublishedFragment constructor. It is used by the fragment and the properties to manage /// the cache levels of property values. It is not meant to be used by the converter. /// - object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview); + object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview); } } diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs index 1db9ce88ad..5a5e36e815 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueConverterBase.cs @@ -23,17 +23,17 @@ namespace Umbraco.Core.PropertyEditors return PropertyCacheLevel.Facade; } - public virtual object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public virtual object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { return source; } - public virtual object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public virtual object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { return inter; } - public virtual object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public virtual object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { return inter?.ToString() ?? string.Empty; } diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueConverterCollection.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueConverterCollection.cs index 5f432f69b0..e351309e4a 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueConverterCollection.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueConverterCollection.cs @@ -12,24 +12,35 @@ namespace Umbraco.Core.PropertyEditors { } private readonly object _locker = new object(); - private Tuple[] _defaults; + private Dictionary _defaultConverters; - /// - /// Gets the default converters and associated metadata. - /// - internal Tuple[] DefaultConverters + private Dictionary DefaultConverters { get { lock (_locker) { - return _defaults ?? (_defaults = this.Select(x => - { - var attrib = x.GetType().GetCustomAttribute(false); - return attrib == null ? null : Tuple.Create(x, attrib); - }).WhereNotNull().ToArray()); + if (_defaultConverters != null) + return _defaultConverters; + + _defaultConverters = new Dictionary(); + + foreach (var converter in this) + { + var attr = converter.GetType().GetCustomAttribute(false); + if (attr != null) + _defaultConverters[converter] = attr.DefaultConvertersToShadow; + } + + return _defaultConverters; } } } + + internal bool IsDefault(IPropertyValueConverter converter) + => DefaultConverters.ContainsKey(converter); + + internal bool Shadows(IPropertyValueConverter shadowing, IPropertyValueConverter shadowed) + => DefaultConverters.TryGetValue(shadowing, out Type[] types) && types.Contains(shadowed.GetType()); } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs index 4051a9037e..d61cbaec60 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/CheckboxListValueConverter.cs @@ -8,32 +8,25 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters [DefaultPropertyValueConverter] public class CheckboxListValueConverter : PropertyValueConverterBase { + private static readonly char[] Comma = { ',' }; + public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.CheckBoxListAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.CheckBoxListAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(IEnumerable); - } + => typeof (IEnumerable); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { - var sourceString = (source ?? string.Empty).ToString(); + var sourceString = source?.ToString() ?? string.Empty; if (string.IsNullOrEmpty(sourceString)) return Enumerable.Empty(); - var values = - sourceString.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => v.Trim()); - - return values; + return sourceString.Split(Comma, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()); } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/ColorPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ColorPickerValueConverter.cs index 3dd6efa79c..13e05aa01e 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/ColorPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ColorPickerValueConverter.cs @@ -7,21 +7,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class ColorPickerValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ColorPickerAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ColorPickerAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // make sure it's a string return source?.ToString() ?? string.Empty; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DatePickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DatePickerValueConverter.cs index 75ff3a3d30..cf09be3008 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DatePickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DatePickerValueConverter.cs @@ -15,21 +15,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters }; public override bool IsConverter(PublishedPropertyType propertyType) - { - return PropertyEditorAliases.Contains(propertyType.PropertyEditorAlias); - } + => PropertyEditorAliases.Contains(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (DateTime); - } + => typeof (DateTime); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return DateTime.MinValue; @@ -37,8 +31,8 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // Actually, not always sometimes it is formatted in UTC style with 'Z' suffixed on the end but that is due to this bug: // http://issues.umbraco.org/issue/U4-4145, http://issues.umbraco.org/issue/U4-3894 // We should just be using TryConvertTo instead. - var sourceString = source as string; - if (sourceString != null) + + if (source is string sourceString) { var attempt = sourceString.TryConvertTo(); return attempt.Success == false ? DateTime.MinValue : attempt.Result; @@ -46,17 +40,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // in the database a DateTime is: DateTime // default value is: DateTime.MinValue - return (source is DateTime) - ? source - : DateTime.MinValue; + return source is DateTime ? source : DateTime.MinValue; } // default ConvertSourceToObject just returns source ie a DateTime value - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a DateTime already - return XmlConvert.ToString((DateTime)inter, XmlDateTimeSerializationMode.Unspecified); + return XmlConvert.ToString((DateTime) inter, XmlDateTimeSerializationMode.Unspecified); } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs index 08941046a4..cb4a34cd1a 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs @@ -8,35 +8,27 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class DecimalValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return Constants.PropertyEditors.DecimalAlias.Equals(propertyType.PropertyEditorAlias); - } + => Constants.PropertyEditors.DecimalAlias.Equals(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (decimal); - } + => typeof (decimal); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return 0M; // in XML a decimal is a string - var sourceString = source as string; - if (sourceString != null) + if (source is string sourceString) { - decimal d; - return (decimal.TryParse(sourceString, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out d)) ? d : 0M; + return decimal.TryParse(sourceString, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out decimal d) ? d : 0M; } // in the database an a decimal is an a decimal // default value is zero - return (source is decimal) ? source : 0M; + return source is decimal ? source : 0M; } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleValueConverter.cs index e8fb3ae918..e605b507f6 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleValueConverter.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Configuration; using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.PropertyEditors.ValueConverters @@ -10,21 +9,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class DropdownListMultipleValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropDownListMultipleAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropDownListMultipleAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(IEnumerable); - } + => typeof (IEnumerable); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { var sourceString = (source ?? "").ToString(); diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleWithKeysValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleWithKeysValueConverter.cs index 6e7e5e130d..e2305cfa6b 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleWithKeysValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListMultipleWithKeysValueConverter.cs @@ -9,21 +9,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class DropdownListMultipleWithKeysValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropdownlistMultiplePublishKeysAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropdownlistMultiplePublishKeysAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(IEnumerable); - } + => typeof (IEnumerable); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return new int[] { }; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListValueConverter.cs index eb75e7eebe..007abd62e2 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListValueConverter.cs @@ -7,24 +7,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class DropdownListValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropDownListAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropDownListAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { return source?.ToString() ?? string.Empty; } - } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListWithKeysValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListWithKeysValueConverter.cs index 1c02d89044..2c7747fa74 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListWithKeysValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DropdownListWithKeysValueConverter.cs @@ -7,21 +7,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class DropdownListWithKeysValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropdownlistPublishingKeysAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.DropdownlistPublishingKeysAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(int); - } + => typeof (int); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { var intAttempt = source.TryConvertTo(); if (intAttempt.Success) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/EmailAddressValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/EmailAddressValueConverter.cs index bb31fd5063..7bc1e37c5c 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/EmailAddressValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/EmailAddressValueConverter.cs @@ -7,21 +7,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class EmailAddressValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.EmailAddressAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.EmailAddressAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { return source?.ToString() ?? string.Empty; } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs index e31e42477b..5f60cfb317 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/GridValueConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.IO; using System.Linq; using System.Web; @@ -19,21 +20,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class GridValueConverter : JsonValueConverter { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.GridAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.GridAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (JToken); - } + => typeof (JToken); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs index c39d1d8b73..15c580ab01 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs @@ -19,19 +19,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters private readonly IDataTypeService _dataTypeService; public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ImageCropperAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ImageCropperAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (JToken); - } + => typeof (JToken); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; public ImageCropperValueConverter() { @@ -40,8 +34,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public ImageCropperValueConverter(IDataTypeService dataTypeService) { - if (dataTypeService == null) throw new ArgumentNullException("dataTypeService"); - _dataTypeService = dataTypeService; + _dataTypeService = dataTypeService ?? throw new ArgumentNullException(nameof(dataTypeService)); } internal static void MergePreValues(JObject currentValue, IDataTypeService dataTypeService, int dataTypeId) @@ -100,7 +93,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters } } - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs index 4327bb4017..c75fa5ad9d 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/IntegerValueConverter.cs @@ -7,21 +7,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class IntegerValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return Constants.PropertyEditors.IntegerAlias.Equals(propertyType.PropertyEditorAlias); - } + => Constants.PropertyEditors.IntegerAlias.Equals(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (int); - } + => typeof (int); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return 0; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs index f49eb8243e..f426ccbf0d 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs @@ -29,16 +29,12 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters } public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (JToken); - } + => typeof (JToken); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs index fbe57adbf2..4f4523281f 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/LabelValueConverter.cs @@ -16,23 +16,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class LabelValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias); - } + => Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { - return source == null ? string.Empty : source.ToString(); + return source?.ToString() ?? string.Empty; } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs index 543133546a..d5870ba104 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs @@ -8,22 +8,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class MarkdownEditorValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return Constants.PropertyEditors.MarkdownEditorAlias.Equals(propertyType.PropertyEditorAlias); - } + => Constants.PropertyEditors.MarkdownEditorAlias.Equals(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (IHtmlString); - } + => typeof (IHtmlString); + // PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - // PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // in xml a string is: string // in the database a string is: string @@ -31,13 +25,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters return source; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return new HtmlString(inter == null ? string.Empty : (string) inter); } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return inter?.ToString() ?? string.Empty; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberGroupPickerValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberGroupPickerValueConverter.cs index fc1959a95a..68727676b4 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberGroupPickerValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MemberGroupPickerValueConverter.cs @@ -7,21 +7,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class MemberGroupPickerValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.MemberGroupPickerAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.MemberGroupPickerAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { return source?.ToString() ?? string.Empty; } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs index 5940032b11..9a50493519 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs @@ -10,21 +10,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class MultipleTextStringValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias); - } + => Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (IEnumerable); - } + => typeof (IEnumerable); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // data is (both in database and xml): // @@ -35,7 +29,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // // - var sourceString = source != null ? source.ToString() : null; + var sourceString = source?.ToString(); if (string.IsNullOrWhiteSpace(sourceString)) return Enumerable.Empty(); //SD: I have no idea why this logic is here, I'm pretty sure we've never saved the multiple txt string @@ -56,16 +50,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters pos = sourceString.IndexOf("", pos, StringComparison.Ordinal); } - // Fall back on normal behaviour - if (values.Any() == false) - { - return sourceString.Split(Environment.NewLine.ToCharArray()); - } - - return values.ToArray(); + // fall back on normal behaviour + return values.Any() == false + ? sourceString.Split(Environment.NewLine.ToCharArray()) + : values.ToArray(); } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { var d = new XmlDocument(); var e = d.CreateElement("values"); diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MustBeStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MustBeStringValueConverter.cs index e498598410..d6da92d2f1 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MustBeStringValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MustBeStringValueConverter.cs @@ -24,24 +24,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters }; public override bool IsConverter(PublishedPropertyType propertyType) - { - return Aliases.Contains(propertyType.PropertyEditorAlias); - } + => Aliases.Contains(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { - if (source == null) return null; - return source.ToString(); + return source?.ToString(); } } } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs index ef3e2e094b..15ad3f518c 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/RadioButtonListValueConverter.cs @@ -7,23 +7,18 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class RadioButtonListValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.RadioButtonListAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.RadioButtonListAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(int); - } + => typeof (int); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { var intAttempt = source.TryConvertTo(); + if (intAttempt.Success) return intAttempt.Result; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/SliderValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/SliderValueConverter.cs index fb3a62ba13..0733d71154 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/SliderValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/SliderValueConverter.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using Umbraco.Core.Models; using Umbraco.Core.Models.PublishedContent; @@ -18,28 +19,18 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters } public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.SliderAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.SliderAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return IsRangeDataType(propertyType.DataTypeId) - ? typeof(Range) - : typeof(decimal); - } + => IsRangeDataType(propertyType.DataTypeId) ? typeof (Range) : typeof (decimal); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { if (source == null) - { return null; - } if (IsRangeDataType(propertyType.DataTypeId)) { @@ -55,9 +46,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters var valueAttempt = source.ToString().TryConvertTo(); if (valueAttempt.Success) - { return valueAttempt.Result; - } // Something failed in the conversion of the strings to decimals return null; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TagsValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TagsValueConverter.cs index f846495c96..4d4994c954 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TagsValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/TagsValueConverter.cs @@ -20,21 +20,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters } public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.TagsAlias); - } + => propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.TagsAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(IEnumerable); - } + => typeof (IEnumerable); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // if Json storage type deserialzie and return as string array if (JsonStorageType(propertyType.DataTypeId)) @@ -51,7 +45,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters return csvTags; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { return (string[]) source; } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs index d38a2b5b3c..1f556d03c4 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/TextStringValueConverter.cs @@ -14,21 +14,15 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters }; public override bool IsConverter(PublishedPropertyType propertyType) - { - return PropertyTypeAliases.Contains(propertyType.PropertyEditorAlias); - } + => PropertyTypeAliases.Contains(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // in xml a string is: string // in the database a string is: string @@ -36,13 +30,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters return source; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return inter ?? string.Empty; } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return inter; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs index 3d35865607..ff788f91c4 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/TinyMceValueConverter.cs @@ -11,22 +11,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class TinyMceValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias; - } + => propertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias; public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (IHtmlString); - } + => typeof (IHtmlString); + // PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - // PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // in xml a string is: string // in the database a string is: string @@ -34,13 +28,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters return source; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return new HtmlString(inter == null ? string.Empty : (string)inter); } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return inter; diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/UploadPropertyConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/UploadPropertyConverter.cs index 9c5386d642..3014d7a60d 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/UploadPropertyConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/UploadPropertyConverter.cs @@ -9,46 +9,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters [DefaultPropertyValueConverter] public class UploadPropertyConverter : PropertyValueConverterBase { - /// - /// Checks if this converter can convert the property editor and registers if it can. - /// - /// - /// The published property type. - /// - /// - /// The . - /// public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.UploadFieldAlias); - } + => propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.UploadFieldAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - /// - /// Convert the source object to a string - /// - /// - /// The published property type. - /// - /// - /// The value of the property - /// - /// - /// The preview. - /// - /// - /// The . - /// - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { return source?.ToString() ?? ""; } diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/YesNoValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/YesNoValueConverter.cs index ab9ec17195..153f209ccf 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/YesNoValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/YesNoValueConverter.cs @@ -7,42 +7,30 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters public class YesNoValueConverter : PropertyValueConverterBase { public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias == Constants.PropertyEditors.TrueFalseAlias; - } + => propertyType.PropertyEditorAlias == Constants.PropertyEditors.TrueFalseAlias; public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (bool); - } + => typeof (bool); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { // in xml a boolean is: string // in the database a boolean is: string "1" or "0" or empty // typically the converter does not need to handle anything else ("true"...) // however there are cases where the value passed to the converter could be a non-string object, e.g. int, bool - if (source is string) + if (source is string s) { - var str = (string)source; - - if (str == null || str.Length == 0 || str == "0") + if (s.Length == 0 || s == "0") return false; - if (str == "1") + if (s == "1") return true; - bool result; - if (bool.TryParse(str, out result)) - return result; - - return false; + return bool.TryParse(s, out bool result) && result; } if (source is int) @@ -57,7 +45,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // default ConvertSourceToObject just returns source ie a boolean value - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a boolean already return (bool)inter ? "1" : "0"; diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index cea1d42e81..b7b8318def 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -609,6 +609,7 @@ + diff --git a/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs b/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs index dbfe5a0bc9..8ce55b3f58 100644 --- a/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs +++ b/src/Umbraco.Tests.Benchmarks/XmlPublishedContentInitBenchmarks.cs @@ -155,7 +155,7 @@ namespace Umbraco.Tests.Benchmarks [Benchmark(OperationsPerInvoke = 10)] public void Enhanced_10_Children() { - XmlPublishedContent.InitializeNode(_xml10.DocumentElement, false, + XmlPublishedContent.InitializeNode(null, _xml10.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, @@ -165,7 +165,7 @@ namespace Umbraco.Tests.Benchmarks [Benchmark(OperationsPerInvoke = 10)] public void Enhanced_100_Children() { - XmlPublishedContent.InitializeNode(_xml100.DocumentElement, false, + XmlPublishedContent.InitializeNode(null, _xml100.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, @@ -175,7 +175,7 @@ namespace Umbraco.Tests.Benchmarks [Benchmark(OperationsPerInvoke = 10)] public void Enhanced_1000_Children() { - XmlPublishedContent.InitializeNode(_xml1000.DocumentElement, false, + XmlPublishedContent.InitializeNode(null, _xml1000.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, @@ -185,7 +185,7 @@ namespace Umbraco.Tests.Benchmarks [Benchmark(OperationsPerInvoke = 10)] public void Enhanced_10000_Children() { - XmlPublishedContent.InitializeNode(_xml10000.DocumentElement, false, + XmlPublishedContent.InitializeNode(null, _xml10000.DocumentElement, false, out id, out key, out template, out sortOrder, out name, out writerName, out urlName, out creatorName, out creatorId, out writerId, out docTypeAlias, out nodeType, out path, out version, out createDate, out updateDate, out level, out isDraft, out publishedContentType, @@ -295,8 +295,8 @@ namespace Umbraco.Tests.Benchmarks { XmlNode n; return propertyNodes.TryGetValue(p.PropertyTypeAlias.ToLowerInvariant(), out n) - ? new XmlPublishedProperty(p, isPreviewing, n) - : new XmlPublishedProperty(p, isPreviewing); + ? new XmlPublishedProperty(p, null, isPreviewing, n) + : new XmlPublishedProperty(p, null, isPreviewing); }).Cast().ToDictionary( x => x.PropertyTypeAlias, x => x, diff --git a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs index fb8e69a1aa..96ab36d2c2 100644 --- a/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs +++ b/src/Umbraco.Tests/PropertyEditors/ImageCropperTest.cs @@ -70,7 +70,7 @@ namespace Umbraco.Tests.PropertyEditors dataTypeService.Setup(x => x.GetPreValuesCollectionByDataTypeId(It.IsAny())).Returns(new PreValueCollection(Enumerable.Empty())); var converter = new Umbraco.Web.PropertyEditors.ValueConverters.ImageCropperValueConverter(dataTypeService.Object); - var result = converter.ConvertSourceToInter(new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion + var result = converter.ConvertSourceToInter(null, new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion var resultShouldMatch = val2.SerializeToCropDataSet(); if (expected) diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs index 71b8208eba..6c1a483ee7 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueConverterTests.cs @@ -28,7 +28,7 @@ namespace Umbraco.Tests.PropertyEditors { var converter = new DatePickerValueConverter(); var dateTime = new DateTime(2012, 11, 10, 13, 14, 15); - var result = converter.ConvertSourceToInter(null, date, false); // does not use type for conversion + var result = converter.ConvertSourceToInter(null, null, date, false); // does not use type for conversion if (expected) Assert.AreEqual(dateTime.Date, ((DateTime) result).Date); @@ -54,7 +54,7 @@ namespace Umbraco.Tests.PropertyEditors public void CanConvertYesNoPropertyEditor(object value, bool expected) { var converter = new YesNoValueConverter(); - var result = converter.ConvertSourceToInter(null, value, false); // does not use type for conversion + var result = converter.ConvertSourceToInter(null, null, value, false); // does not use type for conversion Assert.AreEqual(expected, result); } @@ -67,7 +67,7 @@ namespace Umbraco.Tests.PropertyEditors public void CanConvertCheckboxListPropertyEditor(object value, IEnumerable expected) { var converter = new CheckboxListValueConverter(); - var result = converter.ConvertInterToObject(null, PropertyCacheLevel.Unknown, value, false); + var result = converter.ConvertInterToObject(null, null, PropertyCacheLevel.Unknown, value, false); Assert.AreEqual(expected, result); } @@ -80,8 +80,8 @@ namespace Umbraco.Tests.PropertyEditors public void CanConvertDropdownListMultiplePropertyEditor(object value, IEnumerable expected) { var converter = new DropdownListMultipleValueConverter(); - var inter = converter.ConvertSourceToInter(null, value, false); - var result = converter.ConvertInterToObject(null, PropertyCacheLevel.Unknown, inter, false); + var inter = converter.ConvertSourceToInter(null, null, value, false); + var result = converter.ConvertInterToObject(null, null, PropertyCacheLevel.Unknown, inter, false); Assert.AreEqual(expected, result); } @@ -94,8 +94,8 @@ namespace Umbraco.Tests.PropertyEditors public void CanConvertDropdownListMultipleWithKeysPropertyEditor(object value, IEnumerable expected) { var converter = new DropdownListMultipleWithKeysValueConverter(); - var inter = converter.ConvertSourceToInter(null, value, false); - var result = converter.ConvertInterToObject(null, PropertyCacheLevel.Unknown, inter, false); + var inter = converter.ConvertSourceToInter(null, null, value, false); + var result = converter.ConvertInterToObject(null, null, PropertyCacheLevel.Unknown, inter, false); Assert.AreEqual(expected, result); } diff --git a/src/Umbraco.Tests/PublishedContent/ModelsAndConvertersTests.cs b/src/Umbraco.Tests/PublishedContent/ModelsAndConvertersTests.cs new file mode 100644 index 0000000000..466bb96b61 --- /dev/null +++ b/src/Umbraco.Tests/PublishedContent/ModelsAndConvertersTests.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using LightInject; +using Moq; +using NUnit.Framework; +using Umbraco.Core.Composing; +using Umbraco.Core.Models.PublishedContent; +using Umbraco.Core.PropertyEditors; +using Umbraco.Web; +using Umbraco.Web.PublishedCache; + +namespace Umbraco.Tests.PublishedContent +{ + [TestFixture] + public class ModelsAndConvertersTests + { + [Test] + public void ModelTypeEqualityTests() + { + Assert.AreNotEqual(ModelType.For("alias1"), ModelType.For("alias1")); + + Assert.IsTrue(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias1"))); + Assert.IsFalse(ModelType.Equals(ModelType.For("alias1"), ModelType.For("alias2"))); + + Assert.IsTrue(ModelType.Equals(typeof (IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof (IEnumerable<>).MakeGenericType(ModelType.For("alias1")))); + Assert.IsFalse(ModelType.Equals(typeof (IEnumerable<>).MakeGenericType(ModelType.For("alias1")), typeof (IEnumerable<>).MakeGenericType(ModelType.For("alias2")))); + + Assert.IsTrue(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias1").MakeArrayType())); + Assert.IsFalse(ModelType.Equals(ModelType.For("alias1").MakeArrayType(), ModelType.For("alias2").MakeArrayType())); + } + + [Test] + public void ModelTypeToStringTests() + { + Assert.AreEqual("{alias1}", ModelType.For("alias1").ToString()); + + // there's an "*" there because the arrays are not true SZArray - but that changes when we map + Assert.AreEqual("{alias1}[*]", ModelType.For("alias1").MakeArrayType().ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[{alias1}[*]]", typeof (IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()).ToString()); + } + + [Test] + public void ModelTypeMapTests() + { + var map = new Dictionary + { + { "alias1", typeof (TestSetModel1) }, + { "alias2", typeof (TestSetModel2) }, + }; + + Assert.AreEqual("Umbraco.Tests.PublishedContent.ModelsAndConvertersTests+TestSetModel1", + ModelType.Map(ModelType.For("alias1"), map).ToString()); + Assert.AreEqual("Umbraco.Tests.PublishedContent.ModelsAndConvertersTests+TestSetModel1[]", + ModelType.Map(ModelType.For("alias1").MakeArrayType(), map).ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.PublishedContent.ModelsAndConvertersTests+TestSetModel1]", + ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1")), map).ToString()); + Assert.AreEqual("System.Collections.Generic.IEnumerable`1[Umbraco.Tests.PublishedContent.ModelsAndConvertersTests+TestSetModel1[]]", + ModelType.Map(typeof(IEnumerable<>).MakeGenericType(ModelType.For("alias1").MakeArrayType()), map).ToString()); + } + + [Test] + public void ConverterTest1() + { + Current.Reset(); + var container = new ServiceContainer(); + container.ConfigureUmbracoCore(); + + Current.Container.RegisterCollectionBuilder() + .Append() + .Append(); + + IPublishedContentModelFactory factory = new PublishedContentModelFactory(new[] + { + typeof(TestSetModel1), typeof(TestSetModel2), + typeof(TestContentModel1), typeof(TestContentModel2), + }); + Current.Container.Register(f => factory); + + var setType1 = new PublishedContentType(1000, "set1", new[] + { + new PublishedPropertyType("prop1", "editor1"), + }); + + var setType2 = new PublishedContentType(1001, "set2", new[] + { + new PublishedPropertyType("prop2", "editor2"), + }); + + var contentType1 = new PublishedContentType(1002, "content1", new[] + { + new PublishedPropertyType("prop1", "editor1"), + }); + + var contentType2 = new PublishedContentType(1003, "content2", new[] + { + new PublishedPropertyType("prop2", "editor2"), + }); + + var set1 = new PropertySet(setType1, Guid.NewGuid(), new Dictionary { { "prop1", "val1" } }, false); + var set2 = new PropertySet(setType2, Guid.NewGuid(), new Dictionary { { "prop2", "1003" } }, false); + var cnt1 = new TestPublishedContent(contentType1, Guid.NewGuid(), new Dictionary { { "prop1", "val1" } }, false); + var cnt2 = new TestPublishedContent(contentType2, Guid.NewGuid(), new Dictionary { { "prop2", "1003" } }, false); + + var cache = new Dictionary + { + { 1003, cnt1.CreateModel() }, + { 1004, cnt2.CreateModel() }, + }; + + var facadeMock = new Mock(); + var cacheMock = new Mock(); + cacheMock.Setup(x => x.GetById(It.IsAny())).Returns(id => cache.TryGetValue(id, out IPublishedContent content) ? content : null); + facadeMock.Setup(x => x.ContentCache).Returns(cacheMock.Object); + var facade = facadeMock.Object; + Current.Container.Register(f => facade); + + // can get the actual property Clr type + // ie ModelType gets properly mapped by IPublishedContentModelFactory + // must test ModelClrType with special equals 'cos they are not ref-equals + Assert.IsTrue(ModelType.Equals(typeof (IEnumerable<>).MakeGenericType(ModelType.For("content1")), contentType2.GetPropertyType("prop2").ModelClrType)); + Assert.AreEqual(typeof (IEnumerable), contentType2.GetPropertyType("prop2").ClrType); + + // can create a model for a property set + var model1 = factory.CreateModel(set1); + Assert.IsInstanceOf(model1); + Assert.AreEqual("val1", ((TestSetModel1) model1).Prop1); + + // can create a model for a published content + var model2 = factory.CreateModel(set2); + Assert.IsInstanceOf(model2); + var mmodel2 = (TestSetModel2) model2; + + // and get direct property + Assert.IsInstanceOf(model2.Value("prop2")); + Assert.AreEqual(1, ((TestContentModel1[]) model2.Value("prop2")).Length); + + // and get model property + Assert.IsInstanceOf>(mmodel2.Prop2); + Assert.IsInstanceOf(mmodel2.Prop2); + var mmodel1 = mmodel2.Prop2.First(); + + // and we get what we want + Assert.AreSame(cache[1003], mmodel1); + } + + internal class TestPublishedContent : PropertySet, IPublishedContent + { + public TestPublishedContent(PublishedContentType contentType, Guid key, Dictionary values, bool previewing) + : base(contentType, key, values, previewing) + { } + + public int Id { get; } + public int TemplateId { get; } + public int SortOrder { get; } + public string Name { get; } + public string UrlName { get; } + public string DocumentTypeAlias { get; } + public int DocumentTypeId { get; } + public string WriterName { get; } + public string CreatorName { get; } + public int WriterId { get; } + public int CreatorId { get; } + public string Path { get; } + public DateTime CreateDate { get; } + public DateTime UpdateDate { get; } + public Guid Version { get; } + public int Level { get; } + public string Url { get; } + public PublishedItemType ItemType { get; } + public bool IsDraft { get; } + public IPublishedContent Parent { get; } + public IEnumerable Children { get; } + public IPublishedProperty GetProperty(string alias, bool recurse) + { + throw new NotImplementedException(); + } + } + + [PublishedContentModel("set1")] + public class TestSetModel1 : PropertySetModel + { + public TestSetModel1(IPropertySet content) + : base(content) + { } + + public string Prop1 => this.Value("prop1"); + } + + [PublishedContentModel("set2")] + public class TestSetModel2 : PropertySetModel + { + public TestSetModel2(IPropertySet content) + : base(content) + { } + + public IEnumerable Prop2 => this.Value>("prop2"); + } + + [PublishedContentModel("content1")] + public class TestContentModel1 : PublishedContentModel + { + public TestContentModel1(IPublishedContent content) + : base(content) + { } + + public string Prop1 => this.Value("prop1"); + } + + [PublishedContentModel("content2")] + public class TestContentModel2 : PublishedContentModel + { + public TestContentModel2(IPublishedContent content) + : base(content) + { } + + public IEnumerable Prop2 => this.Value>("prop2"); + } + + public class TestConverter1 : PropertyValueConverterBase + { + public override bool IsConverter(PublishedPropertyType propertyType) + => propertyType.PropertyEditorAlias == "editor1"; + + public override Type GetPropertyValueType(PublishedPropertyType propertyType) + => typeof (string); + + public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) + => PropertyCacheLevel.Content; + } + + public class TestConverter2 : PropertyValueConverterBase + { + private readonly IFacade _facade; + + public TestConverter2(IFacade facade) + { + _facade = facade; + } + + public override bool IsConverter(PublishedPropertyType propertyType) + => propertyType.PropertyEditorAlias == "editor2"; + + // pretend ... when writing the converter, the model type for alias "set1" does not exist yet + public override Type GetPropertyValueType(PublishedPropertyType propertyType) + => typeof (IEnumerable<>).MakeGenericType(ModelType.For("content1")); + + public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) + => PropertyCacheLevel.Snapshot; + + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) + { + var s = source as string; + return s?.Split(',').Select(int.Parse).ToArray() ?? Array.Empty(); + } + + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + { + return ((int[]) inter).Select(x => (TestContentModel1) _facade.ContentCache.GetById(x)).ToArray(); + } + } + } +} diff --git a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs index a9fbbc0749..a7196f9181 100644 --- a/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs +++ b/src/Umbraco.Tests/PublishedContent/PublishedContentTests.cs @@ -556,7 +556,7 @@ namespace Umbraco.Tests.PublishedContent { var pt = new PublishedPropertyType("detached", Constants.PropertyEditors.IntegerAlias); var ct = new PublishedContentType(0, "alias", new[] { pt }); - var prop = new PropertySetProperty(pt, Guid.NewGuid(), false, PropertyCacheLevel.None, 5548); + var prop = new PropertySetProperty(pt, null, false, PropertyCacheLevel.None, 5548); Assert.IsInstanceOf(prop.Value); Assert.AreEqual(5548, prop.Value); } diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index f17d933649..c5354fff12 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -210,6 +210,7 @@ + diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs index 066bf76e09..2384532476 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/ContentPickerValueConverter.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) => PropertyCacheLevel.Snapshot; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; @@ -46,7 +46,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return null; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { if (inter == null) return null; @@ -73,7 +73,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return inter; } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { return inter.ToString(); } diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs index 19b137da28..ca63535260 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/ImageCropperValueConverter.cs @@ -1,7 +1,9 @@ using System; +using System.Collections.Generic; using System.Globalization; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using Umbraco.Core; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; using Umbraco.Core.PropertyEditors.ValueConverters; @@ -19,17 +21,16 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public ImageCropperValueConverter() { } - public ImageCropperValueConverter(IDataTypeService dataTypeService) : base(dataTypeService) + public ImageCropperValueConverter(IDataTypeService dataTypeService) + : base(dataTypeService) { } public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (ImageCropDataSet); - } + => typeof (ImageCropDataSet); - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { - var baseVal = base.ConvertSourceToInter(propertyType, source, preview); + var baseVal = base.ConvertSourceToInter(owner, propertyType, source, preview); var json = baseVal as JObject; if (json == null) return baseVal; diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs index b8ad1c72cd..d1bc5e157f 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MacroContainerValueConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Text; using System.Web; using Umbraco.Core; @@ -63,7 +64,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } } - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs index e27807595a..46c6d6d07e 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MarkdownEditorValueConverter.cs @@ -20,7 +20,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) => PropertyCacheLevel.Facade; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); @@ -32,7 +32,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return sourceString; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // convert markup to html for frontend rendering. // source should come from ConvertSource and be a string (or null) already diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerPropertyConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerPropertyConverter.cs index 0cbc2ecb35..0e7544890b 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerPropertyConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MediaPickerPropertyConverter.cs @@ -44,11 +44,9 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return IsMultipleDataType(propertyType.DataTypeId, propertyType.PropertyEditorAlias) - ? typeof(IEnumerable) - : typeof(IPublishedContent); - } + => IsMultipleDataType(propertyType.DataTypeId, propertyType.PropertyEditorAlias) + ? typeof (IEnumerable) + : typeof (IPublishedContent); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) => PropertyCacheLevel.Facade; @@ -86,7 +84,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters }); } - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { var nodeIds = source.ToString() .Split(new[] { "," }, StringSplitOptions.RemoveEmptyEntries) @@ -95,7 +93,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return nodeIds; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { if (source == null) { diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MemberPickerPropertyConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MemberPickerPropertyConverter.cs index dd634fc7c4..820dbd1aee 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MemberPickerPropertyConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MemberPickerPropertyConverter.cs @@ -23,16 +23,12 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Facade; - } + => PropertyCacheLevel.Facade; public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(IPublishedContent); - } + => typeof (IPublishedContent); - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { var attemptConvertInt = source.TryConvertTo(); if (attemptConvertInt.Success) @@ -43,7 +39,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return null; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { if (source == null) return null; diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerPropertyConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerPropertyConverter.cs index 33bf1adc80..d67e87dbc9 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerPropertyConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultiNodeTreePickerPropertyConverter.cs @@ -1,13 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Umbraco -// -// -// The multi node tree picker property editor value converter. -// -// -------------------------------------------------------------------------------------------------------------------- - -using System; +using System; using System.Collections.Generic; using System.Globalization; using System.Linq; @@ -52,16 +43,12 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Facade; - } + => PropertyCacheLevel.Facade; public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (IEnumerable); - } + => typeof (IEnumerable); - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.MultiNodeTreePickerAlias)) { @@ -82,7 +69,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return null; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel cacheLevel, object source, bool preview) { if (source == null) { diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultipleMediaPickerPropertyConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultipleMediaPickerPropertyConverter.cs index d48aed40b9..de9d068984 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/MultipleMediaPickerPropertyConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/MultipleMediaPickerPropertyConverter.cs @@ -39,18 +39,14 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Facade; - } + => PropertyCacheLevel.Facade; public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return IsMultipleDataType(propertyType.DataTypeId, propertyType.PropertyEditorAlias) - ? typeof(IEnumerable) - : typeof(IPublishedContent); - } + => IsMultipleDataType(propertyType.DataTypeId, propertyType.PropertyEditorAlias) + ? typeof (IEnumerable) + : typeof (IPublishedContent); - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (IsMultipleDataType(propertyType.DataTypeId, propertyType.PropertyEditorAlias)) { @@ -83,7 +79,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return null; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview) { if (source == null) { diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs index f8fe19ebe0..f9148c3610 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksLegacyValueConverter.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Linq; using System.Xml; using Newtonsoft.Json; @@ -35,21 +36,15 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } public override bool IsConverter(PublishedPropertyType propertyType) - { - return MatchingEditors.Contains(propertyType.PropertyEditorAlias); - } + => MatchingEditors.Contains(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof(JArray); - } + => typeof (JArray); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); @@ -103,7 +98,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return sourceString; } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs index dc428236e1..09f32fe9a7 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RelatedLinksValueConverter.cs @@ -44,22 +44,16 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters /// The . /// public override bool IsConverter(PublishedPropertyType propertyType) - { - return propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.RelatedLinksAlias) - || propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.RelatedLinks2Alias); - } + => propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.RelatedLinksAlias) + || propertyType.PropertyEditorAlias.Equals(Constants.PropertyEditors.RelatedLinks2Alias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (JArray); - } + => typeof (JArray); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Content; - } + => PropertyCacheLevel.Content; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); @@ -140,7 +134,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return link; } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { if (inter == null) return null; var sourceString = inter.ToString(); diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index 32190d2c19..2041af92b9 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -63,7 +63,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters } } - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) { diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/TextStringValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/TextStringValueConverter.cs index a7a9f433bf..c921930abd 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/TextStringValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/TextStringValueConverter.cs @@ -17,21 +17,15 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters }; public override bool IsConverter(PublishedPropertyType propertyType) - { - return PropertyTypeAliases.Contains(propertyType.PropertyEditorAlias); - } + => PropertyTypeAliases.Contains(propertyType.PropertyEditorAlias); public override Type GetPropertyValueType(PublishedPropertyType propertyType) - { - return typeof (string); - } + => typeof (string); public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType) - { - return PropertyCacheLevel.Facade; - } + => PropertyCacheLevel.Facade; - public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview) + public override object ConvertSourceToInter(IPropertySet owner, PublishedPropertyType propertyType, object source, bool preview) { if (source == null) return null; var sourceString = source.ToString(); @@ -43,13 +37,13 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters return sourceString; } - public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToObject(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return inter ?? string.Empty; } - public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) + public override object ConvertInterToXPath(IPropertySet owner, PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview) { // source should come from ConvertSource and be a string (or null) already return inter; diff --git a/src/Umbraco.Web/PublishedCache/FacadeServiceBase.cs b/src/Umbraco.Web/PublishedCache/FacadeServiceBase.cs index 17e3080edf..90d4fecced 100644 --- a/src/Umbraco.Web/PublishedCache/FacadeServiceBase.cs +++ b/src/Umbraco.Web/PublishedCache/FacadeServiceBase.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Umbraco.Core.Composing; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.PropertyEditors; @@ -26,10 +27,14 @@ namespace Umbraco.Web.PublishedCache public virtual IPropertySet CreateSet(PublishedContentType contentType, Guid key, Dictionary values, bool previewing, PropertyCacheLevel referenceCacheLevel) { - return new PropertySet(contentType, key, values, previewing, this, referenceCacheLevel); + var set = new PropertySet(contentType, key, values, previewing, this, referenceCacheLevel); + var model = Current.PublishedContentModelFactory.CreateModel(set); + if (model == null) + throw new Exception("Factory returned null."); + return model; } - public abstract IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, Guid setKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null); + public abstract IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null); public abstract string EnterPreview(IUser user, int contentId); public abstract void RefreshPreview(string previewToken, int contentId); diff --git a/src/Umbraco.Web/PublishedCache/IFacadeService.cs b/src/Umbraco.Web/PublishedCache/IFacadeService.cs index b5ec511fc0..bb7acfa052 100644 --- a/src/Umbraco.Web/PublishedCache/IFacadeService.cs +++ b/src/Umbraco.Web/PublishedCache/IFacadeService.cs @@ -169,12 +169,12 @@ namespace Umbraco.Web.PublishedCache /// Creates a set property. /// /// The property type. - /// The set key. + /// The set. /// A value indicating whether previewing. /// The reference cache level. /// The source value. /// A set property. - IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, Guid setKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null); + IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null); #endregion } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs b/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs index 0ae481c0a3..b08e885446 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/FacadeService.cs @@ -1536,9 +1536,9 @@ AND cmsContentNu.nodeId IS NULL #region Property Set - public override IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, Guid setKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) + public override IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) { - return new PropertySetProperty(FacadeAccessor, propertyType, setKey, previewing, referenceCacheLevel, sourceValue); + return new PropertySetProperty(FacadeAccessor, propertyType, set, previewing, referenceCacheLevel, sourceValue); } #endregion diff --git a/src/Umbraco.Web/PublishedCache/NuCache/Property.cs b/src/Umbraco.Web/PublishedCache/NuCache/Property.cs index 12056fbc7b..2e7ee9275d 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/Property.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/Property.cs @@ -15,6 +15,7 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly Guid _contentUid; private readonly bool _isPreviewing; private readonly bool _isMember; + private readonly IPublishedContent _content; private readonly object _locko = new object(); @@ -25,28 +26,29 @@ namespace Umbraco.Web.PublishedCache.NuCache private string _recurseCacheKey; // initializes a published content property with no value - public Property(PublishedPropertyType propertyType, IPublishedContent content, IFacadeAccessor facadeAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Content) + public Property(PublishedPropertyType propertyType, PublishedContent content, IFacadeAccessor facadeAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Content) : this(propertyType, content, null, facadeAccessor, referenceCacheLevel) { } // initializes a published content property with a value - public Property(PublishedPropertyType propertyType, IPublishedContent content, object sourceValue, IFacadeAccessor facadeAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Content) + public Property(PublishedPropertyType propertyType, PublishedContent content, object sourceValue, IFacadeAccessor facadeAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Content) : base(propertyType, referenceCacheLevel) { _sourceValue = sourceValue; _contentUid = content.Key; - var inner = PublishedContent.UnwrapIPublishedContent(content); - _isPreviewing = inner.IsPreviewing; + _content = content; + _isPreviewing = content.IsPreviewing; _isMember = content.ContentType.ItemType == PublishedItemType.Member; _facadeAccessor = facadeAccessor; } // clone for previewing as draft a published content that is published and has no draft - public Property(Property origin) + public Property(Property origin, IPublishedContent content) : base(origin.PropertyType, origin.ReferenceCacheLevel) { _sourceValue = origin._sourceValue; _contentUid = origin._contentUid; + _content = content; _isPreviewing = true; _isMember = origin._isMember; _facadeAccessor = origin._facadeAccessor; @@ -122,7 +124,7 @@ namespace Umbraco.Web.PublishedCache.NuCache { if (_interInitialized) return _interValue; - _interValue = PropertyType.ConvertSourceToInter(_sourceValue, _isPreviewing); + _interValue = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing); _interInitialized = true; return _interValue; } @@ -139,7 +141,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue; // initial reference cache level always is .Content - cacheValues.ObjectValue = PropertyType.ConvertInterToObject(PropertyCacheLevel.Content, GetInterValue(), _isPreviewing); + cacheValues.ObjectValue = PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Content, GetInterValue(), _isPreviewing); cacheValues.ObjectInitialized = true; return cacheValues.ObjectValue; } @@ -156,7 +158,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (cacheValues.XPathInitialized) return cacheValues.XPathValue; // initial reference cache level always is .Content - cacheValues.XPathValue = PropertyType.ConvertInterToXPath(PropertyCacheLevel.Content, GetInterValue(), _isPreviewing); + cacheValues.XPathValue = PropertyType.ConvertInterToXPath(_content, PropertyCacheLevel.Content, GetInterValue(), _isPreviewing); cacheValues.XPathInitialized = true; return cacheValues.XPathValue; } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PropertySetProperty.cs b/src/Umbraco.Web/PublishedCache/NuCache/PropertySetProperty.cs index cc4e9eaa90..eaad29a993 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PropertySetProperty.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PropertySetProperty.cs @@ -11,15 +11,15 @@ namespace Umbraco.Web.PublishedCache.NuCache private string _valuesCacheKey; // initializes a published item property - public PropertySetProperty(IFacadeAccessor facadeAccessor, PublishedPropertyType propertyType, Guid fragmentKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) - : base(propertyType, fragmentKey, previewing, referenceCacheLevel, sourceValue) + public PropertySetProperty(IFacadeAccessor facadeAccessor, PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) + : base(propertyType, set, previewing, referenceCacheLevel, sourceValue) { _facadeAccessor = facadeAccessor; } // used to cache the CacheValues of this property internal string ValuesCacheKey => _valuesCacheKey - ?? (_valuesCacheKey = CacheKeys.PropertyCacheValues(FragmentKey, PropertyTypeAlias, IsPreviewing)); + ?? (_valuesCacheKey = CacheKeys.PropertyCacheValues(Set.Key, PropertyTypeAlias, IsPreviewing)); protected override CacheValues GetSnapshotCacheValues() { diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs index e93b76221c..b06cc3927f 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedContent.cs @@ -92,7 +92,7 @@ namespace Umbraco.Web.PublishedCache.NuCache IsPreviewing = true; // clone properties so _isPreviewing is true - PropertiesArray = origin.PropertiesArray.Select(x => (IPublishedProperty) new Property((Property) x)).ToArray(); + PropertiesArray = origin.PropertiesArray.Select(x => (IPublishedProperty) new Property((Property) x, this)).ToArray(); } #endregion diff --git a/src/Umbraco.Web/PublishedCache/PropertySet.cs b/src/Umbraco.Web/PublishedCache/PropertySet.cs index 98cd39c978..ae93c55a32 100644 --- a/src/Umbraco.Web/PublishedCache/PropertySet.cs +++ b/src/Umbraco.Web/PublishedCache/PropertySet.cs @@ -31,7 +31,7 @@ namespace Umbraco.Web.PublishedCache .Select(propertyType => { values.TryGetValue(propertyType.PropertyTypeAlias, out object value); - return facadeService.CreateSetProperty(propertyType, Key, previewing, referenceCacheLevel, value); + return facadeService.CreateSetProperty(propertyType, this, previewing, referenceCacheLevel, value); }) .ToArray(); } @@ -55,7 +55,7 @@ namespace Umbraco.Web.PublishedCache .Select(propertyType => { values.TryGetValue(propertyType.PropertyTypeAlias, out object value); - return (IPublishedProperty) new PropertySetProperty(propertyType, Key, previewing, cacheLevel, value); + return (IPublishedProperty) new PropertySetProperty(propertyType, this, previewing, cacheLevel, value); }) .ToArray(); } diff --git a/src/Umbraco.Web/PublishedCache/PropertySetProperty.cs b/src/Umbraco.Web/PublishedCache/PropertySetProperty.cs index 4faa2090aa..784351115d 100644 --- a/src/Umbraco.Web/PublishedCache/PropertySetProperty.cs +++ b/src/Umbraco.Web/PublishedCache/PropertySetProperty.cs @@ -6,8 +6,8 @@ namespace Umbraco.Web.PublishedCache { class PropertySetProperty : PropertySetPropertyBase { - public PropertySetProperty(PublishedPropertyType propertyType, Guid fragmentKey, bool previewing, PropertyCacheLevel cacheLevel, object sourceValue = null) - : base(propertyType, fragmentKey, previewing, cacheLevel, sourceValue) + public PropertySetProperty(PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel cacheLevel, object sourceValue = null) + : base(propertyType, set, previewing, cacheLevel, sourceValue) { } protected override CacheValues GetSnapshotCacheValues() diff --git a/src/Umbraco.Web/PublishedCache/PropertySetPropertyBase.cs b/src/Umbraco.Web/PublishedCache/PropertySetPropertyBase.cs index d31a581987..f7d39c62fa 100644 --- a/src/Umbraco.Web/PublishedCache/PropertySetPropertyBase.cs +++ b/src/Umbraco.Web/PublishedCache/PropertySetPropertyBase.cs @@ -9,7 +9,7 @@ namespace Umbraco.Web.PublishedCache private readonly object _locko = new object(); private readonly object _sourceValue; - protected readonly Guid FragmentKey; + protected readonly IPropertySet Set; protected readonly bool IsPreviewing; protected readonly bool IsMember; @@ -18,11 +18,11 @@ namespace Umbraco.Web.PublishedCache private CacheValues _cacheValues; // initializes a published item property - protected PropertySetPropertyBase(PublishedPropertyType propertyType, Guid fragmentKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) + protected PropertySetPropertyBase(PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) : base(propertyType, referenceCacheLevel) { _sourceValue = sourceValue; - FragmentKey = fragmentKey; + Set = set; IsPreviewing = previewing; IsMember = propertyType.ContentType.ItemType == PublishedItemType.Member; } @@ -117,7 +117,7 @@ namespace Umbraco.Web.PublishedCache { if (_interInitialized) return _interValue; - _interValue = PropertyType.ConvertSourceToInter(_sourceValue, IsPreviewing); + _interValue = PropertyType.ConvertSourceToInter(Set, _sourceValue, IsPreviewing); _interInitialized = true; return _interValue; } @@ -136,7 +136,7 @@ namespace Umbraco.Web.PublishedCache var cacheValues = GetCacheValues(cacheLevel); if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue; - cacheValues.ObjectValue = PropertyType.ConvertInterToObject(referenceCacheLevel, GetInterValue(), IsPreviewing); + cacheValues.ObjectValue = PropertyType.ConvertInterToObject(Set, referenceCacheLevel, GetInterValue(), IsPreviewing); cacheValues.ObjectInitialized = true; return cacheValues.ObjectValue; } @@ -155,7 +155,7 @@ namespace Umbraco.Web.PublishedCache var cacheValues = GetCacheValues(cacheLevel); if (cacheValues.XPathInitialized) return cacheValues.XPathValue; - cacheValues.XPathValue = PropertyType.ConvertInterToXPath(referenceCacheLevel, GetInterValue(), IsPreviewing); + cacheValues.XPathValue = PropertyType.ConvertInterToXPath(Set, referenceCacheLevel, GetInterValue(), IsPreviewing); cacheValues.XPathInitialized = true; return cacheValues.XPathValue; } diff --git a/src/Umbraco.Web/PublishedCache/PublishedMember.cs b/src/Umbraco.Web/PublishedCache/PublishedMember.cs index ecd6883fa0..cfc89a1fbd 100644 --- a/src/Umbraco.Web/PublishedCache/PublishedMember.cs +++ b/src/Umbraco.Web/PublishedCache/PublishedMember.cs @@ -21,15 +21,12 @@ namespace Umbraco.Web.PublishedCache public PublishedMember(IMember member, PublishedContentType publishedMemberType) { - if (member == null) throw new ArgumentNullException(nameof(member)); - if (publishedMemberType == null) throw new ArgumentNullException(nameof(publishedMemberType)); - - _member = member; + _member = member ?? throw new ArgumentNullException(nameof(member)); _membershipUser = member; - _publishedMemberType = publishedMemberType; + _publishedMemberType = publishedMemberType ?? throw new ArgumentNullException(nameof(publishedMemberType)); _properties = PublishedProperty.MapProperties(_publishedMemberType.PropertyTypes, _member.Properties, - (t, v) => new RawValueProperty(t, v ?? string.Empty)) + (t, v) => new RawValueProperty(t, this, v ?? string.Empty)) .ToArray(); } diff --git a/src/Umbraco.Web/PublishedCache/RawValueProperty.cs b/src/Umbraco.Web/PublishedCache/RawValueProperty.cs index 32322e42f7..c12d41faf9 100644 --- a/src/Umbraco.Web/PublishedCache/RawValueProperty.cs +++ b/src/Umbraco.Web/PublishedCache/RawValueProperty.cs @@ -12,10 +12,8 @@ namespace Umbraco.Web.PublishedCache internal class RawValueProperty : PublishedPropertyBase { private readonly object _dbVal; //the value in the db - private readonly Lazy _sourceValue; private readonly Lazy _objectValue; private readonly Lazy _xpathValue; - private readonly bool _isPreviewing; public override object SourceValue => _dbVal; @@ -26,24 +24,22 @@ namespace Umbraco.Web.PublishedCache public override object XPathValue => _xpathValue.Value; // note: propertyData cannot be null - public RawValueProperty(PublishedPropertyType propertyType, object propertyData, bool isPreviewing = false) - : this(propertyType, isPreviewing) + public RawValueProperty(PublishedPropertyType propertyType, IPublishedContent content, object propertyData, bool isPreviewing = false) + : this(propertyType, content, isPreviewing) { - if (propertyData == null) - throw new ArgumentNullException(nameof(propertyData)); - _dbVal = propertyData; + _dbVal = propertyData ?? throw new ArgumentNullException(nameof(propertyData)); } // note: maintaining two ctors to make sure we understand what we do when calling them - public RawValueProperty(PublishedPropertyType propertyType, bool isPreviewing = false) + public RawValueProperty(PublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing = false) : base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored { _dbVal = null; - _isPreviewing = isPreviewing; + var isPreviewing1 = isPreviewing; - _sourceValue = new Lazy(() => PropertyType.ConvertSourceToInter(_dbVal, _isPreviewing)); - _objectValue = new Lazy(() => PropertyType.ConvertInterToObject(PropertyCacheLevel.Unknown, _sourceValue.Value, _isPreviewing)); - _xpathValue = new Lazy(() => PropertyType.ConvertInterToXPath(PropertyCacheLevel.Unknown, _sourceValue.Value, _isPreviewing)); + var sourceValue = new Lazy(() => PropertyType.ConvertSourceToInter(content, _dbVal, isPreviewing1)); + _objectValue = new Lazy(() => PropertyType.ConvertInterToObject(content, PropertyCacheLevel.Unknown, sourceValue.Value, isPreviewing1)); + _xpathValue = new Lazy(() => PropertyType.ConvertInterToXPath(content, PropertyCacheLevel.Unknown, sourceValue.Value, isPreviewing1)); } } } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/FacadeService.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/FacadeService.cs index 073608c660..e7f314d730 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/FacadeService.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/FacadeService.cs @@ -240,7 +240,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache #region Property Set - public override IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, Guid setKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) + public override IPublishedProperty CreateSetProperty(PublishedPropertyType propertyType, IPropertySet set, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null) { throw new NotImplementedException(); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs index 1cd1871f4d..30f989ffde 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedMediaCache.cs @@ -683,8 +683,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache string value; const bool isPreviewing = false; // false :: never preview a media var property = valueDictionary.TryGetValue(alias, out value) == false || value == null - ? new XmlPublishedProperty(propertyType, isPreviewing) - : new XmlPublishedProperty(propertyType, isPreviewing, value); + ? new XmlPublishedProperty(propertyType, this, isPreviewing) + : new XmlPublishedProperty(propertyType, this, isPreviewing, value); _properties.Add(property); } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs index b29642fcaa..535571007b 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedContent.cs @@ -301,7 +301,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private void InitializeNode() { - InitializeNode(_xmlNode, _isPreviewing, + InitializeNode(this, _xmlNode, _isPreviewing, out _id, out _key, out _template, out _sortOrder, out _name, out _writerName, out _urlName, out _creatorName, out _creatorId, out _writerId, out _docTypeAlias, out _docTypeId, out _path, out _version, out _createDate, out _updateDate, out _level, out _isDraft, out _contentType, out _properties, @@ -311,7 +311,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache _nodeInitialized = true; } - internal static void InitializeNode(XmlNode xmlNode, bool isPreviewing, + internal static void InitializeNode(XmlPublishedContent node, XmlNode xmlNode, bool isPreviewing, out int id, out Guid key, out int template, out int sortOrder, out string name, out string writerName, out string urlName, out string creatorName, out int creatorId, out int writerId, out string docTypeAlias, out int docTypeId, out string path, out Guid version, out DateTime createDate, out DateTime updateDate, out int level, out bool isDraft, @@ -405,8 +405,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache foreach (var propertyType in contentType.PropertyTypes) { var val = propertyNodes.TryGetValue(propertyType.PropertyTypeAlias.ToLowerInvariant(), out XmlNode n) - ? new XmlPublishedProperty(propertyType, isPreviewing, n) - : new XmlPublishedProperty(propertyType, isPreviewing); + ? new XmlPublishedProperty(propertyType, node, isPreviewing, n) + : new XmlPublishedProperty(propertyType, node, isPreviewing); properties[propertyType.PropertyTypeAlias] = val; } diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedProperty.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedProperty.cs index 48f242b1ca..6e2b000a1e 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedProperty.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlPublishedProperty.cs @@ -22,6 +22,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache private object _objectValue; private bool _objectValueComputed; private readonly bool _isPreviewing; + private readonly IPublishedContent _content; /// /// Gets the raw value of the property. @@ -42,9 +43,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // are single threaded, so the following code should be safe & fast if (_objectValueComputed) return _objectValue; - var inter = PropertyType.ConvertSourceToInter(_sourceValue, _isPreviewing); + var inter = PropertyType.ConvertSourceToInter(_content, _sourceValue, _isPreviewing); // initial reference cache level always is .Content - _objectValue = PropertyType.ConvertInterToObject(PropertyCacheLevel.Content, inter, _isPreviewing); + _objectValue = PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Content, inter, _isPreviewing); _objectValueComputed = true; return _objectValue; } @@ -52,26 +53,27 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache public override object XPathValue { get { throw new NotImplementedException(); } } - public XmlPublishedProperty(PublishedPropertyType propertyType, bool isPreviewing, XmlNode propertyXmlData) - : this(propertyType, isPreviewing) + public XmlPublishedProperty(PublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing, XmlNode propertyXmlData) + : this(propertyType, content, isPreviewing) { if (propertyXmlData == null) throw new ArgumentNullException(nameof(propertyXmlData), "Property xml source is null"); _sourceValue = XmlHelper.GetNodeValue(propertyXmlData); } - public XmlPublishedProperty(PublishedPropertyType propertyType, bool isPreviewing, string propertyData) - : this(propertyType, isPreviewing) + public XmlPublishedProperty(PublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing, string propertyData) + : this(propertyType, content, isPreviewing) { if (propertyData == null) throw new ArgumentNullException(nameof(propertyData)); _sourceValue = propertyData; } - public XmlPublishedProperty(PublishedPropertyType propertyType, bool isPreviewing) + public XmlPublishedProperty(PublishedPropertyType propertyType, IPublishedContent content, bool isPreviewing) : base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored { _sourceValue = string.Empty; + _content = content; _isPreviewing = isPreviewing; } } diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 8e0aaf1fcc..1b99681be5 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -6,7 +6,6 @@ using System.Linq; using System.Web; using Examine.LuceneEngine.SearchCriteria; using Umbraco.Core.Models.PublishedContent; -using Umbraco.Web.Models; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.Services; diff --git a/src/Umbraco.Web/umbraco.presentation/page.cs b/src/Umbraco.Web/umbraco.presentation/page.cs index 2826a1f6ed..8bfcd810e6 100644 --- a/src/Umbraco.Web/umbraco.presentation/page.cs +++ b/src/Umbraco.Web/umbraco.presentation/page.cs @@ -392,8 +392,8 @@ namespace umbraco { // isPreviewing is true here since we want to preview anyway... const bool isPreviewing = true; - var source = PropertyType.ConvertSourceToInter(_sourceValue, isPreviewing); - return PropertyType.ConvertInterToObject(PropertyCacheLevel.Unknown, source, isPreviewing); + var source = PropertyType.ConvertSourceToInter(_content, _sourceValue, isPreviewing); + return PropertyType.ConvertInterToObject(_content, PropertyCacheLevel.Unknown, source, isPreviewing); } }