diff --git a/src/Umbraco.Web/Models/PublishedProperty.cs b/src/Umbraco.Web/Models/PublishedProperty.cs index b24d1260a3..0865f8f915 100644 --- a/src/Umbraco.Web/Models/PublishedProperty.cs +++ b/src/Umbraco.Web/Models/PublishedProperty.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -25,58 +26,56 @@ namespace Umbraco.Web.Models /// Ensures that all conversions took place correctly. internal static IEnumerable MapProperties( IEnumerable propertyTypes, IEnumerable properties, - Func map) + Func map) { - var peResolver = DataTypesResolver.Current; - var dtService = ApplicationContext.Current.Services.DataTypeService; - return MapProperties(propertyTypes, properties, peResolver, dtService, map); + return propertyTypes.Select(x => + { + var property = properties.SingleOrDefault(xx => xx.Alias == x.PropertyTypeAlias); + var value = property == null ? null : property.Value; + return map(x, ConvertPropertyValueFromDbToData(x, value)); + }); } /// - /// Maps a collection of Property to a collection of IPublishedProperty for a specified collection of PublishedPropertyType. + /// Converts a database property value to a "data" value ie a value that we can pass to + /// IPropertyValueConverter. /// - /// The published property types. - /// The properties. - /// A mapping function. - /// A DataTypesResolver instance. - /// An IDataTypeService instance. - /// A collection of IPublishedProperty corresponding to the collection of PublishedPropertyType - /// and taking values from the collection of Property. - /// Ensures that all conversions took place correctly. - internal static IEnumerable MapProperties( - IEnumerable propertyTypes, IEnumerable properties, - DataTypesResolver dataTypesResolver, IDataTypeService dataTypeService, - Func map) + /// The published property type. + /// The value. + /// The converted value. + internal static object ConvertPropertyValueFromDbToData(PublishedPropertyType propertyType, object value) { - return propertyTypes - .Select(x => - { - var p = properties.SingleOrDefault(xx => xx.Alias == x.PropertyTypeAlias); - var v = p == null || p.Value == null ? null : p.Value; - if (v != null) - { - // note - not sure about the performance here - var dataTypeDefinition = global::umbraco.cms.businesslogic.datatype.DataTypeDefinition - .GetDataTypeDefinition(x.DataTypeId); - var dataType = dataTypeDefinition.DataType; - if (dataType != null) - { - var data = dataType.Data; - data.Value = v; - var n = data.ToXMl(new XmlDocument()); - if (n.NodeType == XmlNodeType.CDATA || n.NodeType == XmlNodeType.Text) - v = n.InnerText; - else if (n.NodeType == XmlNodeType.Element) - v = n.InnerXml; - // note - is there anything else we should take care of? - } - } - // fixme - means that the IPropertyValueConverter will always get a string - // fixme and never an int or DateTime that's in the DB unless the value editor has - // fixme a way to say it's OK to use what's in the DB? + if (value == null) return null; - return map(x, p, v); - }); + // We are converting to string, even for database values which are integer or + // DateTime, which is not optimum. Doing differently would require that we have a way to tell + // whether the conversion to XML string changes something or not... which we don't, and we + // don't want to implement it as PropertyValueEditor.ConvertDbToXml/String should die anyway. + + // Don't think about improving the situation here: this is a corner case and the real + // thing to do is to get rig of PropertyValueEditor.ConvertDbToXml/String. + + // works but better use the new API + //var dataTypeDefinition = global::umbraco.cms.businesslogic.datatype.DataTypeDefinition.GetDataTypeDefinition(propertyType.DataTypeId); + //var dataType = dataTypeDefinition.DataType; + + // transient resolver will create a new object each time we call it + // so it is safe to alter DataTypeDefinitionId, Data, etc. + var dataType = DataTypesResolver.Current.GetById(propertyType.PropertyEditorGuid); + if (dataType != null) + { + dataType.DataTypeDefinitionId = propertyType.DataTypeId; // required else conversion fails + var data = dataType.Data; + data.Value = value; + var n = data.ToXMl(new XmlDocument()); + if (n.NodeType == XmlNodeType.CDATA || n.NodeType == XmlNodeType.Text) + value = n.InnerText; + else if (n.NodeType == XmlNodeType.Element) + value = n.InnerXml; + // assuming there are no other node types that we need to take care of + } + + return value; } } } diff --git a/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs b/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs index e538d135d3..bdbc28f3cf 100644 --- a/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs +++ b/src/Umbraco.Web/PublishedCache/MemberPublishedContent.cs @@ -34,7 +34,7 @@ namespace Umbraco.Web.PublishedCache throw new InvalidOperationException("Could not get member type with alias " + _member.ContentTypeAlias); } _properties = PublishedProperty.MapProperties(_publishedMemberType.PropertyTypes, _member.Properties, - (t, p, v) => new RawValueProperty(t, v ?? string.Empty)) + (t, v) => new RawValueProperty(t, v ?? string.Empty)) .ToArray(); }