Introduce IPublishedPropertyType

This commit is contained in:
Stephan
2019-04-15 17:14:45 +02:00
parent 34ad8dfb8d
commit f039b00a44
60 changed files with 497 additions and 384 deletions

View File

@@ -42,7 +42,7 @@ namespace Umbraco.Core.Models.PublishedContent
/// <summary>
/// Gets the content type properties.
/// </summary>
IEnumerable<PublishedPropertyType> PropertyTypes { get; }
IEnumerable<IPublishedPropertyType> PropertyTypes { get; }
/// <summary>
/// Gets a property type index.
@@ -53,11 +53,11 @@ namespace Umbraco.Core.Models.PublishedContent
/// <summary>
/// Gets a property type.
/// </summary>
PublishedPropertyType GetPropertyType(string alias);
IPublishedPropertyType GetPropertyType(string alias);
/// <summary>
/// Gets a property type.
/// </summary>
PublishedPropertyType GetPropertyType(int index);
IPublishedPropertyType GetPropertyType(int index);
}
}

View File

@@ -18,7 +18,7 @@
/// <param name="contentType">The published content type owning the property.</param>
/// <param name="propertyType">A property type.</param>
/// <remarks>Is used by <see cref="PublishedContentType"/> constructor to create property types.</remarks>
PublishedPropertyType CreatePropertyType(IPublishedContentType contentType, PropertyType propertyType);
IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, PropertyType propertyType);
/// <summary>
/// Creates a published property type.
@@ -28,7 +28,7 @@
/// <param name="dataTypeId">The datatype identifier.</param>
/// <param name="variations">The variations.</param>
/// <remarks>Is used by <see cref="PublishedContentType"/> constructor to create special property types.</remarks>
PublishedPropertyType CreatePropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations);
IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations);
/// <summary>
/// Gets a published datatype.

View File

@@ -5,7 +5,7 @@
/// </summary>
public interface IPublishedProperty
{
PublishedPropertyType PropertyType { get; }
IPublishedPropertyType PropertyType { get; }
/// <summary>
/// Gets the alias of the property.

View File

@@ -0,0 +1,108 @@
using System;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Models.PublishedContent
{
/// <summary>
/// Represents a published property type.
/// </summary>
/// <remarks>Instances implementing the <see cref="PublishedPropertyType"/> interface should be
/// immutable, ie if the property type changes, then a new instance needs to be created.</remarks>
public interface IPublishedPropertyType
{
/// <summary>
/// Gets the published content type containing the property type.
/// </summary>
IPublishedContentType ContentType { get; }
/// <summary>
/// Gets the data type.
/// </summary>
PublishedDataType DataType { get; }
/// <summary>
/// Gets property type alias.
/// </summary>
string Alias { get; }
/// <summary>
/// Gets the property editor alias.
/// </summary>
string EditorAlias { get; }
/// <summary>
/// Gets a value indicating whether the property is a user content property.
/// </summary>
/// <remarks>A non-user content property is a property that has been added to a
/// published content type by Umbraco but does not corresponds to a user-defined
/// published property.</remarks>
bool IsUserProperty { get; }
/// <summary>
/// Gets the content variations of the property type.
/// </summary>
ContentVariation Variations { get; }
/// <summary>
/// Determines whether a value is an actual value, or not a value.
/// </summary>
/// <remarks>Used by property.HasValue and, for instance, in fallback scenarios.</remarks>
bool? IsValue(object value, PropertyValueLevel level);
/// <summary>
/// Gets the property cache level.
/// </summary>
PropertyCacheLevel CacheLevel { get; }
/// <summary>
/// Converts the source value into the intermediate value.
/// </summary>
/// <param name="owner">The published element owning the property.</param>
/// <param name="source">The source value.</param>
/// <param name="preview">A value indicating whether content should be considered draft.</param>
/// <returns>The intermediate value.</returns>
object ConvertSourceToInter(IPublishedElement owner, object source, bool preview);
/// <summary>
/// Converts the intermediate value into the object value.
/// </summary>
/// <param name="owner">The published element owning the property.</param>
/// <param name="referenceCacheLevel">The reference cache level.</param>
/// <param name="inter">The intermediate value.</param>
/// <param name="preview">A value indicating whether content should be considered draft.</param>
/// <returns>The object value.</returns>
object ConvertInterToObject(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
/// <summary>
/// Converts the intermediate value into the XPath value.
/// </summary>
/// <param name="owner">The published element owning the property.</param>
/// <param name="referenceCacheLevel">The reference cache level.</param>
/// <param name="inter">The intermediate value.</param>
/// <param name="preview">A value indicating whether content should be considered draft.</param>
/// <returns>The XPath value.</returns>
/// <remarks>
/// <para>The XPath value can be either a string or an XPathNavigator.</para>
/// </remarks>
object ConvertInterToXPath(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview);
/// <summary>
/// Gets the property model CLR type.
/// </summary>
/// <remarks>
/// <para>The model CLR type may be a <see cref="ModelType"/> type, or may contain <see cref="ModelType"/> types.</para>
/// <para>For the actual CLR type, see <see cref="ClrType"/>.</para>
/// </remarks>
Type ModelClrType { get; }
/// <summary>
/// Gets the property CLR type.
/// </summary>
/// <remarks>
/// <para>Returns the actual CLR type which does not contain <see cref="ModelType"/> types.</para>
/// <para>Mapping from <see cref="ModelClrType"/> may throw if some <see cref="ModelType"/> instances
/// could not be mapped to actual CLR types.</para>
/// </remarks>
Type ClrType { get; }
}
}

View File

@@ -11,7 +11,7 @@ namespace Umbraco.Core.Models.PublishedContent
/// if the content type changes, then a new class needs to be created.</remarks>
public class PublishedContentType : IPublishedContentType
{
private readonly PublishedPropertyType[] _propertyTypes;
private readonly IPublishedPropertyType[] _propertyTypes;
// fast alias-to-index xref containing both the raw alias and its lowercase version
private readonly Dictionary<string, int> _indexes = new Dictionary<string, int>();
@@ -34,11 +34,11 @@ namespace Umbraco.Core.Models.PublishedContent
InitializeIndexes();
}
// fixme should be internal?
/// <summary>
/// Initializes a new instance of the <see cref="PublishedContentType"/> with specific values.
/// This constructor is for tests and is not intended to be used directly from application code.
/// </summary>
/// <remarks>
/// <para>This constructor is for tests and is not intended to be used directly from application code.</para>
/// <para>Values are assumed to be consisted and are not checked.</para>
/// </remarks>
public PublishedContentType(int id, string alias, PublishedItemType itemType, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes, ContentVariation variations, bool isElement = false)
@@ -52,6 +52,15 @@ namespace Umbraco.Core.Models.PublishedContent
InitializeIndexes();
}
// fixme
public PublishedContentType(int id, string alias, PublishedItemType itemType, IEnumerable<string> compositionAliases, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes, ContentVariation variations, bool isElement = false)
: this(id, alias, itemType, compositionAliases, variations, isElement)
{
_propertyTypes = propertyTypes(this).ToArray();
InitializeIndexes();
}
private PublishedContentType(int id, string alias, PublishedItemType itemType, IEnumerable<string> compositionAliases, ContentVariation variations, bool isElement)
{
Id = id;
@@ -75,7 +84,7 @@ namespace Umbraco.Core.Models.PublishedContent
// Members have properties such as IMember LastLoginDate which are plain C# properties and not content
// properties; they are exposed as pseudo content properties, as long as a content property with the
// same alias does not exist already.
private void EnsureMemberProperties(List<PublishedPropertyType> propertyTypes, IPublishedContentTypeFactory factory)
private void EnsureMemberProperties(List<IPublishedPropertyType> propertyTypes, IPublishedContentTypeFactory factory)
{
var aliases = new HashSet<string>(propertyTypes.Select(x => x.Alias), StringComparer.OrdinalIgnoreCase);
@@ -123,7 +132,7 @@ namespace Umbraco.Core.Models.PublishedContent
#region Properties
/// <inheritdoc />
public IEnumerable<PublishedPropertyType> PropertyTypes => _propertyTypes;
public IEnumerable<IPublishedPropertyType> PropertyTypes => _propertyTypes;
/// <inheritdoc />
public int GetPropertyIndex(string alias)
@@ -136,7 +145,7 @@ namespace Umbraco.Core.Models.PublishedContent
// virtual for unit tests
// TODO: explain why
/// <inheritdoc />
public virtual PublishedPropertyType GetPropertyType(string alias)
public virtual IPublishedPropertyType GetPropertyType(string alias)
{
var index = GetPropertyIndex(alias);
return GetPropertyType(index);
@@ -145,7 +154,7 @@ namespace Umbraco.Core.Models.PublishedContent
// virtual for unit tests
// TODO: explain why
/// <inheritdoc />
public virtual PublishedPropertyType GetPropertyType(int index)
public virtual IPublishedPropertyType GetPropertyType(int index)
{
return index >= 0 && index < _propertyTypes.Length ? _propertyTypes[index] : null;
}

View File

@@ -31,32 +31,43 @@ namespace Umbraco.Core.Models.PublishedContent
return new PublishedContentType(contentType, this);
}
// fixme kill
// for tests
internal IPublishedContentType CreateContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
{
return new PublishedContentType(id, alias, PublishedItemType.Content, Enumerable.Empty<string>(), propertyTypes, variations, isElement);
}
internal IPublishedContentType CreateContentType(int id, string alias, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
{
return new PublishedContentType(id, alias, PublishedItemType.Content, Enumerable.Empty<string>(), propertyTypes, variations, isElement);
}
// fixme kill
// for tests
internal IPublishedContentType CreateContentType(int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
{
return new PublishedContentType(id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, variations, isElement);
}
internal IPublishedContentType CreateContentType(int id, string alias, IEnumerable<string> compositionAliases, Func<IPublishedContentType, IEnumerable<IPublishedPropertyType>> propertyTypes, ContentVariation variations = ContentVariation.Nothing, bool isElement = false)
{
return new PublishedContentType(id, alias, PublishedItemType.Content, compositionAliases, propertyTypes, variations, isElement);
}
/// <inheritdoc />
public PublishedPropertyType CreatePropertyType(IPublishedContentType contentType, PropertyType propertyType)
public IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, PropertyType propertyType)
{
return new PublishedPropertyType(contentType, propertyType, _propertyValueConverters, _publishedModelFactory, this);
}
/// <inheritdoc />
public PublishedPropertyType CreatePropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations = ContentVariation.Nothing)
public IPublishedPropertyType CreatePropertyType(IPublishedContentType contentType, string propertyTypeAlias, int dataTypeId, ContentVariation variations = ContentVariation.Nothing)
{
return new PublishedPropertyType(contentType, propertyTypeAlias, dataTypeId, true, variations, _propertyValueConverters, _publishedModelFactory, this);
}
// fixme kill
// for tests
internal PublishedPropertyType CreatePropertyType(string propertyTypeAlias, int dataTypeId, bool umbraco = false, ContentVariation variations = ContentVariation.Nothing)
internal IPublishedPropertyType CreatePropertyType(string propertyTypeAlias, int dataTypeId, bool umbraco = false, ContentVariation variations = ContentVariation.Nothing)
{
return new PublishedPropertyType(propertyTypeAlias, dataTypeId, umbraco, variations, _propertyValueConverters, _publishedModelFactory, this);
}

View File

@@ -12,7 +12,7 @@ namespace Umbraco.Core.Models.PublishedContent
/// <summary>
/// Initializes a new instance of the <see cref="PublishedPropertyBase"/> class.
/// </summary>
protected PublishedPropertyBase(PublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel)
protected PublishedPropertyBase(IPublishedPropertyType propertyType, PropertyCacheLevel referenceCacheLevel)
{
PropertyType = propertyType ?? throw new ArgumentNullException(nameof(propertyType));
ReferenceCacheLevel = referenceCacheLevel;
@@ -42,7 +42,7 @@ namespace Umbraco.Core.Models.PublishedContent
/// <summary>
/// Gets the property type.
/// </summary>
public PublishedPropertyType PropertyType { get; }
public IPublishedPropertyType PropertyType { get; }
/// <summary>
/// Gets the property reference cache level.

View File

@@ -10,10 +10,8 @@ namespace Umbraco.Core.Models.PublishedContent
/// </summary>
/// <remarks>Instances of the <see cref="PublishedPropertyType"/> class are immutable, ie
/// if the property type changes, then a new class needs to be created.</remarks>
public class PublishedPropertyType
public class PublishedPropertyType : IPublishedPropertyType
{
// TODO: API design review, should this be an interface?
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly PropertyValueConverterCollection _propertyValueConverters;
private readonly object _locker = new object();
@@ -38,6 +36,7 @@ namespace Umbraco.Core.Models.PublishedContent
ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
}
// fixme should be internal?
/// <summary>
/// This constructor is for tests and is not intended to be used directly from application code.
/// </summary>
@@ -51,6 +50,7 @@ namespace Umbraco.Core.Models.PublishedContent
ContentType = contentType ?? throw new ArgumentNullException(nameof(contentType));
}
// fixme should be internal?
/// <summary>
/// This constructor is for tests and is not intended to be used directly from application code.
/// </summary>
@@ -75,37 +75,22 @@ namespace Umbraco.Core.Models.PublishedContent
#region Property type
/// <summary>
/// Gets the published content type containing the property type.
/// </summary>
/// <inheritdoc />
public IPublishedContentType ContentType { get; internal set; } // internally set by PublishedContentType constructor
/// <summary>
/// Gets the data type.
/// </summary>
/// <inheritdoc />
public PublishedDataType DataType { get; }
/// <summary>
/// Gets property type alias.
/// </summary>
/// <inheritdoc />
public string Alias { get; }
/// <summary>
/// Gets the property editor alias.
/// </summary>
/// <inheritdoc />
public string EditorAlias => DataType.EditorAlias;
/// <summary>
/// Gets a value indicating whether the property is a user content property.
/// </summary>
/// <remarks>A non-user content property is a property that has been added to a
/// published content type by Umbraco but does not corresponds to a user-defined
/// published property.</remarks>
/// <inheritdoc />
public bool IsUserProperty { get; }
/// <summary>
/// Gets the content variations of the property type.
/// </summary>
/// <inheritdoc />
public ContentVariation Variations { get; }
#endregion
@@ -193,10 +178,7 @@ namespace Umbraco.Core.Models.PublishedContent
_modelClrType = _converter == null ? typeof (object) : _converter.GetPropertyValueType(this);
}
/// <summary>
/// Determines whether a value is an actual value, or not a value.
/// </summary>
/// <remarks>Used by property.HasValue and, for instance, in fallback scenarios.</remarks>
/// <inheritdoc />
public bool? IsValue(object value, PropertyValueLevel level)
{
if (!_initialized) Initialize();
@@ -209,9 +191,7 @@ namespace Umbraco.Core.Models.PublishedContent
return value != null && (!(value is string) || string.IsNullOrWhiteSpace((string) value) == false);
}
/// <summary>
/// Gets the property cache level.
/// </summary>
/// <inheritdoc />
public PropertyCacheLevel CacheLevel
{
get
@@ -221,13 +201,7 @@ namespace Umbraco.Core.Models.PublishedContent
}
}
/// <summary>
/// Converts the source value into the intermediate value.
/// </summary>
/// <param name="owner">The published element owning the property.</param>
/// <param name="source">The source value.</param>
/// <param name="preview">A value indicating whether content should be considered draft.</param>
/// <returns>The intermediate value.</returns>
/// <inheritdoc />
public object ConvertSourceToInter(IPublishedElement owner, object source, bool preview)
{
if (!_initialized) Initialize();
@@ -238,14 +212,7 @@ namespace Umbraco.Core.Models.PublishedContent
: source;
}
/// <summary>
/// Converts the intermediate value into the object value.
/// </summary>
/// <param name="owner">The published element owning the property.</param>
/// <param name="referenceCacheLevel">The reference cache level.</param>
/// <param name="inter">The intermediate value.</param>
/// <param name="preview">A value indicating whether content should be considered draft.</param>
/// <returns>The object value.</returns>
/// <inheritdoc />
public object ConvertInterToObject(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
if (!_initialized) Initialize();
@@ -256,17 +223,7 @@ namespace Umbraco.Core.Models.PublishedContent
: inter;
}
/// <summary>
/// Converts the intermediate value into the XPath value.
/// </summary>
/// <param name="owner">The published element owning the property.</param>
/// <param name="referenceCacheLevel">The reference cache level.</param>
/// <param name="inter">The intermediate value.</param>
/// <param name="preview">A value indicating whether content should be considered draft.</param>
/// <returns>The XPath value.</returns>
/// <remarks>
/// <para>The XPath value can be either a string or an XPathNavigator.</para>
/// </remarks>
/// <inheritdoc />
public object ConvertInterToXPath(IPublishedElement owner, PropertyCacheLevel referenceCacheLevel, object inter, bool preview)
{
if (!_initialized) Initialize();
@@ -282,13 +239,7 @@ namespace Umbraco.Core.Models.PublishedContent
return inter.ToString().Trim();
}
/// <summary>
/// Gets the property model CLR type.
/// </summary>
/// <remarks>
/// <para>The model CLR type may be a <see cref="ModelType"/> type, or may contain <see cref="ModelType"/> types.</para>
/// <para>For the actual CLR type, see <see cref="ClrType"/>.</para>
/// </remarks>
/// <inheritdoc />
public Type ModelClrType
{
get
@@ -298,14 +249,7 @@ namespace Umbraco.Core.Models.PublishedContent
}
}
/// <summary>
/// Gets the property CLR type.
/// </summary>
/// <remarks>
/// <para>Returns the actual CLR type which does not contain <see cref="ModelType"/> types.</para>
/// <para>Mapping from <see cref="ModelClrType"/> may throw if some <see cref="ModelType"/> instances
/// could not be mapped to actual CLR types.</para>
/// </remarks>
/// <inheritdoc />
public Type ClrType
{
get

View File

@@ -38,7 +38,7 @@ namespace Umbraco.Core.Models.PublishedContent
public override object GetXPathValue(string culture = null, string segment = null)
=> string.IsNullOrEmpty(culture) & string.IsNullOrEmpty(segment) ? _xpathValue.Value : null;
public RawValueProperty(PublishedPropertyType propertyType, IPublishedElement content, object sourceValue, bool isPreviewing = false)
public RawValueProperty(IPublishedPropertyType propertyType, IPublishedElement content, object sourceValue, bool isPreviewing = false)
: base(propertyType, PropertyCacheLevel.Unknown) // cache level is ignored
{
if (propertyType.Variations != ContentVariation.Nothing)