Files
Umbraco-CMS/src/Umbraco.Infrastructure/PropertyEditors/BlockEditorValidatorBase.cs
Matt Brailsford b14ac811ef Make block editor base classes public (#16774)
* Make block editor base classes public

* Update BlockEditorValues.cs

Change to trigger a new build for #16774

---------

Co-authored-by: Kenn Jacobsen <kja@umbraco.dk>
2024-07-26 08:16:08 +02:00

66 lines
3.1 KiB
C#

using Umbraco.Cms.Core.Cache.PropertyEditors;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.Blocks;
using Umbraco.Cms.Core.Services;
using Umbraco.Extensions;
namespace Umbraco.Cms.Core.PropertyEditors;
public abstract class BlockEditorValidatorBase<TValue, TLayout> : ComplexEditorValidator
where TValue : BlockValue<TLayout>, new()
where TLayout : class, IBlockLayoutItem, new()
{
private readonly IBlockEditorElementTypeCache _elementTypeCache;
protected BlockEditorValidatorBase(IPropertyValidationService propertyValidationService, IBlockEditorElementTypeCache elementTypeCache)
: base(propertyValidationService)
=> _elementTypeCache = elementTypeCache;
protected IEnumerable<ElementTypeValidationModel> GetBlockEditorDataValidation(BlockEditorData<TValue, TLayout> blockEditorData)
{
// There is no guarantee that the client will post data for every property defined in the Element Type but we still
// need to validate that data for each property especially for things like 'required' data to work.
// Lookup all element types for all content/settings and then we can populate any empty properties.
var itemDataGroups = new[]
{
new { Path = nameof(BlockValue<TLayout>.ContentData).ToFirstLowerInvariant(), Items = blockEditorData.BlockValue.ContentData },
new { Path = nameof(BlockValue<TLayout>.SettingsData).ToFirstLowerInvariant(), Items = blockEditorData.BlockValue.SettingsData }
};
foreach (var group in itemDataGroups)
{
var allElementTypes = _elementTypeCache.GetAll(group.Items.Select(x => x.ContentTypeKey).ToArray()).ToDictionary(x => x.Key);
for (var i = 0; i < group.Items.Count; i++)
{
BlockItemData item = group.Items[i];
if (!allElementTypes.TryGetValue(item.ContentTypeKey, out IContentType? elementType))
{
throw new InvalidOperationException($"No element type found with key {item.ContentTypeKey}");
}
// now ensure missing properties
foreach (IPropertyType elementTypeProp in elementType.CompositionPropertyTypes)
{
if (!item.PropertyValues.ContainsKey(elementTypeProp.Alias))
{
// set values to null
item.PropertyValues[elementTypeProp.Alias] = new BlockItemData.BlockPropertyValue(null, elementTypeProp);
item.RawPropertyValues[elementTypeProp.Alias] = null;
}
}
var elementValidation = new ElementTypeValidationModel(item.ContentTypeAlias, item.Key);
foreach (KeyValuePair<string, BlockItemData.BlockPropertyValue> prop in item.PropertyValues)
{
elementValidation.AddPropertyTypeValidation(
new PropertyTypeValidationModel(prop.Value.PropertyType, prop.Value.Value, $"{group.Path}[{i}].{prop.Value.PropertyType.Alias}"));
}
yield return elementValidation;
}
}
}
}