diff --git a/src/Umbraco.Core/Models/DataType.cs b/src/Umbraco.Core/Models/DataType.cs
index d26901ae94..0c32483fd3 100644
--- a/src/Umbraco.Core/Models/DataType.cs
+++ b/src/Umbraco.Core/Models/DataType.cs
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.Serialization;
+using Newtonsoft.Json;
using Umbraco.Core.Models.Entities;
using Umbraco.Core.PropertyEditors;
@@ -16,49 +17,54 @@ namespace Umbraco.Core.Models
{
private static PropertySelectors _selectors;
- private string _editorAlias;
+ private PropertyEditor _editor;
private ValueStorageType _databaseType;
private object _configuration;
private bool _hasConfiguration;
private string _configurationJson;
- private PropertyEditor _editor;
///
/// Initializes a new instance of the class.
///
- public DataType(int parentId, string propertyEditorAlias)
+ public DataType(PropertyEditor editor, int parentId = -1)
{
+ _editor = editor ?? throw new ArgumentNullException(nameof(editor));
ParentId = parentId;
- _editorAlias = propertyEditorAlias;
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- public DataType(string propertyEditorAlias)
- {
- ParentId = -1;
- _editorAlias = propertyEditorAlias;
}
private static PropertySelectors Selectors => _selectors ?? (_selectors = new PropertySelectors());
- // ReSharper disable once ClassNeverInstantiated.Local
private class PropertySelectors
{
- public readonly PropertyInfo EditorAlias = ExpressionHelper.GetPropertyInfo(x => x.EditorAlias);
+ public readonly PropertyInfo Editor = ExpressionHelper.GetPropertyInfo(x => x.Editor);
public readonly PropertyInfo DatabaseType = ExpressionHelper.GetPropertyInfo(x => x.DatabaseType);
public readonly PropertyInfo Configuration = ExpressionHelper.GetPropertyInfo(x => x.Configuration);
}
///
- [DataMember]
- public string EditorAlias
+ [IgnoreDataMember]
+ public PropertyEditor Editor
{
- get => _editorAlias;
- set => SetPropertyValueAndDetectChanges(value, ref _editorAlias, Selectors.EditorAlias);
+ get => _editor;
+ set
+ {
+ // ignore if no change
+ if (_editor.Alias == value.Alias) return;
+ OnPropertyChanged(Selectors.Editor);
+
+ // try to map the existing configuration to the new configuration
+ // simulate saving to db and reloading (ie go via json)
+ var configuration = Configuration;
+ var json = JsonConvert.SerializeObject(configuration);
+ _editor = value;
+ Configuration = _editor.ConfigurationEditor.FromDatabase(json);
+ }
}
+ ///
+ [DataMember]
+ public string EditorAlias => _editor.Alias;
+
///
[DataMember]
public ValueStorageType DatabaseType
@@ -78,47 +84,68 @@ namespace Umbraco.Core.Models
// else, use the editor to get the configuration object
if (_hasConfiguration) return _configuration;
- if (_editor == null) return null;
_configuration = _editor.ConfigurationEditor.FromDatabase(_configurationJson);
_hasConfiguration = true;
_configurationJson = null;
- _editor = null;
+
return _configuration;
}
set
{
- if (value != null)
- {
- // fixme - do it HERE
- // fixme - BUT then we have a problem, what if it's changed?
- // can't we treat configurations as plain immutable objects?!
- // also it means that we just cannot work with dictionaries?
- if (value is IConfigureValueType valueTypeConfiguration)
- DatabaseType = ValueTypes.ToStorageType(valueTypeConfiguration.ValueType);
- if (value is IDictionary dictionaryConfiguration
- && dictionaryConfiguration.TryGetValue("", out var valueTypeObject)
- && valueTypeObject is string valueTypeString)
- DatabaseType = ValueTypes.ToStorageType(valueTypeString);
- }
+ if (value == null)
+ throw new ArgumentNullException(nameof(value));
- // fixme detect changes? if it's the same object? need a special comparer!
- SetPropertyValueAndDetectChanges(value, ref _configuration, Selectors.Configuration);
+ // we don't support re-assigning the same object
+ // configurations are kinda non-mutable, mainly because detecting changes would be a pain
+ if (_configuration == value) // reference comparison
+ throw new ArgumentException("Configurations are kinda non-mutable. Do not reassign the same object.", nameof(value));
+
+ // validate configuration type
+ if (!_editor.ConfigurationEditor.IsConfiguration(value))
+ throw new ArgumentException($"Value of type {value.GetType().Name} cannot be a configuration for editor {_editor.Alias}, expecting.", nameof(value));
+
+ // extract database type from configuration object, if appropriate
+ if (value is IConfigureValueType valueTypeConfiguration)
+ DatabaseType = ValueTypes.ToStorageType(valueTypeConfiguration.ValueType);
+
+ // extract database type from dictionary, if appropriate
+ if (value is IDictionary dictionaryConfiguration
+ && dictionaryConfiguration.TryGetValue(Constants.PropertyEditors.ConfigurationKeys.DataValueType, out var valueTypeObject)
+ && valueTypeObject is string valueTypeString
+ && ValueTypes.IsValue(valueTypeString))
+ DatabaseType = ValueTypes.ToStorageType(valueTypeString);
+
+ _configuration = value;
_hasConfiguration = true;
_configurationJson = null;
- _editor = null;
+
+ // it's always a change
+ OnPropertyChanged(Selectors.Configuration);
}
}
- /// // fixme on interface!?
- public void SetConfiguration(string configurationJson, PropertyEditor editor)
+ public abstract class EditorConfiguration
+ {
+ public abstract bool Equals(EditorConfiguration other);
+ }
+
+ ///
+ /// Lazily set the configuration as a serialized json string.
+ ///
+ ///
+ /// Will be de-serialized on-demand.
+ /// This method is meant to be used when building entities from database, exclusively.
+ /// It does NOT register a property change to dirty. It ignores the fact that the configuration
+ /// may contain the database type, because the datatype DTO should also contain that database
+ /// type, and they should be the same.
+ /// Think before using!
+ ///
+ internal void SetConfiguration(string configurationJson)
{
- // fixme this is lazy, BUT then WHEN are we figuring out the valueType?
- _editor = editor ?? throw new ArgumentNullException(nameof(editor));
_hasConfiguration = false;
_configuration = null;
_configurationJson = configurationJson;
- OnPropertyChanged(Selectors.Configuration);
}
}
}
diff --git a/src/Umbraco.Core/Models/IDataType.cs b/src/Umbraco.Core/Models/IDataType.cs
index 37a54c36b4..c44629a8c0 100644
--- a/src/Umbraco.Core/Models/IDataType.cs
+++ b/src/Umbraco.Core/Models/IDataType.cs
@@ -1,4 +1,5 @@
using Umbraco.Core.Models.Entities;
+using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Models
{
@@ -8,9 +9,14 @@ namespace Umbraco.Core.Models
public interface IDataType : IUmbracoEntity
{
///
- /// Gets or sets the property editor alias.
+ /// Gets or sets the property editor.
///
- string EditorAlias { get; set; }
+ PropertyEditor Editor { get; set; }
+
+ ///
+ /// Gets the property editor alias.
+ ///
+ string EditorAlias { get; }
///
/// Gets or sets the database type for the data type values.
diff --git a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
index 8c560f094f..e8ddadd79a 100644
--- a/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
+++ b/src/Umbraco.Core/Persistence/Factories/DataTypeFactory.cs
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Factories
if (!editors.TryGet(dto.EditorAlias, out var editor))
throw new InvalidOperationException($"Could not find an editor with alias \"{dto.EditorAlias}\".");
- var dataType = new DataType(dto.EditorAlias);
+ var dataType = new DataType(editor);
try
{
@@ -32,7 +32,7 @@ namespace Umbraco.Core.Persistence.Factories
dataType.Trashed = dto.NodeDto.Trashed;
dataType.CreatorId = dto.NodeDto.UserId ?? 0;
- dataType.SetConfiguration(dto.Configuration, editor);
+ dataType.SetConfiguration(dto.Configuration);
// reset dirty initial properties (U4-1946)
dataType.ResetDirtyProperties(false);
diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs
index 24756aefd0..86444a4cc3 100644
--- a/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs
+++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DataTypeRepository.cs
@@ -9,7 +9,6 @@ using Umbraco.Core.Events;
using Umbraco.Core.Exceptions;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
-using Umbraco.Core.Models.Entities;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Persistence.Factories;
using Umbraco.Core.Persistence.Querying;
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
index a94506967d..0b82322513 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditor.cs
@@ -56,6 +56,12 @@ namespace Umbraco.Core.PropertyEditors
/// The default configuration is used to initialize new datatypes.
public virtual IDictionary DefaultConfiguration => new Dictionary();
+ ///
+ /// Determines whether a configuration object is of the type expected by the configuration editor.
+ ///
+ public virtual bool IsConfiguration(object obj)
+ => obj is IDictionary;
+
// notes
// ToConfigurationEditor returns a dictionary, and FromConfigurationEditor accepts a dictionary.
// this is due to the way our front-end editors work, see DataTypeController.PostSave
diff --git a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
index 945d8e8b5a..96965f731a 100644
--- a/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
+++ b/src/Umbraco.Core/PropertyEditors/ConfigurationEditorOfTConfiguration.cs
@@ -94,6 +94,10 @@ namespace Umbraco.Core.PropertyEditors
///
public override IDictionary DefaultConfiguration => ToConfigurationEditor(new TConfiguration());
+ ///
+ public override bool IsConfiguration(object obj)
+ => obj is TConfiguration;
+
///
public override object FromDatabase(string configuration)
{
diff --git a/src/Umbraco.Core/PropertyEditors/VoidEditor.cs b/src/Umbraco.Core/PropertyEditors/VoidEditor.cs
new file mode 100644
index 0000000000..429db431fe
--- /dev/null
+++ b/src/Umbraco.Core/PropertyEditors/VoidEditor.cs
@@ -0,0 +1,21 @@
+using Umbraco.Core.Composing;
+using Umbraco.Core.Logging;
+
+namespace Umbraco.Core.PropertyEditors
+{
+ ///
+ /// Represents a void editor.
+ ///
+ /// Can be used in some places where an editor is needed but no actual
+ /// editor is available. Not to be used otherwise. Not discovered, and therefore
+ /// not part of the editors collection.
+ [HideFromTypeFinder]
+ public class VoidEditor : PropertyEditor
+ {
+ public VoidEditor(ILogger logger)
+ : base(logger)
+ {
+ Alias = "Umbraco.Void";
+ }
+ }
+}
diff --git a/src/Umbraco.Core/Services/Implement/PackagingService.cs b/src/Umbraco.Core/Services/Implement/PackagingService.cs
index 579de1adac..ddc72a285c 100644
--- a/src/Umbraco.Core/Services/Implement/PackagingService.cs
+++ b/src/Umbraco.Core/Services/Implement/PackagingService.cs
@@ -872,7 +872,7 @@ namespace Umbraco.Core.Services.Implement
throw new ArgumentException("The passed in XElement is not valid! It does not contain a root element called 'DataTypes' for multiple imports or 'DataType' for a single import.");
}
- var dataTypes = new Dictionary();
+ var dataTypes = new List();
var dataTypeElements = name.Equals("DataTypes")
? (from doc in element.Elements("DataType") select doc).ToList()
: new List { element };
@@ -898,16 +898,31 @@ namespace Umbraco.Core.Services.Implement
? databaseTypeAttribute.Value.EnumParse(true)
: ValueStorageType.Ntext;
- //the Id field is actually the string property editor Alias
- var dataTypeDefinition = new DataType(dataTypeElement.Attribute("Id").Value.Trim())
+ // the Id field is actually the string property editor Alias
+ // however, the actual editor with this alias could be installed with the package, and
+ // therefore not yet part of the _propertyEditors collection, so we cannot try and get
+ // the actual editor - going with a void editor
+
+ var editorAlias = dataTypeElement.Attribute("Id")?.Value?.Trim();
+ if (!_propertyEditors.TryGet(editorAlias, out var editor))
+ editor = new VoidEditor(_logger) { Alias = editorAlias };
+
+ var dataTypeDefinition = new DataType(editor)
{
Key = dataTypeDefinitionId,
Name = dataTypeDefinitionName,
DatabaseType = databaseType,
ParentId = parentId
};
- dataTypes.Add(dataTypeDefinitionName, dataTypeDefinition);
+ // fixme - so what?
+ var configurationAttribute = dataTypeElement.Attribute("Configuration");
+ if (!string.IsNullOrWhiteSpace(configurationAttribute?.Value))
+ {
+ dataTypeDefinition.Configuration = editor.ConfigurationEditor.FromDatabase(configurationAttribute.Value);
+ }
+
+ dataTypes.Add(dataTypeDefinition);
}
else
{
@@ -916,24 +931,15 @@ namespace Umbraco.Core.Services.Implement
}
}
- var list = dataTypes.Select(x => x.Value).ToList();
- if (list.Any())
+ if (dataTypes.Count > 0)
{
- //NOTE: As long as we have to deal with the two types of PreValue lists (with/without Keys)
- //this is a bit of a pain to handle while ensuring that the imported DataTypes has PreValues
- //place when triggering the save event.
-
- _dataTypeService.Save(list, userId, false);//Save without raising events
-
- SavePrevaluesFromXml(list, dataTypeElements);//Save the PreValues for the current list of DataTypes
-
- _dataTypeService.Save(list, userId, true);//Re-save and raise events
+ _dataTypeService.Save(dataTypes, userId, true);
}
if (raiseEvents)
- ImportedDataType.RaiseEvent(new ImportEventArgs(list, element, false), this);
+ ImportedDataType.RaiseEvent(new ImportEventArgs(dataTypes, element, false), this);
- return list;
+ return dataTypes;
}
private Dictionary CreateDataTypeFolderStructure(IEnumerable datatypeElements)
@@ -994,39 +1000,6 @@ namespace Umbraco.Core.Services.Implement
return _dataTypeService.GetContainer(tryCreateFolder.Result.Entity.Id);
}
- private void SavePrevaluesFromXml(List dataTypes, IEnumerable dataTypeElements)
- {
- foreach (var dataTypeElement in dataTypeElements)
- {
- var configurationAttribute = dataTypeElement.Attribute("Configuration");
- if (string.IsNullOrWhiteSpace(configurationAttribute?.Value)) continue;
-
- var dataTypeName = dataTypeElement.Attribute("Name")?.Value;
- var dataType = dataTypes.FirstOrDefault(x => x.Name == dataTypeName);
-
- if (dataType == null)
- {
- _logger.Warn($"No data type found with name \"{dataTypeName}\", configuration will not be saved.");
- continue;
- }
-
- if (!_propertyEditors.TryGet(dataType.EditorAlias, out var editor))
- {
- _logger.Warn($"Failed to find an editor with alias \"{dataType.EditorAlias}\", configuration will not be saved.");
- continue;
- }
-
- try
- {
- dataType.Configuration = editor.ConfigurationEditor.FromDatabase(configurationAttribute.Value);
- }
- catch (Exception ex)
- {
- _logger.Warn($"Failed to deserialize string \"{configurationAttribute.Value}\" as configuration for editor of type \"{editor.GetType().Name}\".", ex);
- }
- }
- }
-
#endregion
#region Dictionary Items
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 8e10804c41..3f219bae7a 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -343,6 +343,7 @@
+
diff --git a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
index bd289dcdf7..f79953e13e 100644
--- a/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
+++ b/src/Umbraco.Tests/Manifest/ManifestParserTests.cs
@@ -194,7 +194,7 @@ javascript: ['~/test.js',/*** some note about stuff asd09823-4**09234*/ '~/test2
// this is not part of the manifest
var preValues = editor.DefaultConfiguration;
- Assert.IsNull(preValues);
+ Assert.IsEmpty(preValues);
var preValueEditor = editor.ConfigurationEditor;
Assert.IsNotNull(preValueEditor);
diff --git a/src/Umbraco.Tests/Models/DataTypeTests.cs b/src/Umbraco.Tests/Models/DataTypeTests.cs
index 35b4476fd7..6a943c9695 100644
--- a/src/Umbraco.Tests/Models/DataTypeTests.cs
+++ b/src/Umbraco.Tests/Models/DataTypeTests.cs
@@ -1,8 +1,10 @@
using System;
-using System.Collections.Generic;
using System.Diagnostics;
+using Moq;
using NUnit.Framework;
+using Umbraco.Core.Logging;
using Umbraco.Core.Models;
+using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Serialization;
namespace Umbraco.Tests.Models
@@ -13,7 +15,7 @@ namespace Umbraco.Tests.Models
[Test]
public void Can_Deep_Clone()
{
- var dtd = new DataType(9, Guid.NewGuid().ToString())
+ var dtd = new DataType(new VoidEditor(Mock.Of()), 9)
{
CreateDate = DateTime.Now,
CreatorId = 5,
@@ -58,7 +60,7 @@ namespace Umbraco.Tests.Models
{
var ss = new SerializationService(new JsonNetSerializer());
- var dtd = new DataType(9, Guid.NewGuid().ToString())
+ var dtd = new DataType(new VoidEditor(Mock.Of()), 9)
{
CreateDate = DateTime.Now,
CreatorId = 5,
diff --git a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs
index 149fe9f6ab..b9eac41784 100644
--- a/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs
+++ b/src/Umbraco.Tests/Models/Mapping/ContentTypeModelMappingTests.cs
@@ -502,7 +502,7 @@ namespace Umbraco.Tests.Models.Mapping
public void MemberPropertyGroupBasic_To_MemberPropertyGroup()
{
_dataTypeService.Setup(x => x.GetDataType(It.IsAny()))
- .Returns(new DataType("test"));
+ .Returns(new DataType(new VoidEditor(Mock.Of())));
var basic = new PropertyGroupBasic
{
@@ -571,7 +571,7 @@ namespace Umbraco.Tests.Models.Mapping
public void PropertyGroupBasic_To_PropertyGroup()
{
_dataTypeService.Setup(x => x.GetDataType(It.IsAny()))
- .Returns(new DataType("test"));
+ .Returns(new DataType(new VoidEditor(Mock.Of())));
var basic = new PropertyGroupBasic
{
@@ -637,7 +637,7 @@ namespace Umbraco.Tests.Models.Mapping
public void MemberPropertyTypeBasic_To_PropertyType()
{
_dataTypeService.Setup(x => x.GetDataType(It.IsAny()))
- .Returns(new DataType("test"));
+ .Returns(new DataType(new VoidEditor(Mock.Of())));
var basic = new MemberPropertyTypeBasic()
{
@@ -671,7 +671,7 @@ namespace Umbraco.Tests.Models.Mapping
public void PropertyTypeBasic_To_PropertyType()
{
_dataTypeService.Setup(x => x.GetDataType(It.IsAny()))
- .Returns(new DataType("test"));
+ .Returns(new DataType(new VoidEditor(Mock.Of())));
var basic = new PropertyTypeBasic()
{
@@ -883,7 +883,7 @@ namespace Umbraco.Tests.Models.Mapping
public void MemberPropertyTypeBasic_To_MemberPropertyTypeDisplay()
{
_dataTypeService.Setup(x => x.GetDataType(It.IsAny()))
- .Returns(new DataType("test"));
+ .Returns(new DataType(new VoidEditor(Mock.Of())));
var basic = new MemberPropertyTypeBasic()
{
@@ -921,7 +921,7 @@ namespace Umbraco.Tests.Models.Mapping
public void PropertyTypeBasic_To_PropertyTypeDisplay()
{
_dataTypeService.Setup(x => x.GetDataType(It.IsAny()))
- .Returns(new DataType("test"));
+ .Returns(new DataType(new VoidEditor(Mock.Of())));
var basic = new PropertyTypeBasic()
{
diff --git a/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs b/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs
index 59d718e63f..edb8674dd8 100644
--- a/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs
+++ b/src/Umbraco.Tests/Persistence/Querying/ExpressionTests.cs
@@ -13,6 +13,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Tests.TestHelpers;
using System.Linq;
using Umbraco.Core.Persistence.Dtos;
+using Umbraco.Core.PropertyEditors;
namespace Umbraco.Tests.Persistence.Querying
{
@@ -22,7 +23,7 @@ namespace Umbraco.Tests.Persistence.Querying
[Test]
public void Equals_Claus_With_Two_Entity_Values()
{
- var dataType = new DataType(-1, "Test")
+ var dataType = new DataType(new VoidEditor(Mock.Of()))
{
Id = 12345
};
diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
index 1b028de6a0..1c5736c698 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs
@@ -18,6 +18,7 @@ using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
using Umbraco.Tests.Testing;
+using Umbraco.Web.PropertyEditors;
namespace Umbraco.Tests.Persistence.Repositories
{
@@ -347,7 +348,8 @@ namespace Umbraco.Tests.Persistence.Repositories
{
var repository = CreateRepository((IScopeAccessor) provider, out var contentTypeRepository, out DataTypeRepository dataTypeDefinitionRepository);
- var dtd = new DataType(-1, Constants.PropertyEditors.Aliases.Decimal) { Name = "test", DatabaseType = ValueStorageType.Decimal };
+ var editor = new DecimalPropertyEditor(Logger);
+ var dtd = new DataType(editor) { Name = "test", DatabaseType = ValueStorageType.Decimal };
dataTypeDefinitionRepository.Save(dtd);
const string decimalPropertyAlias = "decimalProperty";
diff --git a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs
index 20d066adb8..cc515c4347 100644
--- a/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs
+++ b/src/Umbraco.Tests/Persistence/Repositories/DataTypeDefinitionRepositoryTest.cs
@@ -8,7 +8,9 @@ using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
using LightInject;
using Umbraco.Core.Persistence.Repositories.Implement;
+using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Scoping;
+using Umbraco.Web.PropertyEditors;
namespace Umbraco.Tests.Persistence.Repositories
{
@@ -42,14 +44,14 @@ namespace Umbraco.Tests.Persistence.Repositories
var container2 = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah2", ParentId = container1.Id };
containerRepository.Save(container2);
- var dataType = (IDataType)new DataType(container2.Id, Constants.PropertyEditors.Aliases.RadioButtonList)
+ var dataType = (IDataType) new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService), container2.Id)
{
Name = "dt1"
};
repository.Save(dataType);
//create a
- var dataType2 = (IDataType)new DataType(dataType.Id, Constants.PropertyEditors.Aliases.RadioButtonList)
+ var dataType2 = (IDataType)new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService), dataType.Id)
{
Name = "dt2"
};
@@ -121,7 +123,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" };
containerRepository.Save(container);
- var dataTypeDefinition = new DataType(container.Id, Constants.PropertyEditors.Aliases.RadioButtonList) { Name = "test" };
+ var dataTypeDefinition = new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService), container.Id) { Name = "test" };
repository.Save(dataTypeDefinition);
Assert.AreEqual(container.Id, dataTypeDefinition.ParentId);
@@ -141,7 +143,7 @@ namespace Umbraco.Tests.Persistence.Repositories
var container = new EntityContainer(Constants.ObjectTypes.DataType) { Name = "blah" };
containerRepository.Save(container);
- IDataType dataType = new DataType(container.Id, Constants.PropertyEditors.Aliases.RadioButtonList) { Name = "test" };
+ IDataType dataType = new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService), container.Id) { Name = "test" };
repository.Save(dataType);
// Act
@@ -164,7 +166,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (provider.CreateScope())
{
var repository = CreateRepository();
- IDataType dataType = new DataType(-1, Constants.PropertyEditors.Aliases.RadioButtonList) {Name = "test"};
+ IDataType dataType = new DataType(new RadioButtonsPropertyEditor(Logger, ServiceContext.TextService)) {Name = "test"};
repository.Save(dataType);
@@ -285,11 +287,12 @@ namespace Umbraco.Tests.Persistence.Repositories
using (provider.CreateScope())
{
var repository = CreateRepository();
- var dataTypeDefinition = new DataType(Constants.PropertyEditors.Aliases.NoEdit)
+ var dataTypeDefinition = new DataType(new LabelPropertyEditor(Logger))
{
DatabaseType = ValueStorageType.Integer,
Name = "AgeDataType",
- CreatorId = 0
+ CreatorId = 0,
+ Configuration = new LabelConfiguration { ValueType = ValueTypes.Xml }
};
// Act
@@ -302,7 +305,15 @@ namespace Umbraco.Tests.Persistence.Repositories
Assert.That(dataTypeDefinition.HasIdentity, Is.True);
Assert.That(exists, Is.True);
- TestHelper.AssertPropertyValuesAreEqual(dataTypeDefinition, fetched, "yyyy-MM-dd HH:mm:ss");
+ // cannot compare 'configuration' as it's two different objects
+ TestHelper.AssertPropertyValuesAreEqual(dataTypeDefinition, fetched, "yyyy-MM-dd HH:mm:ss", ignoreProperties: new [] { "Configuration" });
+
+ // still, can compare explicitely
+ Assert.IsNotNull(dataTypeDefinition.Configuration);
+ Assert.IsInstanceOf(dataTypeDefinition.Configuration);
+ Assert.IsNotNull(fetched.Configuration);
+ Assert.IsInstanceOf(fetched.Configuration);
+ Assert.AreEqual(ConfigurationEditor.ConfigurationAs(dataTypeDefinition.Configuration).ValueType, ConfigurationEditor.ConfigurationAs(fetched.Configuration).ValueType);
}
}
@@ -314,7 +325,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (provider.CreateScope())
{
var repository = CreateRepository();
- var dataTypeDefinition = new DataType(Constants.PropertyEditors.Aliases.Integer)
+ var dataTypeDefinition = new DataType(new IntegerPropertyEditor(Logger))
{
DatabaseType = ValueStorageType.Integer,
Name = "AgeDataType",
@@ -325,7 +336,7 @@ namespace Umbraco.Tests.Persistence.Repositories
// Act
var definition = repository.Get(dataTypeDefinition.Id);
definition.Name = "AgeDataType Updated";
- definition.EditorAlias = Constants.PropertyEditors.Aliases.NoEdit; //change
+ definition.Editor = new LabelPropertyEditor(Logger); //change
repository.Save(definition);
var definitionUpdated = repository.Get(dataTypeDefinition.Id);
@@ -345,7 +356,7 @@ namespace Umbraco.Tests.Persistence.Repositories
using (provider.CreateScope())
{
var repository = CreateRepository();
- var dataTypeDefinition = new DataType(Constants.PropertyEditors.Aliases.NoEdit)
+ var dataTypeDefinition = new DataType(new LabelPropertyEditor(Logger))
{
DatabaseType = ValueStorageType.Integer,
Name = "AgeDataType",
diff --git a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs
index 86f859db43..5f51d8d5e8 100644
--- a/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs
+++ b/src/Umbraco.Tests/PropertyEditors/MultiValuePropertyEditorTests.cs
@@ -32,7 +32,8 @@ namespace Umbraco.Tests.PropertyEditors
var dataTypeServiceMock = new Mock();
var editor = new PublishValuesMultipleValueEditor(true, Mock.Of(), new ValueEditorAttribute("key", "nam", "view"));
- var prop = new Property(1, new PropertyType(new DataType(1, "Test.TestEditor")));
+ var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of()));
+ var prop = new Property(1, new PropertyType(dataType));
prop.SetValue("1234,4567,8910");
var result = editor.ConvertDbToString(prop.PropertyType, prop.GetValue(), new Mock().Object);
@@ -43,7 +44,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void DropDownMultipleValueEditor_No_Keys_Format_Data_For_Cache()
{
- var dataType = new DataType("editorAlias")
+ var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of()))
{
Configuration = new ValueListConfiguration
{
@@ -53,7 +54,8 @@ namespace Umbraco.Tests.PropertyEditors
new ValueListConfiguration.ValueListItem { Id = 1234, Value = "Value 2" },
new ValueListConfiguration.ValueListItem { Id = 8910, Value = "Value 3" }
}
- }
+ },
+ Id = 1
};
var dataTypeService = Mock.Of();
@@ -62,12 +64,10 @@ namespace Umbraco.Tests.PropertyEditors
.Setup(x => x.GetDataType(It.IsAny()))
.Returns(x => x == 1 ? dataType : null);
- var editor = new PublishValuesMultipleValueEditor(false, Mock.Of(), new ValueEditorAttribute("alias", "name", "view"));
-
- var prop = new Property(1, new PropertyType(new DataType(1, "Test.TestEditor") { Id = 1 }));
+ var prop = new Property(1, new PropertyType(dataType));
prop.SetValue("1234,4567,8910");
- var result = editor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
+ var result = dataType.Editor.ValueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
Assert.AreEqual("Value 1,Value 2,Value 3", result);
}
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void DropDownValueEditor_Format_Data_For_Cache()
{
- var dataType = new DataType("editorAlias")
+ var dataType = new DataType(new CheckBoxListPropertyEditor(Mock.Of(), Mock.Of()))
{
Configuration = new ValueListConfiguration
{
@@ -85,7 +85,8 @@ namespace Umbraco.Tests.PropertyEditors
new ValueListConfiguration.ValueListItem { Id = 1234, Value = "Value 2" },
new ValueListConfiguration.ValueListItem { Id = 11, Value = "Value 3" }
}
- }
+ },
+ Id = 1
};
var dataTypeService = Mock.Of();
@@ -94,12 +95,10 @@ namespace Umbraco.Tests.PropertyEditors
.Setup(x => x.GetDataType(It.IsAny()))
.Returns(x => x == 1 ? dataType : null);
- var editor = new PublishValueValueEditor(new ValueEditorAttribute("alias", "name", "view"), Mock.Of());
-
- var prop = new Property(1, new PropertyType(new DataType(1, "Test.TestEditor") { Id = 1 }));
+ var prop = new Property(1, new PropertyType(dataType));
prop.SetValue("1234");
- var result = editor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
+ var result = dataType.Editor.ValueEditor.ConvertDbToString(prop.PropertyType, prop.GetValue(), dataTypeService);
Assert.AreEqual("Value 2", result);
}
diff --git a/src/Umbraco.Tests/Published/NestedContentTests.cs b/src/Umbraco.Tests/Published/NestedContentTests.cs
index c333032599..769f16a25c 100644
--- a/src/Umbraco.Tests/Published/NestedContentTests.cs
+++ b/src/Umbraco.Tests/Published/NestedContentTests.cs
@@ -31,8 +31,13 @@ namespace Umbraco.Tests.Published
var profiler = Mock.Of();
var proflog = new ProfilingLogger(logger, profiler);
- var dataType1 = new DataType("editorAlias1")
+ PropertyEditorCollection editors = null;
+ var editor = new NestedContentPropertyEditor(logger, new Lazy(() => editors));
+ editors = new PropertyEditorCollection(new PropertyEditor[] { editor });
+
+ var dataType1 = new DataType(editor)
{
+ Id = 1,
Configuration = new NestedContentConfiguration
{
MinItems = 1,
@@ -44,8 +49,9 @@ namespace Umbraco.Tests.Published
}
};
- var dataType2 = new DataType("editorAlias2")
+ var dataType2 = new DataType(editor)
{
+ Id = 2,
Configuration = new NestedContentConfiguration
{
MinItems = 1,
@@ -124,12 +130,6 @@ namespace Umbraco.Tests.Published
new NestedContentManyValueConverter(publishedSnapshotAccessor.Object, publishedModelFactory.Object, proflog),
});
- PropertyEditorCollection editors = null;
- editors = new PropertyEditorCollection(new PropertyEditor[]
- {
- new NestedContentPropertyEditor(Mock.Of(), new Lazy(() => editors))
- });
-
var source = new DataTypeConfigurationSource(dataTypeService, editors);
var factory = new PublishedContentTypeFactory(publishedModelFactory.Object, converters, source);
diff --git a/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs b/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs
index 937117f952..2bce0ecf6c 100644
--- a/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs
+++ b/src/Umbraco.Tests/Services/CachedDataTypeServiceTests.cs
@@ -2,6 +2,7 @@
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Tests.Testing;
+using Umbraco.Web.PropertyEditors;
namespace Umbraco.Tests.Services
{
@@ -21,7 +22,7 @@ namespace Umbraco.Tests.Services
{
var dataTypeService = ServiceContext.DataTypeService;
- IDataType dataType = new DataType(-1, Constants.PropertyEditors.Aliases.NoEdit) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext };
+ IDataType dataType = new DataType(new LabelPropertyEditor(Logger)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext };
dataTypeService.Save(dataType);
//Get all the first time (no cache)
diff --git a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs
index 5491017dae..e36ab4cac8 100644
--- a/src/Umbraco.Tests/Services/DataTypeServiceTests.cs
+++ b/src/Umbraco.Tests/Services/DataTypeServiceTests.cs
@@ -7,6 +7,7 @@ using Umbraco.Core.Models;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing;
+using Umbraco.Web.PropertyEditors;
namespace Umbraco.Tests.Services
{
@@ -24,7 +25,7 @@ namespace Umbraco.Tests.Services
var dataTypeService = ServiceContext.DataTypeService;
// Act
- IDataType dataType = new DataType(-1, Constants.PropertyEditors.Aliases.NoEdit) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext };
+ IDataType dataType = new DataType(new LabelPropertyEditor(Logger)) { Name = "Testing Textfield", DatabaseType = ValueStorageType.Ntext };
dataTypeService.Save(dataType);
// Assert
@@ -66,7 +67,7 @@ namespace Umbraco.Tests.Services
var dataTypeService = ServiceContext.DataTypeService;
// Act
- var dataTypeDefinition = new DataType(-1, "Test.TestEditor") { Name = string.Empty, DatabaseType = ValueStorageType.Ntext };
+ var dataTypeDefinition = new DataType(new LabelPropertyEditor(Logger)) { Name = string.Empty, DatabaseType = ValueStorageType.Ntext };
// Act & Assert
Assert.Throws(() => dataTypeService.Save(dataTypeDefinition));
diff --git a/src/Umbraco.Tests/TestHelpers/TestHelper.cs b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
index bcd9f8fb61..75a5a3544c 100644
--- a/src/Umbraco.Tests/TestHelpers/TestHelper.cs
+++ b/src/Umbraco.Tests/TestHelpers/TestHelper.cs
@@ -152,7 +152,8 @@ namespace Umbraco.Tests.TestHelpers
else
{
// directly compare values
- Assert.AreEqual(expected, actual, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name, expected, actual);
+ Assert.AreEqual(expected, actual, "Property {0}.{1} does not match. Expected: {2} but was: {3}", property.DeclaringType.Name, property.Name,
+ expected?.ToString() ?? "", actual?.ToString() ?? "");
}
}
diff --git a/src/Umbraco.Web/Editors/DataTypeController.cs b/src/Umbraco.Web/Editors/DataTypeController.cs
index 134cda2690..7d5f5dd79d 100644
--- a/src/Umbraco.Web/Editors/DataTypeController.cs
+++ b/src/Umbraco.Web/Editors/DataTypeController.cs
@@ -33,6 +33,8 @@ namespace Umbraco.Web.Editors
[EnableOverrideAuthorization]
public class DataTypeController : BackOfficeNotificationsController
{
+ private PropertyEditorCollection PropertyEditors => Current.PropertyEditors; // fixme inject
+
///
/// Gets data type by name
///
@@ -81,7 +83,9 @@ namespace Umbraco.Web.Editors
public DataTypeDisplay GetEmpty(int parentId)
{
- var dt = new DataType(parentId, "");
+ // cannot create an "empty" data type, so use something by default.
+ var editor = PropertyEditors[Constants.PropertyEditors.Aliases.NoEdit];
+ var dt = new DataType(editor, parentId);
return Mapper.Map(dt);
}
@@ -113,7 +117,8 @@ namespace Umbraco.Web.Editors
//if it doesnt exist yet, we will create it.
if (dt == null)
{
- dt = new DataType(Constants.PropertyEditors.Aliases.ListView);
+ var editor = PropertyEditors[Constants.PropertyEditors.Aliases.ListView];
+ dt = new DataType(editor);
dt.Name = Constants.Conventions.DataTypes.ListViewPrefix + contentTypeAlias;
Services.DataTypeService.Save(dt);
}
diff --git a/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs b/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs
index a35183521d..0a91553bde 100644
--- a/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs
+++ b/src/Umbraco.Web/Models/Mapping/DataTypeMapperProfile.cs
@@ -16,6 +16,8 @@ namespace Umbraco.Web.Models.Mapping
///
internal class DataTypeMapperProfile : Profile
{
+ private PropertyEditorCollection PropertyEditors => Current.PropertyEditors; // fixme inject
+
public DataTypeMapperProfile()
{
// create, capture, cache
@@ -91,7 +93,7 @@ namespace Umbraco.Web.Models.Mapping
.ConvertUsing(src => configurationDisplayResolver.Resolve(src));
CreateMap()
- .ConstructUsing(src => new DataType(src.EditorAlias) {CreateDate = DateTime.Now})
+ .ConstructUsing(src => new DataType(PropertyEditors[src.EditorAlias]) {CreateDate = DateTime.Now})
.IgnoreEntityCommonProperties()
.ForMember(dest => dest.Id, opt => opt.MapFrom(src => Convert.ToInt32(src.Id)))
.ForMember(dest => dest.Key, opt => opt.Ignore()) // ignore key, else resets UniqueId - U4-3911
@@ -101,7 +103,8 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(dest => dest.CreatorId, opt => opt.Ignore())
.ForMember(dest => dest.Level, opt => opt.Ignore())
.ForMember(dest => dest.SortOrder, opt => opt.Ignore())
- .ForMember(dest => dest.Configuration, opt => opt.Ignore());
+ .ForMember(dest => dest.Configuration, opt => opt.Ignore())
+ .ForMember(dest => dest.Editor, opt => opt.MapFrom(src => PropertyEditors[src.EditorAlias]));
//Converts a property editor to a new list of pre-value fields - used when creating a new data type or changing a data type with new pre-vals
CreateMap>()