Merge branch 'v13/dev' into v14/dev

# Conflicts:
#	Directory.Packages.props
#	src/Umbraco.Core/DependencyInjection/UmbracoBuilder.cs
#	src/Umbraco.Core/Models/Mapping/ContentPropertyDisplayMapper.cs
#	src/Umbraco.Core/Services/DataTypeService.cs
#	src/Umbraco.Infrastructure/PropertyEditors/BlockEditorPropertyValueEditor.cs
#	src/Umbraco.Infrastructure/PropertyEditors/BlockValuePropertyValueEditorBase.cs
#	src/Umbraco.Infrastructure/PropertyEditors/ImageCropperPropertyValueEditor.cs
#	src/Umbraco.Infrastructure/PropertyEditors/MediaPicker3PropertyEditor.cs
#	src/Umbraco.Infrastructure/PropertyEditors/NestedContentPropertyEditor.cs
#	src/Umbraco.Infrastructure/PropertyEditors/RichTextPropertyEditor.cs
This commit is contained in:
Sven Geusens
2024-02-21 14:39:41 +01:00
17 changed files with 189 additions and 61 deletions

View File

@@ -19,6 +19,7 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.1" />
<PackageVersion Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.1" />
<PackageVersion Include="Microsoft.Extensions.Caching.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Caching.Memory" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Configuration.Json" Version="8.0.0" />

View File

@@ -0,0 +1,51 @@
using Microsoft.Extensions.Caching.Memory;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.Cache;
/// <summary>
/// This cache is a temporary measure to reduce the amount of computational power required to deserialize and initialize <see cref="IDataType" /> when fetched from the main cache/database,
/// because datatypes are fetched multiple times troughout a (backoffice content) request with a lot of content (or nested content) and each of these fetches initializes certain fields on the datatypes.
/// </summary>
internal sealed class DataTypeConfigurationCache : IDataTypeConfigurationCache
{
private readonly IDataTypeService _dataTypeService;
private readonly IMemoryCache _memoryCache;
public DataTypeConfigurationCache(IDataTypeService dataTypeService, IMemoryCache memoryCache, IIdKeyMap idKeyMap)
{
_dataTypeService = dataTypeService;
_memoryCache = memoryCache;
}
public T? GetConfigurationAs<T>(Guid key)
where T : class
{
var cacheKey = GetCacheKey(key);
if (_memoryCache.TryGetValue(cacheKey, out T? configuration) is false)
{
IDataType? dataType = _dataTypeService.GetDataType(key);
configuration = dataType?.ConfigurationAs<T>();
// Only cache if data type was found (but still cache null configurations)
if (dataType is not null)
{
_memoryCache.Set(cacheKey, configuration);
}
}
return configuration;
}
public void ClearCache(IEnumerable<Guid> keys)
{
foreach (Guid key in keys)
{
_memoryCache.Remove(GetCacheKey(key));
}
}
private static string GetCacheKey(Guid key) => $"DataTypeConfigurationCache_{key}";
}

View File

@@ -0,0 +1,15 @@
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Notifications;
namespace Umbraco.Cms.Core.Cache;
internal sealed class DataTypeConfigurationCacheRefresher : INotificationHandler<DataTypeCacheRefresherNotification>
{
private readonly IDataTypeConfigurationCache _dataTypeConfigurationCache;
public DataTypeConfigurationCacheRefresher(IDataTypeConfigurationCache dataTypeConfigurationCache)
=> _dataTypeConfigurationCache = dataTypeConfigurationCache;
public void Handle(DataTypeCacheRefresherNotification notification)
=> _dataTypeConfigurationCache.ClearCache(((DataTypeCacheRefresher.JsonPayload[])notification.MessageObject).Select(x => x.Key));
}

View File

@@ -0,0 +1,33 @@
namespace Umbraco.Cms.Core.Cache;
/// <summary>
/// Represents a cache for <see cref="Umbraco.Cms.Core.Models.IDataType" /> configuration.
/// </summary>
public interface IDataTypeConfigurationCache
{
/// <summary>
/// Gets the data type configuration.
/// </summary>
/// <param name="key">The data type key.</param>
/// <returns>
/// The data type configuration.
/// </returns>
object? GetConfiguration(Guid key) => GetConfigurationAs<object>(key);
/// <summary>
/// Gets the data type configuration as <typeparamref name="T" />.
/// </summary>
/// <typeparam name="T">The data type configuration type.</typeparam>
/// <param name="key">The data type key.</param>
/// <returns>
/// The data type configuration as <typeparamref name="T" />.
/// </returns>
T? GetConfigurationAs<T>(Guid key)
where T : class;
/// <summary>
/// Clears the cache for the specified keys.
/// </summary>
/// <param name="keys">The keys.</param>
void ClearCache(IEnumerable<Guid> keys);
}

View File

@@ -371,6 +371,10 @@ namespace Umbraco.Cms.Core.DependencyInjection
Services.AddUnique<IWebhookLogService, WebhookLogService>();
Services.AddUnique<IWebhookLogFactory, WebhookLogFactory>();
Services.AddUnique<IWebhookRequestService, WebhookRequestService>();
// Data type configuration cache
Services.AddUnique<IDataTypeConfigurationCache, DataTypeConfigurationCache>();
Services.AddNotificationHandler<DataTypeCacheRefresherNotification, DataTypeConfigurationCacheRefresher>();
//Two factor providers
Services.AddUnique<ITwoFactorLoginService, TwoFactorLoginService>();

View File

@@ -36,6 +36,8 @@ internal class ContentPropertyDisplayMapper : ContentPropertyBasicMapper<Content
{
base.Map(originalProp, dest, context);
// v13 to v14 merge note: because of changes in the IDataType we can not use the optimized IDataTypeConfigurationCache here
// todo: make sure this (possible) performance degradation isn't serious
IDataType? dataType = DataTypeService.GetDataType(originalProp.PropertyType.DataTypeId);
// TODO: IDataValueEditor configuration - general issue

View File

@@ -1,4 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Dictionary;
using Umbraco.Cms.Core.Mapping;
using Umbraco.Cms.Core.Models.ContentEditing;
@@ -24,7 +27,8 @@ public class ContentPropertyMapDefinition : IMapDefinition
IEntityService entityService,
ILocalizedTextService textService,
ILoggerFactory loggerFactory,
PropertyEditorCollection propertyEditors)
PropertyEditorCollection propertyEditors,
IDataTypeConfigurationCache dataTypeConfigurationCache)
{
_contentPropertyBasicConverter = new ContentPropertyBasicMapper<ContentPropertyBasic>(
dataTypeService,
@@ -42,9 +46,28 @@ public class ContentPropertyMapDefinition : IMapDefinition
entityService,
textService,
loggerFactory.CreateLogger<ContentPropertyDisplayMapper>(),
propertyEditors);
propertyEditors,
dataTypeConfigurationCache);
}
[Obsolete("Please use constructor that takes an IDataTypeConfigurationCache. Will be removed in V14.")]
public ContentPropertyMapDefinition(
ICultureDictionary cultureDictionary,
IDataTypeService dataTypeService,
IEntityService entityService,
ILocalizedTextService textService,
ILoggerFactory loggerFactory,
PropertyEditorCollection propertyEditors)
: this(
cultureDictionary,
dataTypeService,
entityService,
textService,
loggerFactory,
propertyEditors,
StaticServiceProvider.Instance.GetRequiredService<IDataTypeConfigurationCache>())
{ }
public void DefineMaps(IUmbracoMapper mapper)
{
mapper.Define<PropertyGroup, Tab<ContentPropertyDisplay>>(

View File

@@ -29,6 +29,7 @@ namespace Umbraco.Cms.Core.Services.Implement
private readonly IIOHelper _ioHelper;
private readonly IDataTypeContainerService _dataTypeContainerService;
private readonly IUserIdKeyResolver _userIdKeyResolver;
private readonly Lazy<IIdKeyMap> _idKeyMap;
public DataTypeService(
ICoreScopeProvider provider,
@@ -38,7 +39,8 @@ namespace Umbraco.Cms.Core.Services.Implement
IDataValueEditorFactory dataValueEditorFactory,
IAuditRepository auditRepository,
IContentTypeRepository contentTypeRepository,
IIOHelper ioHelper)
IIOHelper ioHelper,
Lazy<IIdKeyMap> idKeyMap)
: base(provider, loggerFactory, eventMessagesFactory)
{
_dataValueEditorFactory = dataValueEditorFactory;
@@ -46,6 +48,7 @@ namespace Umbraco.Cms.Core.Services.Implement
_auditRepository = auditRepository;
_contentTypeRepository = contentTypeRepository;
_ioHelper = ioHelper;
_idKeyMap = idKeyMap;
// resolve dependencies for obsolete methods through the static service provider, so they don't pollute the constructor signature
_dataTypeContainerService = StaticServiceProvider.Instance.GetRequiredService<IDataTypeContainerService>();
@@ -743,11 +746,11 @@ namespace Umbraco.Cms.Core.Services.Implement
}
private IDataType? GetDataTypeFromRepository(Guid id)
=> _idKeyMap.Value.GetIdForKey(id, UmbracoObjectTypes.DataType) switch
{
IQuery<IDataType> query = Query<IDataType>().Where(x => x.Key == id);
IDataType? dataType = _dataTypeRepository.Get(query).FirstOrDefault();
return dataType;
}
{ Success: false } => null,
{ Result: var intId } => _dataTypeRepository.Get(intId),
};
private void Audit(AuditType type, int userId, int objectId)
=> _auditRepository.Save(new AuditItem(objectId, type, userId, ObjectTypes.GetName(UmbracoObjectTypes.DataType)));

View File

@@ -8,6 +8,7 @@
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Embedded" />
<PackageReference Include="Microsoft.Extensions.FileProviders.Physical" />

View File

@@ -2,6 +2,7 @@
// See LICENSE for more details.
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
@@ -18,7 +19,7 @@ internal abstract class BlockEditorPropertyValueEditor<TValue, TLayout> : BlockV
{
private readonly IJsonSerializer _jsonSerializer;
private BlockEditorValues<TValue, TLayout>? _blockEditorValues;
private readonly IDataTypeService _dataTypeService;
private readonly IDataTypeConfigurationCache _dataTypeConfigurationCache;
private readonly PropertyEditorCollection _propertyEditors;
private readonly DataValueReferenceFactoryCollection _dataValueReferenceFactories;
@@ -26,17 +27,17 @@ internal abstract class BlockEditorPropertyValueEditor<TValue, TLayout> : BlockV
DataEditorAttribute attribute,
PropertyEditorCollection propertyEditors,
DataValueReferenceFactoryCollection dataValueReferenceFactories,
IDataTypeService dataTypeService,
IDataTypeConfigurationCache dataTypeConfigurationCache,
ILocalizedTextService textService,
ILogger<BlockEditorPropertyValueEditor<TValue, TLayout>> logger,
IShortStringHelper shortStringHelper,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper)
: base(attribute, propertyEditors, dataTypeService, textService, logger, shortStringHelper, jsonSerializer, ioHelper, dataValueReferenceFactories)
: base(attribute, propertyEditors, dataTypeConfigurationCache, textService, logger, shortStringHelper, jsonSerializer, ioHelper, dataValueReferenceFactories)
{
_propertyEditors = propertyEditors;
_dataValueReferenceFactories = dataValueReferenceFactories;
_dataTypeService = dataTypeService;
_dataTypeConfigurationCache = dataTypeConfigurationCache;
_jsonSerializer = jsonSerializer;
}
@@ -76,7 +77,7 @@ internal abstract class BlockEditorPropertyValueEditor<TValue, TLayout> : BlockV
continue;
}
object? configuration = _dataTypeService.GetDataType(propertyValue.PropertyType.DataTypeKey)?.ConfigurationObject;
object? configuration = _dataTypeConfigurationCache.GetConfiguration(propertyValue.PropertyType.DataTypeKey);
foreach (ITag tag in dataValueTags.GetTags(propertyValue.Value, configuration, languageId))
{
yield return tag;

View File

@@ -4,6 +4,7 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
@@ -51,7 +52,7 @@ public abstract class BlockGridPropertyEditorBase : DataEditor
DataEditorAttribute attribute,
PropertyEditorCollection propertyEditors,
DataValueReferenceFactoryCollection dataValueReferenceFactories,
IDataTypeService dataTypeService,
IDataTypeConfigurationCache dataTypeConfigurationCache,
ILocalizedTextService textService,
ILogger<BlockGridEditorPropertyValueEditor> logger,
IShortStringHelper shortStringHelper,
@@ -59,7 +60,7 @@ public abstract class BlockGridPropertyEditorBase : DataEditor
IIOHelper ioHelper,
IContentTypeService contentTypeService,
IPropertyValidationService propertyValidationService)
: base(attribute, propertyEditors, dataValueReferenceFactories, dataTypeService, textService, logger, shortStringHelper, jsonSerializer, ioHelper)
: base(attribute, propertyEditors, dataValueReferenceFactories, dataTypeConfigurationCache, textService, logger, shortStringHelper, jsonSerializer, ioHelper)
{
BlockEditorValues = new BlockEditorValues<BlockGridValue, BlockGridLayoutItem>(new BlockGridEditorDataConverter(jsonSerializer), contentTypeService, logger);
Validators.Add(new BlockEditorValidator<BlockGridValue, BlockGridLayoutItem>(propertyValidationService, BlockEditorValues, contentTypeService));

View File

@@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
@@ -58,7 +59,7 @@ public abstract class BlockListPropertyEditorBase : DataEditor
BlockEditorDataConverter<BlockListValue, BlockListLayoutItem> blockEditorDataConverter,
PropertyEditorCollection propertyEditors,
DataValueReferenceFactoryCollection dataValueReferenceFactories,
IDataTypeService dataTypeService,
IDataTypeConfigurationCache dataTypeConfigurationCache,
IContentTypeService contentTypeService,
ILocalizedTextService textService,
ILogger<BlockListEditorPropertyValueEditor> logger,
@@ -66,7 +67,7 @@ public abstract class BlockListPropertyEditorBase : DataEditor
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
IPropertyValidationService propertyValidationService) :
base(attribute, propertyEditors, dataValueReferenceFactories,dataTypeService, textService, logger, shortStringHelper, jsonSerializer, ioHelper)
base(attribute, propertyEditors, dataValueReferenceFactories, dataTypeConfigurationCache, textService, logger, shortStringHelper, jsonSerializer, ioHelper)
{
BlockEditorValues = new BlockEditorValues<BlockListValue, BlockListLayoutItem>(blockEditorDataConverter, contentTypeService, logger);
Validators.Add(new BlockEditorValidator<BlockListValue, BlockListLayoutItem>(propertyValidationService, BlockEditorValues, contentTypeService));

View File

@@ -1,4 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
@@ -13,7 +14,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
where TValue : BlockValue<TLayout>, new()
where TLayout : class, IBlockLayoutItem, new()
{
private readonly IDataTypeService _dataTypeService;
private readonly IDataTypeConfigurationCache _dataTypeConfigurationCache;
private readonly PropertyEditorCollection _propertyEditors;
private readonly ILogger _logger;
private readonly DataValueReferenceFactoryCollection _dataValueReferenceFactoryCollection;
@@ -21,7 +22,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
protected BlockValuePropertyValueEditorBase(
DataEditorAttribute attribute,
PropertyEditorCollection propertyEditors,
IDataTypeService dataTypeService,
IDataTypeConfigurationCache dataTypeConfigurationCache,
ILocalizedTextService textService,
ILogger logger,
IShortStringHelper shortStringHelper,
@@ -31,7 +32,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
: base(textService, shortStringHelper, jsonSerializer, ioHelper, attribute)
{
_propertyEditors = propertyEditors;
_dataTypeService = dataTypeService;
_dataTypeConfigurationCache = dataTypeConfigurationCache;
_logger = logger;
_dataValueReferenceFactoryCollection = dataValueReferenceFactoryCollection;
}
@@ -78,6 +79,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
protected IEnumerable<ITag> GetBlockValueTags(TValue blockValue, int? languageId)
{
var result = new List<ITag>();
// loop through all content and settings data
foreach (BlockItemData row in blockValue.ContentData.Concat(blockValue.SettingsData))
{
@@ -91,7 +93,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
continue;
}
object? configuration = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeKey)?.ConfigurationObject;
object? configuration = _dataTypeConfigurationCache.GetConfiguration(prop.Value.PropertyType.DataTypeKey);
result.AddRange(tagsProvider.GetTags(prop.Value.Value, configuration, languageId));
}
@@ -114,7 +116,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
private void MapBlockItemDataToEditor(IProperty property, List<BlockItemData> items)
{
var valEditors = new Dictionary<int, IDataValueEditor>();
var valEditors = new Dictionary<Guid, IDataValueEditor>();
foreach (BlockItemData row in items)
{
@@ -136,25 +138,13 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
continue;
}
IDataType? dataType = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId);
if (dataType == null)
Guid dataTypeKey = prop.Value.PropertyType.DataTypeKey;
if (!valEditors.TryGetValue(dataTypeKey, out IDataValueEditor? valEditor))
{
// deal with weird situations by ignoring them (no comment)
row.PropertyValues.Remove(prop.Key);
_logger.LogWarning(
"ToEditor removed property value {PropertyKey} in row {RowId} for property type {PropertyTypeAlias}",
prop.Key,
row.Key,
property.PropertyType.Alias);
continue;
}
var configuration = _dataTypeConfigurationCache.GetConfiguration(dataTypeKey);
valEditor = propEditor.GetValueEditor(configuration);
if (!valEditors.TryGetValue(dataType.Id, out IDataValueEditor? valEditor))
{
var tempConfig = dataType.ConfigurationObject;
valEditor = propEditor.GetValueEditor(tempConfig);
valEditors.Add(dataType.Id, valEditor);
valEditors.Add(dataTypeKey, valEditor);
}
var convValue = valEditor.ToEditor(tempProp);
@@ -172,7 +162,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
foreach (KeyValuePair<string, BlockItemData.BlockPropertyValue> prop in row.PropertyValues)
{
// Fetch the property types prevalue
var propConfiguration = _dataTypeService.GetDataType(prop.Value.PropertyType.DataTypeId)?.ConfigurationObject;
var configuration = _dataTypeConfigurationCache.GetConfiguration(prop.Value.PropertyType.DataTypeKey);
// Lookup the property editor
IDataEditor? propEditor = _propertyEditors[prop.Value.PropertyType.PropertyEditorAlias];
@@ -182,7 +172,7 @@ internal abstract class BlockValuePropertyValueEditorBase<TValue, TLayout> : Dat
}
// Create a fake content property data object
var contentPropData = new ContentPropertyData(prop.Value.Value, propConfiguration);
var contentPropData = new ContentPropertyData(prop.Value.Value, configuration);
// Get the property editor to do it's conversion
var newValue = propEditor.GetValueEditor().FromEditor(contentPropData, prop.Value.Value);

View File

@@ -4,6 +4,7 @@
using System.Text.Json.Nodes;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
@@ -24,7 +25,7 @@ namespace Umbraco.Cms.Core.PropertyEditors;
/// </summary>
internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core vs web?
{
private readonly IDataTypeService _dataTypeService;
private readonly IDataTypeConfigurationCache _dataTypeConfigurationCache;
private readonly IFileStreamSecurityValidator _fileStreamSecurityValidator;
private readonly ILogger<ImageCropperPropertyValueEditor> _logger;
private readonly MediaFileManager _mediaFileManager;
@@ -42,20 +43,20 @@ internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core v
IOptionsMonitor<ContentSettings> contentSettings,
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
IDataTypeService dataTypeService,
ITemporaryFileService temporaryFileService,
IScopeProvider scopeProvider,
IFileStreamSecurityValidator fileStreamSecurityValidator)
IFileStreamSecurityValidator fileStreamSecurityValidator,
IDataTypeConfigurationCache dataTypeConfigurationCache)
: base(localizedTextService, shortStringHelper, jsonSerializer, ioHelper, attribute)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_mediaFileManager = mediaFileSystem ?? throw new ArgumentNullException(nameof(mediaFileSystem));
_jsonSerializer = jsonSerializer;
_contentSettings = contentSettings.CurrentValue;
_dataTypeService = dataTypeService;
_temporaryFileService = temporaryFileService;
_scopeProvider = scopeProvider;
_fileStreamSecurityValidator = fileStreamSecurityValidator;
_dataTypeConfigurationCache = dataTypeConfigurationCache;
contentSettings.OnChange(x => _contentSettings = x);
Validators.Add(new TemporaryFileUploadValidator(() => _contentSettings, TryParseTemporaryFileKey, TryGetTemporaryFile));
@@ -83,10 +84,10 @@ internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core v
value = new ImageCropperValue { Src = val.ToString() };
}
IDataType? dataType = _dataTypeService.GetDataType(property.PropertyType.DataTypeId);
if (dataType?.ConfigurationObject != null)
var configuration = _dataTypeConfigurationCache.GetConfigurationAs<ImageCropperConfiguration>(property.PropertyType.DataTypeKey);
if (configuration is not null)
{
value?.ApplyConfiguration(dataType.ConfigurationAs<ImageCropperConfiguration>());
value?.ApplyConfiguration(configuration);
}
return value;
@@ -213,8 +214,7 @@ internal class ImageCropperPropertyValueEditor : DataValueEditor // TODO: core v
}
// more magic here ;-(
ImageCropperConfiguration? configuration = _dataTypeService.GetDataType(propertyType.DataTypeId)
?.ConfigurationAs<ImageCropperConfiguration>();
ImageCropperConfiguration? configuration = _dataTypeConfigurationCache.GetConfigurationAs<ImageCropperConfiguration>(propertyType.DataTypeKey);
ImageCropperConfiguration.Crop[] crops = configuration?.Crops ?? Array.Empty<ImageCropperConfiguration.Crop>();
return _jsonSerializer.Serialize(new { src = val, crops });

View File

@@ -1,4 +1,5 @@
using System.Text.Json.Nodes;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Editors;
@@ -48,7 +49,7 @@ public class MediaPicker3PropertyEditor : DataEditor
internal class MediaPicker3PropertyValueEditor : DataValueEditor, IDataValueReference
{
private readonly IDataTypeService _dataTypeService;
private readonly IDataTypeConfigurationCache _dataTypeReadCache;
private readonly IJsonSerializer _jsonSerializer;
private readonly IMediaImportService _mediaImportService;
private readonly IMediaService _mediaService;
@@ -61,21 +62,21 @@ public class MediaPicker3PropertyEditor : DataEditor
IJsonSerializer jsonSerializer,
IIOHelper ioHelper,
DataEditorAttribute attribute,
IDataTypeService dataTypeService,
IMediaImportService mediaImportService,
IMediaService mediaService,
ITemporaryFileService temporaryFileService,
IScopeProvider scopeProvider,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor)
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
IDataTypeConfigurationCache dataTypeReadCache)
: base(shortStringHelper, jsonSerializer, ioHelper, attribute)
{
_jsonSerializer = jsonSerializer;
_dataTypeService = dataTypeService;
_mediaImportService = mediaImportService;
_mediaService = mediaService;
_temporaryFileService = temporaryFileService;
_scopeProvider = scopeProvider;
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_dataTypeReadCache = dataTypeReadCache;
}
/// <remarks>
@@ -97,11 +98,9 @@ public class MediaPicker3PropertyEditor : DataEditor
var dtos = Deserialize(_jsonSerializer, value).ToList();
dtos = UpdateMediaTypeAliases(dtos);
IDataType? dataType = _dataTypeService.GetDataType(property.PropertyType.DataTypeId);
if (dataType?.ConfigurationObject != null)
var configuration = _dataTypeReadCache.GetConfigurationAs<MediaPicker3Configuration>(property.PropertyType.DataTypeKey);
if (configuration is not null)
{
MediaPicker3Configuration? configuration = dataType.ConfigurationAs<MediaPicker3Configuration>();
foreach (MediaWithCropsDto dto in dtos)
{
dto.ApplyConfiguration(configuration);

View File

@@ -3,6 +3,8 @@
using System.Diagnostics.CodeAnalysis;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
@@ -73,7 +75,7 @@ public class RichTextPropertyEditor : DataEditor
public RichTextPropertyValueEditor(
DataEditorAttribute attribute,
PropertyEditorCollection propertyEditors,
IDataTypeService dataTypeService,
IDataTypeConfigurationCache dataTypeReadCache,
ILogger<RichTextPropertyValueEditor> logger,
IBackOfficeSecurityAccessor backOfficeSecurityAccessor,
ILocalizedTextService localizedTextService,
@@ -87,7 +89,7 @@ public class RichTextPropertyEditor : DataEditor
IContentTypeService contentTypeService,
IPropertyValidationService propertyValidationService,
DataValueReferenceFactoryCollection dataValueReferenceFactoryCollection)
: base(attribute, propertyEditors, dataTypeService, localizedTextService, logger, shortStringHelper, jsonSerializer, ioHelper, dataValueReferenceFactoryCollection)
: base(attribute, propertyEditors, dataTypeReadCache, localizedTextService, logger, shortStringHelper, jsonSerializer, ioHelper, dataValueReferenceFactoryCollection)
{
_backOfficeSecurityAccessor = backOfficeSecurityAccessor;
_imageSourceParser = imageSourceParser;

View File

@@ -1,6 +1,7 @@
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.IO;
using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Cms.Core.PropertyEditors;
@@ -41,7 +42,7 @@ public class DataValueEditorReuseTests
new BlockListEditorDataConverter(Mock.Of<IJsonSerializer>()),
_propertyEditorCollection,
_dataValueReferenceFactories,
Mock.Of<IDataTypeService>(),
Mock.Of<IDataTypeConfigurationCache>(),
Mock.Of<IContentTypeService>(),
Mock.Of<ILocalizedTextService>(),
Mock.Of<ILogger<BlockListPropertyEditorBase.BlockListEditorPropertyValueEditor>>(),