Refactor model type mapping in IPublishedModelFactory
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
{
|
||||
@@ -17,9 +17,18 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
IPublishedElement CreateModel(IPublishedElement element);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the model type map.
|
||||
/// Creates a List{T} of a strongly-typed model for a model type alias.
|
||||
/// </summary>
|
||||
/// <remarks>The model type map maps element type aliases to actual Clr types.</remarks>
|
||||
Dictionary<string, Type> ModelTypeMap { get; }
|
||||
/// <param name="alias">The model type alias.</param>
|
||||
/// <returns>A List{T} of the strongly-typed model, exposed as an IList.</returns>
|
||||
IList CreateModelList(string alias);
|
||||
|
||||
/// <summary>
|
||||
/// Maps a Clr type that may contain model types, to an actual Clr type.
|
||||
/// </summary>
|
||||
/// <param name="type">The Clr type.</param>
|
||||
/// <returns>The actual Clr type.</returns>
|
||||
/// <remarks>See <seealso cref="ModelType"/> for more details.</remarks>
|
||||
Type MapModelType(Type type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Umbraco.Core.Models.PublishedContent
|
||||
@@ -11,6 +12,9 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public IPublishedElement CreateModel(IPublishedElement element) => element;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, Type> ModelTypeMap { get; } = new Dictionary<string, Type>();
|
||||
public IList CreateModelList(string alias) => new List<IPublishedElement>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type MapModelType(Type type) => typeof(IPublishedElement);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
@@ -10,16 +11,16 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public class PublishedModelFactory : IPublishedModelFactory
|
||||
{
|
||||
private readonly Dictionary<string, ModelInfo> _modelInfos;
|
||||
private readonly Dictionary<string, Type> _modelTypeMap;
|
||||
|
||||
private class ModelInfo
|
||||
{
|
||||
public Type ParameterType { get; set; }
|
||||
public Func<object, object> Ctor { get; set; }
|
||||
public Type ModelType { get; set; }
|
||||
public Func<IList> ListCtor { get; set; }
|
||||
}
|
||||
|
||||
public Dictionary<string, Type> ModelTypeMap { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedModelFactory"/> class with types.
|
||||
/// </summary>
|
||||
@@ -37,7 +38,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
public PublishedModelFactory(IEnumerable<Type> types)
|
||||
{
|
||||
var modelInfos = new Dictionary<string, ModelInfo>(StringComparer.InvariantCultureIgnoreCase);
|
||||
ModelTypeMap = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase);
|
||||
var modelTypeMap = new Dictionary<string, Type>(StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
foreach (var type in types)
|
||||
{
|
||||
@@ -72,19 +73,21 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
// have to use an unsafe ctor because we don't know the types, really
|
||||
var modelCtor = ReflectionUtilities.EmitCtorUnsafe<Func<object, object>>(constructor);
|
||||
modelInfos[typeName] = new ModelInfo { ParameterType = parameterType, ModelType = type, Ctor = modelCtor };
|
||||
ModelTypeMap[typeName] = type;
|
||||
modelTypeMap[typeName] = type;
|
||||
}
|
||||
|
||||
_modelInfos = modelInfos.Count > 0 ? modelInfos : null;
|
||||
_modelTypeMap = modelTypeMap;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IPublishedElement CreateModel(IPublishedElement element)
|
||||
{
|
||||
// fail fast
|
||||
if (_modelInfos == null)
|
||||
return element;
|
||||
|
||||
if (_modelInfos.TryGetValue(element.ContentType.Alias, out var modelInfo) == false)
|
||||
if (!_modelInfos.TryGetValue(element.ContentType.Alias, out var modelInfo))
|
||||
return element;
|
||||
|
||||
// ReSharper disable once UseMethodIsInstanceOfType
|
||||
@@ -94,5 +97,27 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
// can cast, because we checked when creating the ctor
|
||||
return (IPublishedElement) modelInfo.Ctor(element);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IList CreateModelList(string alias)
|
||||
{
|
||||
// fail fast
|
||||
if (_modelInfos == null)
|
||||
return new List<IPublishedElement>();
|
||||
|
||||
if (!_modelInfos.TryGetValue(alias, out var modelInfo))
|
||||
return new List<IPublishedElement>();
|
||||
|
||||
var ctor = modelInfo.ListCtor;
|
||||
if (ctor != null) return ctor();
|
||||
|
||||
var listType = typeof(List<>).MakeGenericType(modelInfo.ModelType);
|
||||
ctor = modelInfo.ListCtor = ReflectionUtilities.EmitCtor<Func<IList>>(declaring: listType);
|
||||
return ctor();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Type MapModelType(Type type)
|
||||
=> ModelType.Map(type, _modelTypeMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ namespace Umbraco.Core.Models.PublishedContent
|
||||
get
|
||||
{
|
||||
if (!_initialized) Initialize();
|
||||
return _clrType ?? (_clrType = ModelType.Map(_modelClrType, Current.PublishedModelFactory.ModelTypeMap));
|
||||
return _clrType ?? (_clrType = Current.PublishedModelFactory.MapModelType(_modelClrType));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -71,12 +71,13 @@ namespace Umbraco.Tests.Facade
|
||||
container.RegisterSingleton(f => publishedModelFactory.Object);
|
||||
|
||||
// mocked model factory returns model type
|
||||
var modelTypes = new Dictionary<string, Type>
|
||||
{
|
||||
{ "contentN1", typeof(TestElementModel) }
|
||||
};
|
||||
publishedModelFactory
|
||||
.Setup(x => x.ModelTypeMap)
|
||||
.Returns(new Dictionary<string, Type>
|
||||
{
|
||||
{ "contentN1", typeof (TestElementModel) }
|
||||
});
|
||||
.Setup(x => x.MapModelType(It.IsAny<Type>()))
|
||||
.Returns((Type type) => ModelType.Map(type, modelTypes));
|
||||
|
||||
// mocked model factory creates models
|
||||
publishedModelFactory
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
@@ -19,7 +16,6 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
/// </summary>
|
||||
public class NestedContentManyValueConverter : NestedContentValueConverterBase
|
||||
{
|
||||
private readonly ConcurrentDictionary<Type, Func<IList>> _listCtors = new ConcurrentDictionary<Type, Func<IList>>();
|
||||
private readonly ProfilingLogger _proflog;
|
||||
|
||||
/// <summary>
|
||||
@@ -70,26 +66,9 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
// fixme do NOT do it here! + use the facade cache
|
||||
var preValueCollection = NestedContentHelper.GetPreValuesCollectionByDataTypeId(propertyType.DataTypeId);
|
||||
var contentTypes = preValueCollection.PreValuesAsDictionary["contentTypes"].Value;
|
||||
IList elements;
|
||||
if (contentTypes.Contains(","))
|
||||
{
|
||||
elements = new List<IPublishedElement>();
|
||||
}
|
||||
else if (PublishedModelFactory.ModelTypeMap.TryGetValue(contentTypes, out var type))
|
||||
{
|
||||
var ctor = _listCtors.GetOrAdd(type, t =>
|
||||
{
|
||||
var listType = typeof(List<>).MakeGenericType(t);
|
||||
return ReflectionUtilities.EmitCtor<Func<IList>>(declaring: listType);
|
||||
});
|
||||
|
||||
elements = ctor();
|
||||
}
|
||||
else
|
||||
{
|
||||
// should we throw instead?
|
||||
elements = new List<IPublishedElement>();
|
||||
}
|
||||
var elements = contentTypes.Contains(",")
|
||||
? new List<IPublishedElement>()
|
||||
: PublishedModelFactory.CreateModelList(contentTypes);
|
||||
|
||||
foreach (var sourceObject in objects)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user