Refactor - IPublishedContent, converters, fragments

This commit is contained in:
Stephan
2016-06-10 16:37:28 +02:00
parent 78ab9c087d
commit d08412c0fe
123 changed files with 1513 additions and 1447 deletions

View File

@@ -1,6 +1,7 @@
using System;
using Umbraco.Core.Models;
using System.Web;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.Dynamics
{
@@ -32,7 +33,7 @@ namespace Umbraco.Core.Dynamics
internal PropertyResultType PropertyType { get { return _type; } }
public string PropertyTypeAlias { get { return _source == null ? _alias : _source.PropertyTypeAlias; } }
public object DataValue { get { return _source == null ? _value : _source.DataValue; } }
public object SourceValue { get { return _source == null ? _value : _source.SourceValue; } }
public bool HasValue { get { return _source == null || _source.HasValue; } }
public object Value { get { return _source == null ? _value : _source.Value; } }
public object XPathValue { get { return Value == null ? null : Value.ToString(); } }

View File

@@ -1,8 +1,7 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.Models
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents a cached content.
@@ -14,21 +13,11 @@ namespace Umbraco.Core.Models
/// cached preview (so, maybe unpublished) content. A better name would therefore be ICachedContent, as
/// has been suggested. However, can't change now. Maybe in v7?</para>
/// </remarks>
public interface IPublishedContent
public interface IPublishedContent : IPublishedFragment
{
#region ContentType
/// <summary>
/// Gets the content type.
/// </summary>
PublishedContentType ContentType { get; }
#endregion
#region Content
int Id { get; }
Guid Key { get; }
int TemplateId { get; }
int SortOrder { get; }
string Name { get; }
@@ -78,29 +67,6 @@ namespace Umbraco.Core.Models
#region Properties
/// <summary>
/// Gets the properties of the content.
/// </summary>
/// <remarks>
/// <para>Contains one <c>IPublishedProperty</c> for each property defined for the content type, including
/// inherited properties. Some properties may have no value.</para>
/// <para>The properties collection of an IPublishedContent instance should be read-only ie it is illegal
/// to add properties to the collection.</para>
/// </remarks>
ICollection<IPublishedProperty> Properties { get; }
/// <summary>
/// Gets a property identified by its alias.
/// </summary>
/// <param name="alias">The property alias.</param>
/// <returns>The property identified by the alias.</returns>
/// <remarks>
/// <para>If the content type has no property with that alias, including inherited properties, returns <c>null</c>,</para>
/// <para>otherwise return a property -- that may have no value (ie <c>HasValue</c> is <c>false</c>).</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
IPublishedProperty GetProperty(string alias);
/// <summary>
/// Gets a property identified by its alias.
/// </summary>
@@ -115,21 +81,6 @@ namespace Umbraco.Core.Models
/// </remarks>
IPublishedProperty GetProperty(string alias, bool recurse);
/// <summary>
/// Gets the value of a property identified by its alias.
/// </summary>
/// <param name="alias">The property alias.</param>
/// <returns>The value of the property identified by the alias.</returns>
/// <remarks>
/// <para>If <c>GetProperty(alias)</c> is <c>null</c> then returns <c>null</c> else return <c>GetProperty(alias).Value</c>.</para>
/// <para>So if the property has no value, returns the default value for that property type.</para>
/// <para>This one is defined here really because we cannot define index extension methods, but all it should do is:
/// <code>var p = GetProperty(alias); return p == null ? null : p.Value;</code> and nothing else.</para>
/// <para>The recursive syntax (eg "_title") is _not_ supported here.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
object this[string alias] { get; } // todo - should obsolete this[alias] (when?)
#endregion
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents a facade fragment.
/// </summary>
public interface IPublishedFragment
{
#region ContentType
/// <summary>
/// Gets the content type.
/// </summary>
PublishedContentType ContentType { get; }
#endregion
#region Content
/// <summary>
/// Gets the unique key of the facade item.
/// </summary>
Guid Key { get; }
#endregion
#region Properties
/// <summary>
/// Gets the properties of the content.
/// </summary>
/// <remarks>Contains one <c>IPublishedProperty</c> for each property defined for the content type, including
/// inherited properties. Some properties may have no value.</remarks>
IEnumerable<IPublishedProperty> Properties { get; }
/// <summary>
/// Gets a property identified by its alias.
/// </summary>
/// <param name="alias">The property alias.</param>
/// <returns>The property identified by the alias.</returns>
/// <remarks>
/// <para>If the content type has no property with that alias, including inherited properties, returns <c>null</c>,</para>
/// <para>otherwise return a property -- that may have no value (ie <c>HasValue</c> is <c>false</c>).</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
IPublishedProperty GetProperty(string alias);
#endregion
}
}

View File

@@ -1,4 +1,4 @@
namespace Umbraco.Core.Models
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents a property of an <c>IPublishedContent</c>.
@@ -24,18 +24,18 @@ namespace Umbraco.Core.Models
bool HasValue { get; }
/// <summary>
/// Gets the data value of the property.
/// Gets the source value of the property.
/// </summary>
/// <remarks>
/// <para>The data value is whatever was passed to the property when it was instanciated, and it is
/// <para>The source value is whatever was passed to the property when it was instanciated, and it is
/// somewhat implementation-dependent -- depending on how the IPublishedCache is implemented.</para>
/// <para>The XmlPublishedCache raw values are strings exclusively since they come from the Xml cache.</para>
/// <para>For other caches that get their raw value from the database, it would be either a string,
/// an integer (Int32), or a date and time (DateTime).</para>
/// <para>The XmlPublishedCache source values are strings exclusively since they come from the Xml cache.</para>
/// <para>For other caches that get their source value from the database, it would be either a string,
/// an integer (Int32), a date and time (DateTime) or a decimal (double).</para>
/// <para>If you're using that value, you're probably wrong, unless you're doing some internal
/// Umbraco stuff.</para>
/// </remarks>
object DataValue { get; }
object SourceValue { get; }
/// <summary>
/// Gets the object value of the property.

View File

@@ -87,10 +87,7 @@ namespace Umbraco.Core.Models.PublishedContent
_properties.Add(property);
}
bool IPublishedContentExtended.HasAddedProperties
{
get { return _properties != null; }
}
bool IPublishedContentExtended.HasAddedProperties => _properties != null;
#endregion
@@ -98,28 +95,9 @@ namespace Umbraco.Core.Models.PublishedContent
private ICollection<IPublishedProperty> _properties;
public override ICollection<IPublishedProperty> Properties
{
get
{
return _properties == null
public override IEnumerable<IPublishedProperty> Properties => _properties == null
? Content.Properties
: Content.Properties.Union(_properties).ToList();
}
}
public override object this[string alias]
{
get
{
if (_properties != null)
{
var property = _properties.FirstOrDefault(prop => prop.PropertyTypeAlias.InvariantEquals(alias));
if (property != null) return property.HasValue ? property.Value : null;
}
return Content[alias];
}
}
public override IPublishedProperty GetProperty(string alias)
{

View File

@@ -70,7 +70,7 @@ namespace Umbraco.Core.Models.PublishedContent
InitializeIndexes();
}
// create detached content type - ie does not match anything in the DB
// create floating content type - ie does not match anything in the DB
internal PublishedContentType(string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
: this(0, alias, compositionAliases, propertyTypes)
{ }

View File

@@ -108,9 +108,7 @@ namespace Umbraco.Core.Models.PublishedContent
#region Properties
public virtual ICollection<IPublishedProperty> Properties => Content.Properties;
public virtual object this[string alias] => Content[alias];
public virtual IEnumerable<IPublishedProperty> Properties => Content.Properties;
public virtual IPublishedProperty GetProperty(string alias)
{

View File

@@ -1,4 +1,4 @@
namespace Umbraco.Core.Models
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// The type of published content, ie whether it is a content or a media.

View File

@@ -1,4 +1,5 @@
using System;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Models.PublishedContent
{
@@ -8,23 +9,20 @@ namespace Umbraco.Core.Models.PublishedContent
/// </summary>
internal abstract class PublishedPropertyBase : IPublishedProperty
{
public readonly PublishedPropertyType PropertyType;
protected PublishedPropertyBase(PublishedPropertyType propertyType)
protected PublishedPropertyBase(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel)
{
if (propertyType == null)
throw new ArgumentNullException("propertyType");
if (propertyType == null) throw new ArgumentNullException(nameof(propertyType));
PropertyType = propertyType;
ReferenceCacheLevel = referenceCacheLevel;
}
public string PropertyTypeAlias
{
get { return PropertyType.PropertyTypeAlias; }
}
public PublishedPropertyType PropertyType { get; }
public string PropertyTypeAlias => PropertyType.PropertyTypeAlias;
public PropertyCacheLevel ReferenceCacheLevel { get; }
// these have to be provided by the actual implementation
public abstract bool HasValue { get; }
public abstract object DataValue { get; }
public abstract object SourceValue { get; }
public abstract object Value { get; }
public abstract object XPathValue { get; }
}

View File

@@ -18,24 +18,6 @@ namespace Umbraco.Core.Models.PublishedContent
{
#region Constructors
// clone
private PublishedPropertyType(PublishedPropertyType orig)
{
ContentType = orig.ContentType;
PropertyTypeAlias = orig.PropertyTypeAlias;
DataTypeId = orig.DataTypeId;
PropertyEditorAlias = orig.PropertyEditorAlias;
_converter = orig._converter;
_sourceCacheLevel = orig._sourceCacheLevel;
_objectCacheLevel = orig._objectCacheLevel;
_xpathCacheLevel = orig._xpathCacheLevel;
_clrType = orig._clrType;
_initialized = true;
// do NOT copy the reduced cache levels
// as we should NOT clone a nested / detached type
}
/// <summary>
/// Initialize a new instance of the <see cref="PublishedPropertyType"/> class within a <see cref="PublishedContentType"/>,
/// with a <see cref="PropertyType"/>.
@@ -115,7 +97,6 @@ namespace Umbraco.Core.Models.PublishedContent
{
// ContentType
// - in unit tests, to be set by PublishedContentType when creating it
// - in detached types, remains null
PropertyTypeAlias = propertyTypeAlias;
@@ -161,10 +142,7 @@ namespace Umbraco.Core.Models.PublishedContent
private readonly object _locker = new object();
private volatile bool _initialized;
private IPropertyValueConverter _converter;
private PropertyCacheLevel _sourceCacheLevel;
private PropertyCacheLevel _objectCacheLevel;
private PropertyCacheLevel _xpathCacheLevel;
private PropertyCacheLevel _cacheLevel;
private Type _clrType = typeof (object);
@@ -242,129 +220,68 @@ namespace Umbraco.Core.Models.PublishedContent
}
var converterMeta = _converter as IPropertyValueConverterMeta;
_cacheLevel = _converter?.GetPropertyCacheLevel(this) ?? PropertyCacheLevel.Facade;
_clrType = _converter?.GetPropertyValueType(this) ?? typeof(object);
}
// get the cache levels, quietely fixing the inconsistencies (no need to throw, really)
if (converterMeta != null)
// gets the cache level
public PropertyCacheLevel CacheLevel
{
_sourceCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Source);
_objectCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.Object);
_xpathCacheLevel = converterMeta.GetPropertyCacheLevel(this, PropertyCacheValue.XPath);
}
else
get
{
_sourceCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Source);
_objectCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.Object);
_xpathCacheLevel = GetCacheLevel(_converter, PropertyCacheValue.XPath);
}
if (_objectCacheLevel < _sourceCacheLevel) _objectCacheLevel = _sourceCacheLevel;
if (_xpathCacheLevel < _sourceCacheLevel) _xpathCacheLevel = _sourceCacheLevel;
// get the CLR type of the converted value
if (_converter != null)
{
if (converterMeta != null)
{
_clrType = converterMeta.GetPropertyValueType(this);
}
else
{
var attr = _converter.GetType().GetCustomAttribute<PropertyValueTypeAttribute>(false);
if (attr != null)
_clrType = attr.Type;
}
EnsureInitialized();
return _cacheLevel;
}
}
static PropertyCacheLevel GetCacheLevel(IPropertyValueConverter converter, PropertyCacheValue value)
{
if (converter == null)
return PropertyCacheLevel.Request;
var attr = converter.GetType().GetCustomAttributes<PropertyValueCacheAttribute>(false)
.FirstOrDefault(x => x.Value == value || x.Value == PropertyCacheValue.All);
return attr?.Level ?? PropertyCacheLevel.Request;
}
// converts the raw value into the source value
// converts the source value into the inter value
// uses converters, else falls back to dark (& performance-wise expensive) magic
// source: the property raw value
// source: the property source value
// preview: whether we are previewing or not
public object ConvertDataToSource(object source, bool preview)
public object ConvertSourceToInter(object source, bool preview)
{
EnsureInitialized();
// use the converter else use dark (& performance-wise expensive) magic
return _converter != null
? _converter.ConvertDataToSource(this, source, preview)
? _converter.ConvertSourceToInter(this, source, preview)
: ConvertUsingDarkMagic(source);
}
// gets the source cache level
public PropertyCacheLevel SourceCacheLevel
{
get
{
EnsureInitialized();
return _sourceCacheLevel;
}
}
// converts the source value into the clr value
// uses converters, else returns the source value
// source: the property source value
// converts the inter value into the clr value
// uses converters, else returns the inter value
// inter: the property inter value
// preview: whether we are previewing or not
public object ConvertSourceToObject(object source, bool preview)
public object ConvertInterToObject(PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
EnsureInitialized();
// use the converter if any
// else just return the source value
// else just return the inter value
return _converter != null
? _converter.ConvertSourceToObject(this, source, preview)
: source;
? _converter.ConvertInterToObject(this, referenceCacheLevel, inter, preview)
: inter;
}
// gets the value cache level
public PropertyCacheLevel ObjectCacheLevel
{
get
{
EnsureInitialized();
return _objectCacheLevel;
}
}
// converts the source value into the xpath value
// uses the converter else returns the source value as a string
// converts the inter value into the xpath value
// uses the converter else returns the inter value as a string
// if successful, returns either a string or an XPathNavigator
// source: the property source value
// inter: the property inter value
// preview: whether we are previewing or not
public object ConvertSourceToXPath(object source, bool preview)
public object ConvertInterToXPath(PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
EnsureInitialized();
// use the converter if any
if (_converter != null)
return _converter.ConvertSourceToXPath(this, source, preview);
return _converter.ConvertInterToXPath(this, referenceCacheLevel, inter, preview);
// else just return the source value as a string or an XPathNavigator
if (source == null) return null;
var xElement = source as XElement;
// else just return the inter value as a string or an XPathNavigator
if (inter == null) return null;
var xElement = inter as XElement;
if (xElement != null)
return xElement.CreateNavigator();
return source.ToString().Trim();
}
// gets the xpath cache level
public PropertyCacheLevel XPathCacheLevel
{
get
{
EnsureInitialized();
return _xpathCacheLevel;
}
return inter.ToString().Trim();
}
internal static object ConvertUsingDarkMagic(object source)
@@ -409,128 +326,5 @@ namespace Umbraco.Core.Models.PublishedContent
}
#endregion
#region Detached
private PropertyCacheLevel _sourceCacheLevelReduced = 0;
private PropertyCacheLevel _objectCacheLevelReduced = 0;
private PropertyCacheLevel _xpathCacheLevelReduced = 0;
internal bool IsDetachedOrNested => _sourceCacheLevelReduced != 0;
/// <summary>
/// Creates a detached clone of this published property type.
/// </summary>
/// <returns>A detached clone of this published property type.</returns>
/// <remarks>
/// <para>Only a published property type that has not already been detached or nested, can be detached.</para>
/// <para>Use detached published property type when creating detached properties outside of a published content.</para>
/// </remarks>
internal PublishedPropertyType Detached()
{
// verify
if (IsDetachedOrNested)
throw new Exception("PublishedPropertyType is already detached/nested.");
var detached = new PublishedPropertyType(this);
detached._sourceCacheLevel
= detached._objectCacheLevel
= detached._xpathCacheLevel
= PropertyCacheLevel.Content;
// set to none to a) indicate it's detached / nested and b) make sure any nested
// types switch all their cache to .Content
detached._sourceCacheLevelReduced
= detached._objectCacheLevelReduced
= detached._xpathCacheLevelReduced
= PropertyCacheLevel.None;
return detached;
}
/// <summary>
/// Creates a nested clone of this published property type within a specified container published property type.
/// </summary>
/// <param name="containerType">The container published property type.</param>
/// <returns>A nested clone of this published property type</returns>
/// <remarks>
/// <para>Only a published property type that has not already been detached or nested, can be nested.</para>
/// <para>Use nested published property type when creating detached properties within a published content.</para>
/// </remarks>
internal PublishedPropertyType Nested(PublishedPropertyType containerType)
{
// verify
if (IsDetachedOrNested)
throw new Exception("PublishedPropertyType is already detached/nested.");
var nested = new PublishedPropertyType(this);
// before we reduce, both xpath and object are >= source, and
// the way reduce works, the relative order of resulting xpath, object and source are preserved
// Reduce() will set _xxxCacheLevelReduced thus indicating that the type is detached / nested
Reduce(_sourceCacheLevel, _sourceCacheLevelReduced, ref nested._sourceCacheLevel, ref nested._sourceCacheLevelReduced);
Reduce(_objectCacheLevel, _objectCacheLevelReduced, ref nested._objectCacheLevel, ref nested._objectCacheLevelReduced);
Reduce(_xpathCacheLevel, _xpathCacheLevelReduced, ref nested._xpathCacheLevel, ref nested._xpathCacheLevelReduced);
return nested;
}
private static void Reduce(
PropertyCacheLevel containerCacheLevel, PropertyCacheLevel containerCacheLevelReduced,
ref PropertyCacheLevel nestedCacheLevel, ref PropertyCacheLevel nestedCacheLevelReduced)
{
// initialize if required
if (containerCacheLevelReduced == 0)
containerCacheLevelReduced = containerCacheLevel;
switch (containerCacheLevelReduced)
{
case PropertyCacheLevel.None:
// once .None, force .Content for everything
nestedCacheLevel = PropertyCacheLevel.Content;
nestedCacheLevelReduced = PropertyCacheLevel.None; // and propagate
break;
case PropertyCacheLevel.Request:
// once .Request, force .Content for everything
nestedCacheLevel = PropertyCacheLevel.Content;
nestedCacheLevelReduced = PropertyCacheLevel.Request; // and propagate
break;
case PropertyCacheLevel.Content:
// as long as .Content, accept anything
nestedCacheLevelReduced = nestedCacheLevel; // and it becomes the nested reduced
break;
case PropertyCacheLevel.ContentCache:
// once .ContentCache, accept .Request and .Content but not .ContentCache
switch (nestedCacheLevel)
{
case PropertyCacheLevel.Request:
case PropertyCacheLevel.None:
// accept
nestedCacheLevelReduced = nestedCacheLevel; // and it becomes the nested reduced
break;
case PropertyCacheLevel.Content:
// accept
nestedCacheLevelReduced = PropertyCacheLevel.ContentCache; // and propagate
break;
case PropertyCacheLevel.ContentCache:
// force .Content
nestedCacheLevel = PropertyCacheLevel.Content;
nestedCacheLevelReduced = PropertyCacheLevel.ContentCache; // and propagate
break;
default:
throw new Exception("Unsupported PropertyCacheLevel value.");
}
break;
default:
throw new Exception("Unsupported PropertyCacheLevel value.");
}
}
#endregion
}
}

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors
{
@@ -14,6 +15,20 @@ namespace Umbraco.Core.PropertyEditors
/// <returns>A value indicating whether the converter supports a property type.</returns>
bool IsConverter(PublishedPropertyType propertyType);
/// <summary>
/// Gets the type of values returned by the converter.
/// </summary>
/// <param name="propertyType">The property type.</param>
/// <returns>The CLR type of values returned by the converter.</returns>
Type GetPropertyValueType(PublishedPropertyType propertyType);
/// <summary>
/// Gets the property cache level of a specified value.
/// </summary>
/// <param name="propertyType">The property type.</param>
/// <returns>The property cache level of the specified value.</returns>
PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType);
/// <summary>
/// Converts a property Data value to a Source value.
/// </summary>
@@ -32,25 +47,27 @@ namespace Umbraco.Core.PropertyEditors
/// strings, and xml-whitespace strings appropriately, ie it should know whether to preserve
/// whitespaces.</para>
/// </remarks>
object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview);
object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview);
/// <summary>
/// Converts a property Source value to an Object value.
/// </summary>
/// <param name="propertyType">The property type.</param>
/// <param name="source">The source value.</param>
/// <param name="referenceCacheLevel">fixme</param>
/// <param name="inter">The source value.</param>
/// <param name="preview">A value indicating whether conversion should take place in preview mode.</param>
/// <returns>The result of the conversion.</returns>
/// <remarks>The converter should know how to convert a <c>null</c> source value, or any source value
/// indicating that no value has been assigned to the property. It is up to the converter to determine
/// what to return in that case: either <c>null</c>, or the default value...</remarks>
object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview);
object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
/// <summary>
/// Converts a property Source value to an XPath value.
/// </summary>
/// <param name="propertyType">The property type.</param>
/// <param name="source">The source value.</param>
/// <param name="referenceCacheLevel">fixme</param>
/// <param name="inter">The source value.</param>
/// <param name="preview">A value indicating whether conversion should take place in preview mode.</param>
/// <returns>The result of the conversion.</returns>
/// <remarks>
@@ -63,6 +80,6 @@ namespace Umbraco.Core.PropertyEditors
/// <para>The converter may want to return an XML fragment that represent a part of the content tree,
/// but should pay attention not to create infinite loops that would kill XPath and XSLT.</para>
/// </remarks>
object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview);
object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
}
}

View File

@@ -1,29 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Provides published content properties converter meta data.
/// </summary>
public interface IPropertyValueConverterMeta : IPropertyValueConverter
{
/// <summary>
/// Gets the type of values returned by the converter.
/// </summary>
/// <param name="propertyType">The property type.</param>
/// <returns>The CLR type of values returned by the converter.</returns>
Type GetPropertyValueType(PublishedPropertyType propertyType);
/// <summary>
/// Gets the property cache level of a specified value.
/// </summary>
/// <param name="propertyType">The property type.</param>
/// <param name="cacheValue">The property value.</param>
/// <returns>The property cache level of the specified value.</returns>
PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType, PropertyCacheValue cacheValue);
}
}

View File

@@ -10,6 +10,11 @@
// object level >= source level
// xpath level >= source level
/// <summary>
/// Default value.
/// </summary>
Unknown = 0,
/// <summary>
/// Indicates that the property value can be cached at the content level, ie it can be
/// cached until the content itself is modified.
@@ -17,16 +22,16 @@
Content = 1,
/// <summary>
/// Indicates that the property value can be cached at the content cache level, ie it can
/// Indicates that the property value can be cached at the snapshot level, ie it can
/// be cached until any content in the cache is modified.
/// </summary>
ContentCache = 2,
Snapshot = 2,
/// <summary>
/// Indicates that the property value can be cached at the request level, ie it can be
/// cached for the duration of the current request.
/// Indicates that the property value can be cached at the facade level, ie it can be
/// cached for the duration of the current facade (ie, in most cases, request).
/// </summary>
Request = 3,
Facade = 3,
/// <summary>
/// Indicates that the property value cannot be cached and has to be converted any time

View File

@@ -1,29 +0,0 @@
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Specifies the different types of property cacheable values.
/// </summary>
public enum PropertyCacheValue
{
/// <summary>
/// All of them.
/// </summary>
All,
/// <summary>
/// The source value ie the internal value that can be used to create both the
/// object value and the xpath value.
/// </summary>
Source,
/// <summary>
/// The object value ie the strongly typed value of the property as seen when accessing content via C#.
/// </summary>
Object,
/// <summary>
/// The XPath value ie the value of the property as seen when accessing content via XPath.
/// </summary>
XPath
}
}

View File

@@ -1,34 +0,0 @@
using System;
using log4net.Core;
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Indicates the cache level for a property cacheable value.
/// </summary>
/// <remarks>Use this attribute to mark property values converters.</remarks>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]
public class PropertyValueCacheAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="PropertyValueCacheAttribute"/> class with a cacheable value and a cache level.
/// </summary>
/// <param name="value">The cacheable value.</param>
/// <param name="level">The cache level.</param>
public PropertyValueCacheAttribute(PropertyCacheValue value, PropertyCacheLevel level)
{
Value = value;
Level = level;
}
/// <summary>
/// Gets or sets the cacheable value.
/// </summary>
public PropertyCacheValue Value { get; private set; }
/// <summary>
/// Gets or sets the cache level;
/// </summary>
public PropertyCacheLevel Level { get; private set; }
}
}

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors
{
@@ -12,19 +13,29 @@ namespace Umbraco.Core.PropertyEditors
return false;
}
public virtual object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public virtual Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (object);
}
public virtual PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Facade;
}
public virtual object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
return PublishedPropertyType.ConvertUsingDarkMagic(source);
}
public virtual object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
public virtual object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
return source;
return inter;
}
public virtual object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public virtual object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
return source?.ToString() ?? string.Empty;
return inter?.ToString() ?? string.Empty;
}
}
}

View File

@@ -1,26 +0,0 @@
using System;
namespace Umbraco.Core.PropertyEditors
{
/// <summary>
/// Indicates the CLR type of property object values returned by a converter.
/// </summary>
/// <remarks>Use this attribute to mark property values converters.</remarks>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = false)]
public class PropertyValueTypeAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="PropertyValueTypeAttribute"/> class with a type.
/// </summary>
/// <param name="type">The type.</param>
public PropertyValueTypeAttribute(Type type)
{
Type = type;
}
/// <summary>
/// Gets or sets the type.
/// </summary>
public Type Type { get; private set; }
}
}

View File

@@ -9,7 +9,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ColorPickerAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
// make sure it's a string
return source?.ToString() ?? string.Empty;

View File

@@ -1,13 +1,10 @@
using System;
using System.Globalization;
using System.Linq;
using System.Xml;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(DateTime))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DatePickerValueConverter : PropertyValueConverterBase
{
private static readonly string[] PropertyEditorAliases =
@@ -21,7 +18,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return PropertyEditorAliases.Contains(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (DateTime);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return DateTime.MinValue;
@@ -45,10 +52,10 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
// default ConvertSourceToObject just returns source ie a DateTime value
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a DateTime already
return XmlConvert.ToString((DateTime)source, XmlDateTimeSerializationMode.Unspecified);
return XmlConvert.ToString((DateTime)inter, XmlDateTimeSerializationMode.Unspecified);
}
}
}

View File

@@ -1,10 +1,9 @@
using System.Globalization;
using System;
using System.Globalization;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(decimal))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class DecimalValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -12,7 +11,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Constants.PropertyEditors.DecimalAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (decimal);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return 0M;

View File

@@ -16,8 +16,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
/// This ensures that the grid config is merged in with the front-end value
/// </summary>
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
[PropertyValueType(typeof(JToken))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class GridValueConverter : JsonValueConverter
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -25,7 +23,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.GridAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (JToken);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();

View File

@@ -13,12 +13,25 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
/// This ensures that the cropper config (pre-values/crops) are merged in with the front-end value.
/// </summary>
[DefaultPropertyValueConverter(typeof (JsonValueConverter))] //this shadows the JsonValueConverter
[PropertyValueType(typeof (JToken))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class ImageCropperValueConverter : JsonValueConverter
{
private readonly IDataTypeService _dataTypeService;
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ImageCropperAlias);
}
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (JToken);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public ImageCropperValueConverter()
{
_dataTypeService = ApplicationContext.Current.Services.DataTypeService;
@@ -30,11 +43,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
_dataTypeService = dataTypeService;
}
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ImageCropperAlias);
}
internal static void MergePreValues(JObject currentValue, IDataTypeService dataTypeService, int dataTypeId)
{
//need to lookup the pre-values for this data type
@@ -91,7 +99,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
}
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();

View File

@@ -1,9 +1,8 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(int))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class IntegerValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -11,7 +10,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Constants.PropertyEditors.IntegerAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (int);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return 0;

View File

@@ -13,8 +13,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
/// Since this is a default (umbraco) converter it will be ignored if another converter found conflicts with this one.
/// </remarks>
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(JToken))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class JsonValueConverter : PropertyValueConverterBase
{
/// <summary>
@@ -29,7 +27,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return propertyEditor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.Json);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (JToken);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
@@ -12,15 +13,24 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
/// Example: http://issues.umbraco.org/issue/U4-7929
/// </remarks>
[DefaultPropertyValueConverter]
[PropertyValueType(typeof (string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class LabelValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
{
return Constants.PropertyEditors.NoEditAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (string);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
return source == null ? string.Empty : source.ToString();
}

View File

@@ -4,8 +4,6 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class MarkdownEditorValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -13,7 +11,18 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Constants.PropertyEditors.MarkdownEditorAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IHtmlString);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
// PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
// in xml a string is: string
// in the database a string is: string
@@ -21,16 +30,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return source;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return new HtmlString(source == null ? string.Empty : (string)source);
return new HtmlString(inter == null ? string.Empty : (string) inter);
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source;
return inter?.ToString() ?? string.Empty;
}
}
}

View File

@@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(IEnumerable<string>))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class MultipleTextStringValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -17,7 +13,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IEnumerable<string>);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
// data is (both in database and xml):
// <keyFeatureList>
@@ -58,13 +64,13 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return values.ToArray();
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
var d = new XmlDocument();
var e = d.CreateElement("values");
d.AppendChild(e);
var values = (IEnumerable<string>) source;
var values = (IEnumerable<string>) inter;
foreach (var value in values)
{
var ee = d.CreateElement("value");

View File

@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
@@ -14,8 +15,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
/// to use that converter for values whose .ToString() would depend on other content.</para>
/// </remarks>
[DefaultPropertyValueConverter]
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class MustBeStringValueConverter : PropertyValueConverterBase
{
private static readonly string[] Aliases =
@@ -29,7 +28,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Aliases.Contains(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (string);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
return source.ToString();

View File

@@ -1,13 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class TextStringValueConverter : PropertyValueConverterBase
{
private readonly static string[] PropertyTypeAliases =
@@ -21,7 +17,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return PropertyTypeAliases.Contains(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (string);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
// in xml a string is: string
// in the database a string is: string
@@ -29,16 +35,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return source;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source ?? string.Empty;
return inter ?? string.Empty;
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source;
return inter;
}
}
}

View File

@@ -7,9 +7,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
/// <summary>
/// Value converter for the RTE so that it always returns IHtmlString so that Html.Raw doesn't have to be used.
/// </summary>
// PropertyCacheLevel.Content is ok here because that version of RTE converter does not parse {locallink} nor executes macros
[PropertyValueType(typeof(IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class TinyMceValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -17,7 +14,18 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return propertyType.PropertyEditorAlias == Constants.PropertyEditors.TinyMCEAlias;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IHtmlString);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
// PropertyCacheLevel.Content is ok here because that converter does not parse {locallink} nor executes macros
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
// in xml a string is: string
// in the database a string is: string
@@ -25,16 +33,16 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return source;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return new HtmlString(source == null ? string.Empty : (string)source);
return new HtmlString(inter == null ? string.Empty : (string)inter);
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source;
return inter;
}
}
}

View File

@@ -3,8 +3,6 @@ using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(bool))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class YesNoValueConverter : PropertyValueConverterBase
{
public override bool IsConverter(PublishedPropertyType propertyType)
@@ -12,7 +10,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return propertyType.PropertyEditorAlias == Constants.PropertyEditors.TrueFalseAlias;
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (bool);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
// in xml a boolean is: string
// in the database a boolean is: string "1" or "0" or empty
@@ -48,10 +56,10 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
// default ConvertSourceToObject just returns source ie a boolean value
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a boolean already
return (bool)source ? "1" : "0";
return (bool)inter ? "1" : "0";
}
}
}

View File

@@ -260,6 +260,7 @@
<DependentUpon>Files.resx</DependentUpon>
</Compile>
<Compile Include="Models\DictionaryItemExtensions.cs" />
<Compile Include="Models\PublishedContent\IPublishedFragment.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionEight\AddContentNuTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionEight\RefactorXmlColumns.cs" />
<Compile Include="Plugins\HideFromTypeFinderAttribute.cs" />
@@ -540,7 +541,7 @@
<Compile Include="Models\EntityExtensions.cs" />
<Compile Include="Models\Folder.cs" />
<Compile Include="Models\IMemberGroup.cs" />
<Compile Include="Models\IPublishedProperty.cs" />
<Compile Include="Models\PublishedContent\IPublishedProperty.cs" />
<Compile Include="Models\IRelation.cs" />
<Compile Include="Models\IRelationType.cs" />
<Compile Include="Models\Membership\EntityPermissionSet.cs" />
@@ -610,9 +611,6 @@
<Compile Include="Persistence\SqlSyntax\SqlServerVersionName.cs" />
<Compile Include="Persistence\SqlSyntax\SqlSyntaxProviderExtensions.cs" />
<Compile Include="PropertyEditors\LegacyPropertyEditorIdToAliasConverter.cs" />
<Compile Include="PropertyEditors\PropertyCacheValue.cs" />
<Compile Include="PropertyEditors\PropertyValueCacheAttribute.cs" />
<Compile Include="PropertyEditors\PropertyValueTypeAttribute.cs" />
<Compile Include="PropertyEditors\PropertyCacheLevel.cs" />
<Compile Include="PropertyEditors\PropertyValueConverterBase.cs" />
<Compile Include="PropertyEditors\SupportTagsAttribute.cs" />
@@ -620,7 +618,6 @@
<Compile Include="PropertyEditors\TagValueType.cs" />
<Compile Include="PropertyEditors\ValueConverters\ColorPickerValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\IntegerValueConverter.cs" />
<Compile Include="PropertyEditors\IPropertyValueConverterMeta.cs" />
<Compile Include="PropertyEditors\ValueConverters\JsonValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\MultipleTextStringValueConverter.cs" />
<Compile Include="PropertyEditors\ValueConverters\MarkdownEditorValueConverter.cs" />
@@ -682,7 +679,7 @@
<Compile Include="Models\Membership\User.cs" />
<Compile Include="Models\Membership\UserType.cs" />
<Compile Include="Models\PropertyExtensions.cs" />
<Compile Include="Models\PublishedItemType.cs" />
<Compile Include="Models\PublishedContent\PublishedItemType.cs" />
<Compile Include="Models\PublishedState.cs" />
<Compile Include="Models\Rdbms\ContentType2ContentTypeDto.cs" />
<Compile Include="Models\Rdbms\PropertyTypeGroupDto.cs" />
@@ -1124,7 +1121,7 @@
<Compile Include="Dynamics\Res.cs" />
<Compile Include="Dynamics\Signature.cs" />
<Compile Include="ExpressionExtensions.cs" />
<Compile Include="Models\IPublishedContent.cs" />
<Compile Include="Models\PublishedContent\IPublishedContent.cs" />
<Compile Include="Cache\CacheRefreshersResolver.cs" />
<Compile Include="Configuration\GlobalSettings.cs" />
<Compile Include="CustomBooleanTypeConverter.cs" />

View File

@@ -17,6 +17,7 @@ using Umbraco.Core.Profiling;
using Umbraco.Core.Services;
using Moq;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;

View File

@@ -149,7 +149,7 @@ namespace Umbraco.Tests.PropertyEditors
dataTypeService.Setup(x => x.GetPreValuesCollectionByDataTypeId(It.IsAny<int>())).Returns(new PreValueCollection(Enumerable.Empty<PreValue>()));
var converter = new Umbraco.Web.PropertyEditors.ValueConverters.ImageCropperValueConverter(dataTypeService.Object);
var result = converter.ConvertDataToSource(new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion
var result = converter.ConvertSourceToInter(new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion
var resultShouldMatch = val2.SerializeToCropDataSet();
if (expected)

View File

@@ -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.ConvertDataToSource(null, date, false); // does not use type for conversion
var result = converter.ConvertSourceToInter(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.ConvertDataToSource(null, value, false); // does not use type for conversion
var result = converter.ConvertSourceToInter(null, value, false); // does not use type for conversion
Assert.AreEqual(expected, result);
}

View File

@@ -4,6 +4,7 @@ using System.Linq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web;
using Umbraco.Web.Models;
using Umbraco.Web.PublishedCache;

View File

@@ -159,11 +159,11 @@ namespace Umbraco.Tests.PublishedContent
if (!createChildren)
{
//create additional columns, used to test the different columns for child nodes
d.Properties.Add(new PropertyResult("property4", "value" + (indexVals + 2), PropertyResultType.UserProperty));
((Collection<IPublishedProperty>)d.Properties).Add(new PropertyResult("property4", "value" + (indexVals + 2), PropertyResultType.UserProperty));
}
else
{
d.Properties.Add(new PropertyResult("property3", "value" + (indexVals + 2), PropertyResultType.UserProperty));
((Collection<IPublishedProperty>)d.Properties).Add(new PropertyResult("property3", "value" + (indexVals + 2), PropertyResultType.UserProperty));
}
return d;
}
@@ -204,14 +204,8 @@ namespace Umbraco.Tests.PublishedContent
public Guid Version { get; set; }
public int Level { get; set; }
public bool IsDraft { get; set; }
public int GetIndex() { throw new NotImplementedException();}
public ICollection<IPublishedProperty> Properties { get; set; }
public object this[string propertyAlias]
{
get { return GetProperty(propertyAlias).Value; }
}
public IEnumerable<IPublishedProperty> Properties { get; set; }
public IEnumerable<IPublishedContent> Children { get; set; }
@@ -235,11 +229,6 @@ namespace Umbraco.Tests.PublishedContent
return property;
}
public IEnumerable<IPublishedContent> ContentSet
{
get { throw new NotImplementedException(); }
}
public PublishedContentType ContentType
{
get { throw new NotImplementedException(); }

View File

@@ -226,7 +226,7 @@ namespace Umbraco.Tests.PublishedContent
PropertyTypeAlias = "prop1",
HasValue = true,
Value = 1234,
DataValue = "1234"
SourceValue = "1234"
}
}
});
@@ -249,7 +249,7 @@ namespace Umbraco.Tests.PublishedContent
PropertyTypeAlias = "prop1",
HasValue = true,
Value = 1234,
DataValue = "1234"
SourceValue = "1234"
}
}
});
@@ -272,7 +272,7 @@ namespace Umbraco.Tests.PublishedContent
PropertyTypeAlias = "prop1",
HasValue = true,
Value = 1234,
DataValue = "1234"
SourceValue = "1234"
}
}
});

View File

@@ -7,6 +7,7 @@ using Moq;
using NUnit.Framework;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web.Routing;

View File

@@ -1,11 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;
@@ -16,31 +14,24 @@ namespace Umbraco.Tests.PublishedContent
public readonly SolidPublishedContentCache InnerContentCache = new SolidPublishedContentCache();
public readonly SolidPublishedContentCache InnerMediaCache = new SolidPublishedContentCache();
public IPublishedContentCache ContentCache
{
get { return InnerContentCache; }
}
public IPublishedContentCache ContentCache => InnerContentCache;
public IPublishedMediaCache MediaCache
{
get { return InnerMediaCache; }
}
public IPublishedMediaCache MediaCache => InnerMediaCache;
public IPublishedMemberCache MemberCache
{
get { return null; }
}
public IPublishedMemberCache MemberCache => null;
public IDomainCache DomainCache
{
get { return null; }
}
public IDomainCache DomainCache => null;
public IDisposable ForcedPreview(bool forcedPreview, Action<bool> callback = null)
{
throw new NotImplementedException();
}
public IPublishedProperty CreateFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
{
throw new NotImplementedException();
}
public void Resync()
{ }
}
@@ -133,11 +124,6 @@ namespace Umbraco.Tests.PublishedContent
return _content.Count > 0;
}
public IPublishedProperty CreateDetachedProperty(PublishedPropertyType propertyType, object value, bool isPreviewing)
{
throw new NotImplementedException();
}
public override PublishedContentType GetContentType(int id)
{
throw new NotImplementedException();
@@ -219,7 +205,7 @@ namespace Umbraco.Tests.PublishedContent
#region Properties
public ICollection<IPublishedProperty> Properties { get; set; }
public IEnumerable<IPublishedProperty> Properties { get; set; }
public IPublishedProperty GetProperty(string alias)
{
@@ -261,7 +247,7 @@ namespace Umbraco.Tests.PublishedContent
}
public string PropertyTypeAlias { get; set; }
public object DataValue { get; set; }
public object SourceValue { get; set; }
public object Value { get; set; }
public bool HasValue { get; set; }
public object XPathValue { get; set; }
@@ -278,11 +264,7 @@ namespace Umbraco.Tests.PublishedContent
#endregion
// fast, if you know that the appropriate IPropertyEditorValueConverter is wired
public int Prop1 { get { return (int)this["prop1"]; } }
// almost as fast, not sure I like it as much, though
//public int Prop1 { get { return this.GetPropertyValue<int>("prop1"); } }
public int Prop1 => this.GetPropertyValue<int>("prop1");
}
[PublishedContentModel("ContentType2Sub")]
@@ -303,7 +285,7 @@ namespace Umbraco.Tests.PublishedContent
: base(content)
{ }
public int StrongValue { get { return (int)this["strongValue"]; } }
public int StrongValue => this.GetPropertyValue<int>("strongValue");
}
class PublishedContentStrong1Sub : PublishedContentStrong1
@@ -312,7 +294,7 @@ namespace Umbraco.Tests.PublishedContent
: base(content)
{ }
public int AnotherValue { get { return (int)this["anotherValue"]; } }
public int AnotherValue => this.GetPropertyValue<int>("anotherValue");
}
class PublishedContentStrong2 : PublishedContentExtended
@@ -321,7 +303,7 @@ namespace Umbraco.Tests.PublishedContent
: base(content)
{ }
public int StrongValue { get { return (int)this["strongValue"]; } }
public int StrongValue => this.GetPropertyValue<int>("strongValue");
}
class AutoPublishedContentType : PublishedContentType

View File

@@ -3,7 +3,6 @@ using System.Linq;
using System.Web;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Plugins;
using Umbraco.Web;
@@ -50,7 +49,7 @@ namespace Umbraco.Tests.PublishedContent
};
var compositionAliases = new[] {"MyCompositionAlias"};
var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes);
ContentTypesCache.GetPublishedContentTypeByAlias = (alias) => type;
ContentTypesCache.GetPublishedContentTypeByAlias = alias => type;
}
public override void TearDown()
@@ -197,7 +196,7 @@ namespace Umbraco.Tests.PublishedContent
.Where(x => x.IsVisible()) // so, here it's linq again :-(
.ToIndexedArray(); // so, we need that one for the test to pass
Assert.AreEqual(1, items.Count());
Assert.AreEqual(1, items.Length);
foreach (var d in items)
{
@@ -288,11 +287,11 @@ namespace Umbraco.Tests.PublishedContent
}
[Test]
public void Test_Get_Recursive_Val()
public void GetPropertyValueRecursiveTest()
{
var doc = GetNode(1174);
var rVal = doc.GetRecursiveValue("testRecursive");
var nullVal = doc.GetRecursiveValue("DoNotFindThis");
var rVal = doc.GetPropertyValue("testRecursive", true);
var nullVal = doc.GetPropertyValue("DoNotFindThis", true);
Assert.AreEqual("This is the recursive val", rVal);
Assert.AreEqual("", nullVal);
}
@@ -333,9 +332,9 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1046);
var found1 = doc.Children.GroupBy("DocumentTypeAlias");
var found1 = doc.Children.GroupBy("DocumentTypeAlias").ToArray();
Assert.AreEqual(2, found1.Count());
Assert.AreEqual(2, found1.Length);
Assert.AreEqual(2, found1.Single(x => x.Key.ToString() == "Home").Count());
Assert.AreEqual(1, found1.Single(x => x.Key.ToString() == "CustomDocument").Count());
}
@@ -460,11 +459,11 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1174);
var result = doc.AncestorsOrSelf();
var result = doc.AncestorsOrSelf().ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(3, result.Count());
Assert.AreEqual(3, result.Length);
Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1174, 1173, 1046 }));
}
@@ -473,11 +472,11 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1174);
var result = doc.Ancestors();
var result = doc.Ancestors().ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(2, result.Count());
Assert.AreEqual(2, result.Length);
Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1046 }));
}
@@ -486,11 +485,11 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1046);
var result = doc.DescendantsOrSelf();
var result = doc.DescendantsOrSelf().ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(8, result.Count());
Assert.AreEqual(8, result.Length);
Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1046, 1173, 1174, 1176, 1175 }));
}
@@ -499,11 +498,11 @@ namespace Umbraco.Tests.PublishedContent
{
var doc = GetNode(1046);
var result = doc.Descendants();
var result = doc.Descendants().ToArray();
Assert.IsNotNull(result);
Assert.AreEqual(7, result.Count());
Assert.AreEqual(7, result.Length);
Assert.IsTrue(result.Select(x => ((dynamic)x).Id).ContainsAll(new dynamic[] { 1173, 1174, 1176, 1175, 4444 }));
}
@@ -516,7 +515,7 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsNotNull(result);
Assert.AreEqual((int)1046, (int)result.Id);
Assert.AreEqual(1046, result.Id);
}
[Test]
@@ -528,7 +527,13 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsNotNull(result);
Assert.AreEqual((int)1174, (int)result.Id);
Assert.AreEqual(1174, result.Id);
}
[Test]
public void FragmentTest()
{
}
[Test]
@@ -574,8 +579,8 @@ namespace Umbraco.Tests.PublishedContent
class ImageWithLegendModel
{
private IPublishedProperty _legendProperty;
private IPublishedProperty _imageProperty;
private readonly IPublishedProperty _legendProperty;
private readonly IPublishedProperty _imageProperty;
public ImageWithLegendModel(IPublishedProperty legendProperty, IPublishedProperty imageProperty)
{
@@ -583,8 +588,8 @@ namespace Umbraco.Tests.PublishedContent
_imageProperty = imageProperty;
}
public string Legend { get { return _legendProperty.GetValue<string>(); } }
public IPublishedContent Image { get { return _imageProperty.GetValue<IPublishedContent>(); } }
public string Legend => _legendProperty.GetValue<string>();
public IPublishedContent Image => _imageProperty.GetValue<IPublishedContent>();
}
}
}

View File

@@ -18,6 +18,7 @@ using Examine.Session;
using LightInject;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Strings;
using UmbracoExamine;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels
{

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Mvc;
namespace Umbraco.Tests.PublishedContent.StronglyTypedModels

View File

@@ -12,6 +12,7 @@ using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.Dictionary;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Profiling;

View File

@@ -2,6 +2,7 @@
using System.Linq;
using System.Collections;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
namespace Umbraco.Web.Dynamics

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
namespace Umbraco.Web.Dynamics

View File

@@ -7,6 +7,7 @@ using Umbraco.Web.WebApi.Filters;
using Umbraco.Web.WebApi;
using System;
using System.Diagnostics;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Dynamics;
using Umbraco.Web.Models.TemplateQuery;

View File

@@ -10,6 +10,7 @@ using System.Web.Mvc;
using Umbraco.Web.Templates;
using System.IO;
using System.Web.Routing;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Mvc;
namespace Umbraco.Web

View File

@@ -13,6 +13,7 @@ using Umbraco.Core.Dynamics;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Profiling;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
namespace Umbraco.Web

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Xml.XPath;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml;
namespace Umbraco.Web

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using System.Web;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web
{

View File

@@ -4,6 +4,7 @@ using System.Globalization;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
namespace Umbraco.Web

View File

@@ -5,6 +5,7 @@ using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using umbraco.cms.businesslogic.macro;
using System.Linq;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Macros
{

View File

@@ -9,6 +9,7 @@ using umbraco.cms.businesslogic.macro;
using Umbraco.Core.Models;
using Umbraco.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Macros
{

View File

@@ -1,115 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models
{
internal class DetachedContent
{
private readonly Dictionary<string, IPublishedProperty> _properties;
/// <summary>
/// Initialized a new instance of the <see cref="DetachedContent"/> class with properties.
/// </summary>
/// <param name="properties">The properties</param>
/// <remarks>Properties must be detached or nested properties ie their property type must be detached or nested.
/// Such a detached content can be part of a published property value.</remarks>
public DetachedContent(IEnumerable<IPublishedProperty> properties)
{
_properties = properties.ToDictionary(x => x.PropertyTypeAlias, x => x, StringComparer.InvariantCultureIgnoreCase);
}
// don't uncomment until you know what you are doing
/*
public DetachedContent(IPublishedContent content)
{
_properties = content.Properties.ToDictionary(x => x.PropertyTypeAlias, x => x, StringComparer.InvariantCultureIgnoreCase);
}
*/
// don't uncomment until you know what you are doing
// at the moment, I don't fully
/*
public DetachedContent(IContent content, bool isPreviewing)
{
var publishedContentType = PublishedContentType.Get(PublishedItemType.Content, content.ContentType.Alias);
_properties = PublishedProperty.MapProperties(publishedContentType.PropertyTypes, content.Properties,
(t, v) => PublishedProperty.GetDetached(t.Detached(), v, isPreviewing))
.ToDictionary(x => x.PropertyTypeAlias, x => x, StringComparer.InvariantCultureIgnoreCase);
}
public DetachedContent(IMedia media, bool isPreviewing)
{
var publishedContentType = PublishedContentType.Get(PublishedItemType.Media, media.ContentType.Alias);
_properties = PublishedProperty.MapProperties(publishedContentType.PropertyTypes, media.Properties,
(t, v) => PublishedProperty.GetDetached(t.Detached(), v, isPreviewing))
.ToDictionary(x => x.PropertyTypeAlias, x => x, StringComparer.InvariantCultureIgnoreCase);
}
public DetachedContent(IMember member, bool isPreviewing)
{
var publishedContentType = PublishedContentType.Get(PublishedItemType.Member, member.ContentType.Alias);
_properties = PublishedProperty.MapProperties(publishedContentType.PropertyTypes, member.Properties,
(t, v) => PublishedProperty.GetDetached(t.Detached(), v, isPreviewing))
.ToDictionary(x => x.PropertyTypeAlias, x => x, StringComparer.InvariantCultureIgnoreCase);
}
*/
public ICollection<IPublishedProperty> Properties
{
get { return _properties.Values; }
}
public IPublishedProperty GetProperty(string alias)
{
IPublishedProperty property;
return _properties.TryGetValue(alias, out property) ? property : null;
}
public bool HasProperty(string alias)
{
var property = GetProperty(alias);
return property != null;
}
public bool HasValue(string alias)
{
var property = GetProperty(alias);
return property != null && property.HasValue;
}
public object GetPropertyValue(string alias)
{
var property = GetProperty(alias);
return property == null ? null : property.Value;
}
public object GetPropertyValue(string alias, string defaultValue)
{
var property = GetProperty(alias);
return property == null || property.HasValue == false ? defaultValue : property.Value;
}
public object GetPropertyValue(string alias, object defaultValue)
{
var property = GetProperty(alias);
return property == null || property.HasValue == false ? defaultValue : property.Value;
}
public T GetPropertyValue<T>(string alias)
{
var property = GetProperty(alias);
if (property == null) return default(T);
return property.GetValue(false, default(T));
}
public T GetPropertyValue<T>(string alias, T defaultValue)
{
var property = GetProperty(alias);
if (property == null) return defaultValue;
return property.GetValue(true, defaultValue);
}
}
}

View File

@@ -46,15 +46,6 @@ namespace Umbraco.Web.Models
#endregion
// these two here have leaked in v6 and so we cannot remove them anymore
// without breaking compatibility but... TODO: remove them in v7
[Obsolete("Will be removing in future versions")]
public DynamicPublishedContentList ChildrenAsList { get { return Children; } }
[Obsolete("Will be removing in future versions")]
public int parentId { get { return PublishedContent.Parent.Id; } }
#region DynamicObject
private readonly ConcurrentDictionary<string, object> _cachedMemberOutput = new ConcurrentDictionary<string, object>();
@@ -428,7 +419,7 @@ namespace Umbraco.Web.Models
get { return PublishedContent.IsDraft; }
}
ICollection<IPublishedProperty> IPublishedContent.Properties
IEnumerable<IPublishedProperty> IPublishedFragment.Properties
{
get { return PublishedContent.Properties; }
}
@@ -438,7 +429,7 @@ namespace Umbraco.Web.Models
get { return PublishedContent.Children; }
}
IPublishedProperty IPublishedContent.GetProperty(string alias)
IPublishedProperty IPublishedFragment.GetProperty(string alias)
{
return PublishedContent.GetProperty(alias);
}
@@ -548,11 +539,6 @@ namespace Umbraco.Web.Models
get { return PublishedContent.Properties; }
}
public object this[string propertyAlias]
{
get { return PublishedContent[propertyAlias]; }
}
#endregion
#region GetProperty

View File

@@ -1,4 +1,5 @@
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models
{

View File

@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Models
{

View File

@@ -143,30 +143,7 @@ namespace Umbraco.Web.Models
/// <summary>
/// Gets the properties of the content.
/// </summary>
public abstract ICollection<IPublishedProperty> Properties { get; }
/// <summary>
/// Gets the value of a property identified by its alias.
/// </summary>
/// <param name="alias">The property alias.</param>
/// <returns>The value of the property identified by the alias.</returns>
/// <remarks>
/// <para>If <c>GetProperty(alias)</c> is <c>null</c> then returns <c>null</c> else return <c>GetProperty(alias).Value</c>.</para>
/// <para>So if the property has no value, returns the default value for that property type.</para>
/// <para>This one is defined here really because we cannot define index extension methods, but all it should do is:
/// <code>var p = GetProperty(alias); return p == null ? null : p.Value;</code> and nothing else.</para>
/// <para>The recursive syntax (eg "_title") is _not_ supported here.</para>
/// <para>The alias is case-insensitive.</para>
/// </remarks>
public virtual object this[string alias]
{
get
{
// no cache here: GetProperty should be fast, and .Value cache should be managed by the property.
var property = GetProperty(alias);
return property == null ? null : property.Value;
}
}
public abstract IEnumerable<IPublishedProperty> Properties { get; }
/// <summary>
/// Gets a property identified by its alias.

View File

@@ -1,33 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
namespace Umbraco.Web.Models
{
public static class PublishedProperty
{
/// <summary>
/// Creates a detached published property.
/// </summary>
/// <param name="propertyType">A published property type.</param>
/// <param name="value">The property data raw value.</param>
/// <param name="isPreviewing">A value indicating whether to evaluate the property value in previewing context.</param>
/// <returns>A detached published property holding the value.</returns>
internal static IPublishedProperty GetDetached(PublishedPropertyType propertyType, object value, bool isPreviewing = false)
{
if (propertyType.IsDetachedOrNested == false)
throw new ArgumentException("Property type is neither detached nor nested.", "propertyType");
var property = UmbracoContext.Current.ContentCache.CreateDetachedProperty(propertyType, value, isPreviewing);
return property;
}
/// <summary>
/// Maps a collection of Property to a collection of IPublishedProperty for a specified collection of PublishedPropertyType.
/// </summary>

View File

@@ -1,6 +1,7 @@
using System;
using System.Globalization;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Mvc;
namespace Umbraco.Web.Models

View File

@@ -1,5 +1,6 @@
using System.Globalization;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Mvc;
namespace Umbraco.Web.Models

View File

@@ -5,6 +5,7 @@ using System.Web.Mvc;
using Umbraco.Core.Models;
using Umbraco.Web.Routing;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Language = umbraco.cms.businesslogic.language.Language;
namespace Umbraco.Web.Mvc

View File

@@ -5,6 +5,7 @@ using System.Web;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Mvc
{

View File

@@ -6,6 +6,7 @@ using System.Web;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
namespace Umbraco.Web.Mvc

View File

@@ -2,6 +2,7 @@ using System;
using System.Web.Mvc;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
using Umbraco.Web.Routing;

View File

@@ -5,6 +5,7 @@ using Umbraco.Core.Models;
using Umbraco.Core;
using Umbraco.Web.Security;
using System.Collections.Specialized;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Mvc
{

View File

@@ -1,5 +1,6 @@
using Umbraco.Core.Dynamics;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
namespace Umbraco.Web.Mvc

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Mvc
{

View File

@@ -8,6 +8,7 @@ using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;

View File

@@ -1,5 +1,6 @@
using System.Web.Routing;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.Mvc
{

View File

@@ -6,6 +6,7 @@ using System.Web.Routing;
using System.Web.Security;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
using Umbraco.Web.Routing;

View File

@@ -0,0 +1,52 @@
using System;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
internal class ContentPickerValueConverter : PropertyValueConverterBase
{
private readonly IFacadeAccessor _facadeAccessor;
public ContentPickerValueConverter(IFacadeAccessor facadeAccessor)
{
_facadeAccessor = facadeAccessor;
}
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ContentPickerAlias);
}
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IPublishedContent);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Snapshot;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
int id;
return int.TryParse(source.ToString(), out id) ? id : -1;
}
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
var id = (int) inter;
return id < 0 ? null : _facadeAccessor.Facade.ContentCache.GetById(id);
}
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
return inter.ToString();
}
}
}

View File

@@ -1,3 +1,4 @@
using System;
using System.Globalization;
using System.Xml;
using System.Xml.Linq;
@@ -16,21 +17,22 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// Used to strongly type the value for the image cropper
/// </summary>
[DefaultPropertyValueConverter(typeof (JsonValueConverter))] //this shadows the JsonValueConverter
[PropertyValueType(typeof (ImageCropDataSet))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
public class ImageCropperValueConverter : Core.PropertyEditors.ValueConverters.ImageCropperValueConverter
{
public ImageCropperValueConverter()
{
}
{ }
public ImageCropperValueConverter(IDataTypeService dataTypeService) : base(dataTypeService)
{ }
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (ImageCropDataSet);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
var baseVal = base.ConvertDataToSource(propertyType, source, preview);
var baseVal = base.ConvertSourceToInter(propertyType, source, preview);
var json = baseVal as JObject;
if (json == null) return baseVal;

View File

@@ -12,8 +12,6 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// Ensures macro syntax is parsed for the macro container which will work when getting the field
/// values in any way (i.e. dynamically, using Field(), or IPublishedContent)
/// </summary>
[PropertyValueType(typeof (IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Request)]
[DefaultPropertyValueConverter]
public class MacroContainerValueConverter : PropertyValueConverterBase
{
@@ -29,6 +27,16 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return propertyType.PropertyEditorAlias == Constants.PropertyEditors.MacroContainerAlias;
}
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IHtmlString);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Facade;
}
// NOT thread-safe over a request because it modifies the
// global UmbracoContext.Current.InPreviewMode status. So it
// should never execute in // over the same UmbracoContext with
@@ -54,7 +62,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
}
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();

View File

@@ -8,8 +8,6 @@ using Umbraco.Web.Templates;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Request)]
[DefaultPropertyValueConverter]
public class MarkdownEditorValueConverter : PropertyValueConverterBase
{
@@ -18,7 +16,17 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return Constants.PropertyEditors.MarkdownEditorAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IHtmlString);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Facade;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
@@ -30,19 +38,19 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return sourceString;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// Convert markup to html for frontend rendering.
Markdown mark = new Markdown();
// source should come from ConvertSource and be a string (or null) already
return new HtmlString(source == null ? string.Empty : mark.Transform((string)source));
return new HtmlString(inter == null ? string.Empty : mark.Transform((string)inter));
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source;
return inter;
}
}
}

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
@@ -14,8 +11,6 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(JArray))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
[DefaultPropertyValueConverter(typeof(JsonValueConverter))] //this shadows the JsonValueConverter
public class RelatedLinksEditorValueConvertor : PropertyValueConverterBase
{
@@ -31,7 +26,17 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return Constants.PropertyEditors.RelatedLinksAlias.Equals(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (JArray);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Content;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
@@ -68,10 +73,10 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return sourceString;
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
if (inter == null) return null;
var sourceString = inter.ToString();
if (sourceString.DetectIsJson())
{
@@ -83,7 +88,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
var e = d.CreateElement("links");
d.AppendChild(e);
var values = (IEnumerable<string>)source;
var values = (IEnumerable<string>)inter;
foreach (dynamic link in obj)
{
var ee = d.CreateElement("link");

View File

@@ -18,17 +18,17 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// A value converter for TinyMCE that will ensure any macro content is rendered properly even when
/// used dynamically.
/// </summary>
// because that version of RTE converter parses {locallink} and executes macros, when going from
// data to source, its source value has to be cached at the request level, because we have no idea
// what the macros may depend on actually. An so, object and xpath need to follow... request, too.
// note: the TinyMceValueConverter is NOT inherited, so the PropertyValueCache attribute here is not
// actually required (since Request is default) but leave it here to be absolutely explicit.
[PropertyValueType(typeof(IHtmlString))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Request)]
public class RteMacroRenderingValueConverter : TinyMceValueConverter
{
private readonly UmbracoContext _umbracoContext;
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
// because that version of RTE converter parses {locallink} and executes macros, its value has
// to be cached at the facade level, because we have no idea what the macros may depend on actually.
return PropertyCacheLevel.Facade;
}
public RteMacroRenderingValueConverter(UmbracoContext umbracoContext)
{
_umbracoContext = umbracoContext;
@@ -59,7 +59,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
}
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null)
{

View File

@@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.PublishedCache.NuCache;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
// fixme
// this is an experimental converter to work with nested etc.
internal class TempValueConverter : PropertyValueConverterBase
{
private readonly IFacadeAccessor _facadeAccessor;
public TempValueConverter(IFacadeAccessor facadeAccessor)
{
_facadeAccessor = facadeAccessor;
}
public override bool IsConverter(PublishedPropertyType propertyType)
{
return propertyType.PropertyEditorAlias.InvariantEquals(Constants.PropertyEditors.ContentPickerAlias);
}
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (IPublishedFragment);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Snapshot;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
var json = source as string;
return json == null ? null : JsonConvert.DeserializeObject<TempData>(json);
}
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
var data = (TempData) inter;
if (data == null) return null;
var contentType = _facadeAccessor.Facade.ContentCache.GetContentType(data.ContentTypeAlias);
if (contentType == null) return null;
// fixme
// note: if we wanted to returned a strongly-typed model here, we'd have to be explicit about it
// so that we can tell GetPropertyValueType what we return - just relying on a factory is not
// going to make it in any helpful way?
return new PublishedFragment(contentType, _facadeAccessor, referenceCacheLevel, data.Key, data.Values, preview);
}
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
return inter == null ? null : JsonConvert.SerializeObject((TempData) inter);
}
public class TempData
{
public string ContentTypeAlias { get; set; }
public Guid Key { get; set; }
public Dictionary<string, object> Values { get; set; }
}
}
}

View File

@@ -1,17 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Umbraco.Core;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Web.Templates;
namespace Umbraco.Web.PropertyEditors.ValueConverters
{
[PropertyValueType(typeof(string))]
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Request)]
public class TextStringValueConverter : PropertyValueConverterBase
{
private readonly static string[] PropertyTypeAliases =
@@ -25,7 +20,17 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return PropertyTypeAliases.Contains(propertyType.PropertyEditorAlias);
}
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
{
return typeof (string);
}
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
{
return PropertyCacheLevel.Facade;
}
public override object ConvertSourceToInter(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return null;
var sourceString = source.ToString();
@@ -37,16 +42,16 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
return sourceString;
}
public override object ConvertSourceToObject(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToObject(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source ?? string.Empty;
return inter ?? string.Empty;
}
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
public override object ConvertInterToXPath(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
// source should come from ConvertSource and be a string (or null) already
return source;
return inter;
}
}
}

View File

@@ -1,4 +1,8 @@
namespace Umbraco.Web.PublishedCache
using System;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache
{
/// <summary>
/// The Umbraco facade.
@@ -35,5 +39,17 @@
/// otherwise the facade keeps previewing according to whatever settings it is using already.</para>
/// <para>Stops forcing preview when disposed.</para></remarks>
IDisposable ForcedPreview(bool preview, Action<bool> callback = null);
// fixme - document
/// <summary>
/// Creates a fragment property.
/// </summary>
/// <param name="propertyType"></param>
/// <param name="itemKey"></param>
/// <param name="previewing"></param>
/// <param name="referenceCacheLevel"></param>
/// <param name="sourceValue"></param>
/// <returns></returns>
IPublishedProperty CreateFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null);
}
}

View File

@@ -48,15 +48,5 @@ namespace Umbraco.Web.PublishedCache
/// <returns>The route.</returns>
/// <remarks>Considers published or unpublished content depending on defaults.</remarks>
string GetRouteById(int contentId);
/// <summary>
/// Creates a detached property.
/// </summary>
/// <param name="propertyType">The published property type.</param>
/// <param name="value">The value.</param>
/// <param name="isPreviewing">A value indicating whether the property is created within a previewing context.</param>
/// <returns>A detached property.</returns>
/// <remarks>Implementations must check that propertyType.IsDetachedOrNested is true.</remarks>
IPublishedProperty CreateDetachedProperty(PublishedPropertyType propertyType, object value, bool isPreviewing);
}
}

View File

@@ -41,9 +41,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
return "NuCache.Property.Recurse[" + DraftOrPub(previewing) + contentUid + ":" + typeAlias + "]";
}
public static string PropertyValueSet(Guid contentUid, string typeAlias, bool previewing)
public static string PropertyCacheValues(Guid contentUid, string typeAlias, bool previewing)
{
return "NuCache.Property.ValueSet[" + DraftOrPub(previewing) + contentUid + ":" + typeAlias + "]";
return "NuCache.Property.CacheValues[" + DraftOrPub(previewing) + contentUid + ":" + typeAlias + "]";
}
// routes still use int id and not Guid uid, because routable nodes must have

View File

@@ -339,19 +339,6 @@ namespace Umbraco.Web.PublishedCache.NuCache
#endregion
#region Detached
// detached is something that needs to be refactored entirely eventually
// detached property should accept the "container content" guid
// etc
public IPublishedProperty CreateDetachedProperty(PublishedPropertyType propertyType, object value, bool isPreviewing)
{
throw new NotImplementedException();
}
#endregion
#region Content types
public override PublishedContentType GetContentType(int id)

View File

@@ -91,8 +91,8 @@ namespace Umbraco.Web.PublishedCache.NuCache
var originDraft = origin.Draft == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Draft);
var originPublished = origin.Published == null ? null : PublishedContent.UnwrapIPublishedContent(origin.Published);
Draft = originDraft == null ? null : new PublishedContent(this, originDraft, facadeAccessor).CreateModel();
Published = originPublished == null ? null : new PublishedContent(this, originPublished, facadeAccessor).CreateModel();
Draft = originDraft == null ? null : new PublishedContent(this, originDraft).CreateModel();
Published = originPublished == null ? null : new PublishedContent(this, originPublished).CreateModel();
ChildContentIds = new List<int>(origin.ChildContentIds); // needs to be *another* list
}

View File

@@ -1,6 +1,8 @@
using System;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache.NuCache
{
@@ -94,6 +96,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
}
public IPublishedProperty CreateFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
{
return _service.CreateFragmentProperty(propertyType, itemKey, previewing, referenceCacheLevel, sourceValue);
}
#endregion
#region IDisposable

View File

@@ -17,6 +17,7 @@ using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Repositories;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Core.Services.Changes;
using Umbraco.Web.Cache;
@@ -1478,5 +1479,14 @@ AND cmsContentNu.nodeId IS NULL
}
#endregion
#region Fragments
public IPublishedProperty CreateFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
{
return new PublishedFragmentProperty(_facadeAccessor, propertyType, itemKey, previewing, referenceCacheLevel, sourceValue);
}
#endregion
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Web.PublishedCache.NuCache.Navigable
{

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.Xml.XPath;
namespace Umbraco.Web.PublishedCache.NuCache.Navigable

View File

@@ -1,7 +1,6 @@
using System;
using System.Xml.Serialization;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
@@ -12,27 +11,29 @@ namespace Umbraco.Web.PublishedCache.NuCache
class Property : PublishedPropertyBase
{
private readonly IFacadeAccessor _facadeAccessor;
private readonly object _dataValue;
private readonly object _sourceValue;
private readonly Guid _contentUid;
private readonly bool _isPreviewing;
private readonly bool _isMember;
readonly object _locko = new object();
private readonly object _locko = new object();
private ValueSet _valueSet;
private string _valueSetCacheKey;
private bool _interInitialized;
private object _interValue;
private CacheValues _cacheValues;
private string _valuesCacheKey;
private string _recurseCacheKey;
// initializes a published content property with no value
public Property(PublishedPropertyType propertyType, PublishedContent content, IFacadeAccessor facadeAccessor)
: this(propertyType, content, null, facadeAccessor)
public Property(PublishedPropertyType propertyType, IPublishedContent 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, PublishedContent content, object valueSource, IFacadeAccessor facadeAccessor)
: base(propertyType)
public Property(PublishedPropertyType propertyType, IPublishedContent content, object sourceValue, IFacadeAccessor facadeAccessor, PropertyCacheLevel referenceCacheLevel = PropertyCacheLevel.Content)
: base(propertyType, referenceCacheLevel)
{
_dataValue = valueSource;
_sourceValue = sourceValue;
_contentUid = content.Key;
var inner = PublishedContent.UnwrapIPublishedContent(content);
_isPreviewing = inner.IsPreviewing;
@@ -42,60 +43,50 @@ namespace Umbraco.Web.PublishedCache.NuCache
// clone for previewing as draft a published content that is published and has no draft
public Property(Property origin)
: base(origin.PropertyType)
: base(origin.PropertyType, origin.ReferenceCacheLevel)
{
_dataValue = origin._dataValue;
_sourceValue = origin._sourceValue;
_contentUid = origin._contentUid;
_isPreviewing = true;
_isMember = origin._isMember;
_facadeAccessor = origin._facadeAccessor;
}
// detached
//internal Property(PublishedPropertyType propertyType, Guid contentUid, object valueSource, bool isPreviewing, bool isMember)
// : base(propertyType)
//{
// _dataValue = valueSource;
// _contentUid = contentUid;
// _isPreviewing = isPreviewing;
// _isMember = isMember;
//}
public override bool HasValue => _sourceValue != null
&& ((_sourceValue is string) == false || string.IsNullOrWhiteSpace((string)_sourceValue) == false);
public override bool HasValue => _dataValue != null
&& ((_dataValue is string) == false || string.IsNullOrWhiteSpace((string)_dataValue) == false);
private class ValueSet
private class CacheValues
{
public bool SourceInitialized;
public object Source;
public bool ValueInitialized;
public object Value;
public bool ObjectInitialized;
public object ObjectValue;
public bool XPathInitialized;
public object XPath;
public object XPathValue;
}
// used to cache the recursive *property* for this property
internal string RecurseCacheKey => _recurseCacheKey
?? (_recurseCacheKey = CacheKeys.PropertyRecurse(_contentUid, PropertyTypeAlias, _isPreviewing));
internal string ValueSetCacheKey => _valueSetCacheKey
?? (_valueSetCacheKey = CacheKeys.PropertyValueSet(_contentUid, PropertyTypeAlias, _isPreviewing));
// used to cache the CacheValues of this property
internal string ValuesCacheKey => _valuesCacheKey
?? (_valuesCacheKey = CacheKeys.PropertyCacheValues(_contentUid, PropertyTypeAlias, _isPreviewing));
private ValueSet GetValueSet(PropertyCacheLevel cacheLevel)
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
{
ValueSet valueSet;
CacheValues cacheValues;
Facade facade;
ICacheProvider cache;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
// never cache anything
valueSet = new ValueSet();
cacheValues = new CacheValues();
break;
case PropertyCacheLevel.Content:
// cache within the property object itself, ie within the content object
valueSet = _valueSet ?? (_valueSet = new ValueSet());
cacheValues = _cacheValues ?? (_cacheValues = new CacheValues());
break;
case PropertyCacheLevel.ContentCache:
case PropertyCacheLevel.Snapshot:
// cache within the snapshot cache, unless previewing, then use the facade or
// snapshot cache (if we don't want to pollute the snapshot cache with short-lived
// data) depending on settings
@@ -106,39 +97,37 @@ namespace Umbraco.Web.PublishedCache.NuCache
: ((_isPreviewing == false || FacadeService.FullCacheWhenPreviewing) && (_isMember == false)
? facade.SnapshotCache
: facade.FacadeCache);
valueSet = GetValueSet(cache);
cacheValues = GetCacheValues(cache);
break;
case PropertyCacheLevel.Request:
case PropertyCacheLevel.Facade:
// cache within the facade cache
facade = (Facade)_facadeAccessor.Facade;
facade = (Facade) _facadeAccessor.Facade;
cache = facade?.FacadeCache;
valueSet = GetValueSet(cache);
cacheValues = GetCacheValues(cache);
break;
default:
throw new InvalidOperationException("Invalid cache level.");
}
return valueSet;
return cacheValues;
}
private ValueSet GetValueSet(ICacheProvider cache)
private CacheValues GetCacheValues(ICacheProvider cache)
{
if (cache == null) // no cache, don't cache
return new ValueSet();
return (ValueSet) cache.GetCacheItem(ValueSetCacheKey, () => new ValueSet());
return new CacheValues();
return (CacheValues) cache.GetCacheItem(ValuesCacheKey, () => new CacheValues());
}
private object GetSourceValue()
private object GetInterValue()
{
var valueSet = GetValueSet(PropertyType.SourceCacheLevel);
if (valueSet.SourceInitialized == false)
{
valueSet.Source = PropertyType.ConvertDataToSource(_dataValue, _isPreviewing);
valueSet.SourceInitialized = true;
}
return valueSet.Source;
if (_interInitialized) return _interValue;
_interValue = PropertyType.ConvertSourceToInter(_sourceValue, _isPreviewing);
_interInitialized = true;
return _interValue;
}
public override object DataValue => _dataValue;
public override object SourceValue => _sourceValue;
public override object Value
{
@@ -146,13 +135,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
lock (_locko)
{
var valueSet = GetValueSet(PropertyType.ObjectCacheLevel);
if (valueSet.ValueInitialized == false)
{
valueSet.Value = PropertyType.ConvertSourceToObject(GetSourceValue(), _isPreviewing);
valueSet.ValueInitialized = true;
}
return valueSet.Value;
var cacheValues = GetCacheValues(PropertyType.CacheLevel);
if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue;
// initial reference cache level always is .Content
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(PropertyCacheLevel.Content, GetInterValue(), _isPreviewing);
cacheValues.ObjectInitialized = true;
return cacheValues.ObjectValue;
}
}
}
@@ -163,13 +152,13 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
lock (_locko)
{
var valueSet = GetValueSet(PropertyType.XPathCacheLevel);
if (valueSet.XPathInitialized == false)
{
valueSet.XPath = PropertyType.ConvertSourceToXPath(GetSourceValue(), _isPreviewing);
valueSet.XPathInitialized = true;
}
return valueSet.XPath;
var cacheValues = GetCacheValues(PropertyType.CacheLevel);
if (cacheValues.XPathInitialized) return cacheValues.XPathValue;
// initial reference cache level always is .Content
cacheValues.XPathValue = PropertyType.ConvertInterToXPath(PropertyCacheLevel.Content, GetInterValue(), _isPreviewing);
cacheValues.XPathInitialized = true;
return cacheValues.XPathValue;
}
}
}

View File

@@ -3,7 +3,6 @@ using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
using Umbraco.Web.PublishedCache.NuCache.DataSource;
@@ -29,7 +28,18 @@ namespace Umbraco.Web.PublishedCache.NuCache
_urlName = _contentData.Name.ToUrlSegment();
IsPreviewing = _contentData.Published == false;
PropertiesArray = CreateProperties(this, contentData.Properties);
var values = contentData.Properties;
PropertiesArray = _contentNode.ContentType
.PropertyTypes
.Select(propertyType =>
{
object value;
return values.TryGetValue(propertyType.PropertyTypeAlias, out value) && value != null
? new Property(propertyType, this, value, _facadeAccessor) as IPublishedProperty
: new Property(propertyType, this, _facadeAccessor) as IPublishedProperty;
})
.ToArray();
}
private string GetProfileNameById(int id)
@@ -56,25 +66,11 @@ namespace Umbraco.Web.PublishedCache.NuCache
return user?.Name;
}
private IPublishedProperty[] CreateProperties(PublishedContent content, IDictionary<string, object> values)
{
return content._contentNode.ContentType
.PropertyTypes
.Select(propertyType =>
{
object value;
return values.TryGetValue(propertyType.PropertyTypeAlias, out value)
? new Property(propertyType, content, value, _facadeAccessor) as IPublishedProperty
: new Property(propertyType, content, _facadeAccessor) as IPublishedProperty;
})
.ToArray();
}
// (see ContentNode.CloneParent)
public PublishedContent(ContentNode contentNode, PublishedContent origin, IFacadeAccessor facadeAccessor)
public PublishedContent(ContentNode contentNode, PublishedContent origin)
{
_contentNode = contentNode;
_facadeAccessor = facadeAccessor;
_facadeAccessor = origin._facadeAccessor;
_contentData = origin._contentData;
_urlName = origin._urlName;
@@ -87,9 +83,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
}
// clone for previewing as draft a published content that is published and has no draft
private PublishedContent(PublishedContent origin, IFacadeAccessor facadeAccessor)
private PublishedContent(PublishedContent origin)
{
_facadeAccessor = facadeAccessor;
_facadeAccessor = origin._facadeAccessor;
_contentNode = origin._contentNode;
_contentData = origin._contentData;
@@ -106,32 +102,16 @@ namespace Umbraco.Web.PublishedCache.NuCache
// this is for tests purposes
// args are: current facade (may be null), previewing, content id - returns: content
private static Func<IFacade, bool, int, IPublishedContent> _getContentByIdFunc =
(facade, previewing, id) => facade.ContentCache.GetById(previewing, id);
private static Func<IFacade, bool, int, IPublishedContent> _getMediaByIdFunc =
(facade, previewing, id) => facade.MediaCache.GetById(previewing, id);
internal static Func<IFacade, bool, int, IPublishedContent> GetContentByIdFunc
{
get { return _getContentByIdFunc; }
set
{
_getContentByIdFunc = value;
}
}
internal static Func<IFacade, bool, int, IPublishedContent> GetContentByIdFunc { get; set; }
= (facade, previewing, id) => facade.ContentCache.GetById(previewing, id);
internal static Func<IFacade, bool, int, IPublishedContent> GetMediaByIdFunc
{
get { return _getMediaByIdFunc; }
set
{
_getMediaByIdFunc = value;
}
}
internal static Func<IFacade, bool, int, IPublishedContent> GetMediaByIdFunc { get; set; }
= (facade, previewing, id) => facade.MediaCache.GetById(previewing, id);
private IPublishedContent GetContentById(bool previewing, int id)
{
return _getContentByIdFunc(_facadeAccessor.Facade, previewing, id);
return GetContentByIdFunc(_facadeAccessor.Facade, previewing, id);
}
private IEnumerable<IPublishedContent> GetContentByIds(bool previewing, IEnumerable<int> ids)
@@ -147,14 +127,14 @@ namespace Umbraco.Web.PublishedCache.NuCache
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var id in ids)
{
var content = _getContentByIdFunc(facade, previewing, id);
var content = GetContentByIdFunc(facade, previewing, id);
if (content != null) yield return content;
}
}
private IPublishedContent GetMediaById(bool previewing, int id)
{
return _getMediaByIdFunc(_facadeAccessor.Facade, previewing, id);
return GetMediaByIdFunc(_facadeAccessor.Facade, previewing, id);
}
private IEnumerable<IPublishedContent> GetMediaByIds(bool previewing, IEnumerable<int> ids)
@@ -166,7 +146,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var id in ids)
{
var content = _getMediaByIdFunc(facade, previewing, id);
var content = GetMediaByIdFunc(facade, previewing, id);
if (content != null) yield return content;
}
}
@@ -226,7 +206,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
{
get
{
var cache = GetAppropriateCurrentFacadeCache();
var cache = GetAppropriateCache();
if (cache == null || FacadeService.CachePublishedContentChildren == false)
return GetChildren();
@@ -258,7 +238,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
// Q: perfs-wise, is it better than having the store managed an ordered list
}
public override ICollection<IPublishedProperty> Properties => PropertiesArray;
public override IEnumerable<IPublishedProperty> Properties => PropertiesArray;
public override IPublishedProperty GetProperty(string alias)
{
@@ -272,7 +252,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
var property = GetProperty(alias);
if (recurse == false) return property;
var cache = GetAppropriateCurrentFacadeCache();
var cache = GetAppropriateCache();
if (cache == null)
return base.GetProperty(alias, true);
@@ -287,7 +267,7 @@ namespace Umbraco.Web.PublishedCache.NuCache
#region Caching
// beware what you use that one for - you don't want to cache its result
private ICacheProvider GetAppropriateCurrentFacadeCache()
private ICacheProvider GetAppropriateCache()
{
var facade = (Facade) _facadeAccessor.Facade;
var cache = facade == null
@@ -335,9 +315,9 @@ namespace Umbraco.Web.PublishedCache.NuCache
if (IsPreviewing)
return this;
var cache = GetAppropriateCurrentFacadeCache();
if (cache == null) return new PublishedContent(this, _facadeAccessor).CreateModel();
return (IPublishedContent) cache.GetCacheItem(AsPreviewingCacheKey, () => new PublishedContent(this, _facadeAccessor).CreateModel());
var cache = GetAppropriateCache();
if (cache == null) return new PublishedContent(this).CreateModel();
return (IPublishedContent) cache.GetCacheItem(AsPreviewingCacheKey, () => new PublishedContent(this).CreateModel());
}
// used by Navigable.Source,...

View File

@@ -0,0 +1,55 @@
using System;
using Umbraco.Core.Cache;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache.NuCache
{
internal class PublishedFragmentProperty : PublishedCache.PublishedFragmentProperty
{
private readonly IFacadeAccessor _facadeAccessor;
private string _valuesCacheKey;
// initializes a published item property
public PublishedFragmentProperty(IFacadeAccessor facadeAccessor, PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
: base(propertyType, itemKey, previewing, referenceCacheLevel, sourceValue)
{
_facadeAccessor = facadeAccessor;
}
// used to cache the CacheValues of this property
internal string ValuesCacheKey => _valuesCacheKey
?? (_valuesCacheKey = CacheKeys.PropertyCacheValues(ItemUid, PropertyTypeAlias, IsPreviewing));
protected override CacheValues GetSnapshotCacheValues()
{
// cache within the snapshot cache, unless previewing, then use the facade or
// snapshot cache (if we don't want to pollute the snapshot cache with short-lived
// data) depending on settings
// for members, always cache in the facade cache - never pollute snapshot cache
var facade = (Facade)_facadeAccessor.Facade;
var cache = facade == null
? null
: ((IsPreviewing == false || FacadeService.FullCacheWhenPreviewing) && (IsMember == false)
? facade.SnapshotCache
: facade.FacadeCache);
return GetCacheValues(cache);
}
protected override CacheValues GetFacadeCacheValues()
{
// cache within the facade cache
var facade = (Facade) _facadeAccessor.Facade;
var cache = facade?.FacadeCache;
return GetCacheValues(cache);
}
private CacheValues GetCacheValues(ICacheProvider cache)
{
// no cache, don't cache
return cache == null
? new CacheValues()
: (CacheValues) cache.GetCacheItem(ValuesCacheKey, () => new CacheValues());
}
}
}

View File

@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache
{
// fixme document & review
//
// these things should NOT manage any tree-like elements (fixme:discuss?)
// Lee's NestedContent package DetachedPublishedContent does NOT
// and yet we need to be able to figure out what happens when nesting things?
//
// how would we create MODELS for published items? should it be automatic
// or explicit when creating the items? probably cannot be automatic because
// then, how would we cast the returned object?
//
// note: could also have a totally detached one in Core?
//
internal class PublishedFragment : IPublishedFragment
{
private readonly IFacadeAccessor _facadeAccessor;
public PublishedFragment(PublishedContentType contentType,
IFacadeAccessor facadeAccessor, PropertyCacheLevel referenceCacheLevel,
Guid key, Dictionary<string, object> values,
bool previewing)
{
ContentType = contentType;
_facadeAccessor = facadeAccessor;
Key = key;
// ensure we ignore case for property aliases
var comparer = values.Comparer;
var ignoreCase = comparer == StringComparer.OrdinalIgnoreCase || comparer == StringComparer.InvariantCultureIgnoreCase || comparer == StringComparer.CurrentCultureIgnoreCase;
if (ignoreCase == false)
values = new Dictionary<string, object>(values, StringComparer.OrdinalIgnoreCase);
_propertiesArray = contentType
.PropertyTypes
.Select(propertyType =>
{
object value;
values.TryGetValue(propertyType.PropertyTypeAlias, out value);
return _facadeAccessor.Facade.CreateFragmentProperty(propertyType, Key, previewing, referenceCacheLevel, value);
})
.ToArray();
}
#region ContentType
public PublishedContentType ContentType { get; }
#endregion
#region Content
public Guid Key { get; }
#endregion
#region Properties
private readonly IPublishedProperty[] _propertiesArray;
public IEnumerable<IPublishedProperty> Properties => _propertiesArray;
public IPublishedProperty GetProperty(string alias)
{
var index = ContentType.GetPropertyIndex(alias);
var property = index < 0 ? null : _propertiesArray[index];
return property;
}
#endregion
}
}

View File

@@ -0,0 +1,165 @@
using System;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache
{
internal abstract class PublishedFragmentProperty : PublishedPropertyBase
{
private readonly object _locko = new object();
private readonly object _sourceValue;
protected readonly Guid ItemUid;
protected readonly bool IsPreviewing;
protected readonly bool IsMember;
private bool _interInitialized;
private object _interValue;
private CacheValues _cacheValues;
// initializes a published item property
protected PublishedFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
: base(propertyType, referenceCacheLevel)
{
_sourceValue = sourceValue;
ItemUid = itemKey;
IsPreviewing = previewing;
IsMember = propertyType.ContentType.ItemType == PublishedItemType.Member;
}
public override bool HasValue => _sourceValue != null
&& ((_sourceValue is string) == false || string.IsNullOrWhiteSpace((string)_sourceValue) == false);
protected class CacheValues
{
public bool ObjectInitialized;
public object ObjectValue;
public bool XPathInitialized;
public object XPathValue;
}
private static void ValidateCacheLevel(PropertyCacheLevel cacheLevel)
{
switch (cacheLevel)
{
case PropertyCacheLevel.Content:
case PropertyCacheLevel.Snapshot:
case PropertyCacheLevel.Facade:
case PropertyCacheLevel.None:
break;
default:
throw new Exception("Invalid cache level.");
}
}
private void GetCacheLevels(out PropertyCacheLevel cacheLevel, out PropertyCacheLevel referenceCacheLevel)
{
// based upon the current reference cache level (ReferenceCacheLevel) and this property
// cache level (PropertyType.CacheLevel), determines both the actual cache level for the
// property, and the new reference cache level.
// sanity checks
ValidateCacheLevel(ReferenceCacheLevel);
ValidateCacheLevel(PropertyType.CacheLevel);
// if the property cache level is 'shorter-termed' that the reference
// then use it and it becomes the new reference, else use Content and
// don't change the reference.
//
// examples:
// currently (reference) caching at facade, property specifies
// snapshot, ok to use content. OTOH, currently caching at snapshot,
// property specifies facade, need to use facade.
//
if (PropertyType.CacheLevel > ReferenceCacheLevel)
{
cacheLevel = PropertyType.CacheLevel;
referenceCacheLevel = cacheLevel;
}
else
{
cacheLevel = PropertyCacheLevel.Content;
referenceCacheLevel = ReferenceCacheLevel;
}
}
protected abstract CacheValues GetSnapshotCacheValues();
protected abstract CacheValues GetFacadeCacheValues();
private CacheValues GetCacheValues(PropertyCacheLevel cacheLevel)
{
CacheValues cacheValues;
switch (cacheLevel)
{
case PropertyCacheLevel.None:
// never cache anything
cacheValues = new CacheValues();
break;
case PropertyCacheLevel.Content:
// cache within the property object itself, ie within the content object
cacheValues = _cacheValues ?? (_cacheValues = new CacheValues());
break;
case PropertyCacheLevel.Snapshot:
// cache within the snapshot cache, depending...
cacheValues = GetSnapshotCacheValues();
break;
case PropertyCacheLevel.Facade:
// cache within the facade cache
cacheValues = GetFacadeCacheValues();
break;
default:
throw new InvalidOperationException("Invalid cache level.");
}
return cacheValues;
}
private object GetInterValue()
{
if (_interInitialized) return _interValue;
_interValue = PropertyType.ConvertSourceToInter(_sourceValue, IsPreviewing);
_interInitialized = true;
return _interValue;
}
public override object SourceValue => _sourceValue;
public override object Value
{
get
{
lock (_locko)
{
PropertyCacheLevel cacheLevel, referenceCacheLevel;
GetCacheLevels(out cacheLevel, out referenceCacheLevel);
var cacheValues = GetCacheValues(cacheLevel);
if (cacheValues.ObjectInitialized) return cacheValues.ObjectValue;
cacheValues.ObjectValue = PropertyType.ConvertInterToObject(referenceCacheLevel, GetInterValue(), IsPreviewing);
cacheValues.ObjectInitialized = true;
return cacheValues.ObjectValue;
}
}
}
public override object XPathValue
{
get
{
lock (_locko)
{
PropertyCacheLevel cacheLevel, referenceCacheLevel;
GetCacheLevels(out cacheLevel, out referenceCacheLevel);
var cacheValues = GetCacheValues(cacheLevel);
if (cacheValues.XPathInitialized) return cacheValues.XPathValue;
cacheValues.XPathValue = PropertyType.ConvertInterToXPath(referenceCacheLevel, GetInterValue(), IsPreviewing);
cacheValues.XPathInitialized = true;
return cacheValues.XPathValue;
}
}
}
}
}

View File

@@ -70,7 +70,7 @@ namespace Umbraco.Web.PublishedCache
public override IEnumerable<IPublishedContent> Children => Enumerable.Empty<IPublishedContent>();
public override ICollection<IPublishedProperty> Properties => _properties;
public override IEnumerable<IPublishedProperty> Properties => _properties;
public override IPublishedProperty GetProperty(string alias, bool recurse)
{

View File

@@ -1,5 +1,6 @@
using System;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PublishedCache
{
@@ -16,7 +17,7 @@ namespace Umbraco.Web.PublishedCache
private readonly Lazy<object> _xpathValue;
private readonly bool _isPreviewing;
public override object DataValue => _dbVal;
public override object SourceValue => _dbVal;
public override bool HasValue => _dbVal != null && _dbVal.ToString().Trim().Length > 0;
@@ -35,14 +36,14 @@ namespace Umbraco.Web.PublishedCache
// note: maintaining two ctors to make sure we understand what we do when calling them
public RawValueProperty(PublishedPropertyType propertyType, bool isPreviewing = false)
: base(propertyType)
: base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored
{
_dbVal = null;
_isPreviewing = isPreviewing;
_sourceValue = new Lazy<object>(() => PropertyType.ConvertDataToSource(_dbVal, _isPreviewing));
_objectValue = new Lazy<object>(() => PropertyType.ConvertSourceToObject(_sourceValue.Value, _isPreviewing));
_xpathValue = new Lazy<object>(() => PropertyType.ConvertSourceToXPath(_sourceValue.Value, _isPreviewing));
_sourceValue = new Lazy<object>(() => PropertyType.ConvertSourceToInter(_dbVal, _isPreviewing));
_objectValue = new Lazy<object>(() => PropertyType.ConvertInterToObject(PropertyCacheLevel.Unknown, _sourceValue.Value, _isPreviewing));
_xpathValue = new Lazy<object>(() => PropertyType.ConvertInterToXPath(PropertyCacheLevel.Unknown, _sourceValue.Value, _isPreviewing));
}
}
}

View File

@@ -57,5 +57,12 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
protected override void DisposeResources()
{ }
}
public IPublishedProperty CreateFragmentProperty(PublishedPropertyType propertyType, Guid itemKey, bool previewing, PropertyCacheLevel referenceCacheLevel, object sourceValue = null)
{
// fixme
throw new NotImplementedException();
}
}
}

Some files were not shown because too many files have changed in this diff Show More