V15: Refresh IPublishedContentTypeFactory when data types change (#17180)

* Refresh IPublishedContentTypeFactory when data types change

* Add tests
This commit is contained in:
Mole
2024-10-07 11:11:22 +02:00
committed by GitHub
parent aa6bf5606c
commit 2b12eadd3d
6 changed files with 116 additions and 9 deletions

View File

@@ -14,6 +14,7 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase<Conten
{
private readonly IContentTypeCommonRepository _contentTypeCommonRepository;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
private readonly IIdKeyMap _idKeyMap;
public ContentTypeCacheRefresher(
@@ -23,12 +24,14 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase<Conten
IContentTypeCommonRepository contentTypeCommonRepository,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IPublishedModelFactory publishedModelFactory)
IPublishedModelFactory publishedModelFactory,
IPublishedContentTypeFactory publishedContentTypeFactory)
: base(appCaches, serializer, eventAggregator, factory)
{
_idKeyMap = idKeyMap;
_contentTypeCommonRepository = contentTypeCommonRepository;
_publishedModelFactory = publishedModelFactory;
_publishedContentTypeFactory = publishedContentTypeFactory;
}
#region Json
@@ -114,6 +117,8 @@ public sealed class ContentTypeCacheRefresher : PayloadCacheRefresherBase<Conten
// TODO: We need to clear the HybridCache of any content using the ContentType, but NOT the database cache here, and this should be done within the "WithSafeLiveFactoryReset" to ensure that the factory is locked in the meantime.
_publishedModelFactory.WithSafeLiveFactoryReset(() => { });
_publishedContentTypeFactory.NotifyDataTypeChanges();
// now we can trigger the event
base.Refresh(payloads);
}

View File

@@ -13,6 +13,7 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
{
private readonly IIdKeyMap _idKeyMap;
private readonly IPublishedModelFactory _publishedModelFactory;
private readonly IPublishedContentTypeFactory _publishedContentTypeFactory;
public DataTypeCacheRefresher(
AppCaches appCaches,
@@ -20,11 +21,13 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
IIdKeyMap idKeyMap,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IPublishedModelFactory publishedModelFactory)
IPublishedModelFactory publishedModelFactory,
IPublishedContentTypeFactory publishedContentTypeFactory)
: base(appCaches, serializer, eventAggregator, factory)
{
_idKeyMap = idKeyMap;
_publishedModelFactory = publishedModelFactory;
_publishedContentTypeFactory = publishedContentTypeFactory;
}
#region Json
@@ -86,6 +89,9 @@ public sealed class DataTypeCacheRefresher : PayloadCacheRefresherBase<DataTypeC
// TODO: We need to clear the HybridCache of any content using the ContentType, but NOT the database cache here, and this should be done within the "WithSafeLiveFactoryReset" to ensure that the factory is locked in the meantime.
_publishedModelFactory.WithSafeLiveFactoryReset(() => { });
var changedIds = payloads.Select(x => x.Id).ToArray();
_publishedContentTypeFactory.NotifyDataTypeChanges(changedIds);
base.Refresh(payloads);
}

View File

@@ -4,16 +4,16 @@ using Umbraco.Extensions;
namespace Umbraco.Cms.Tests.Common.TestHelpers;
public class ContentTypeUpdateHelper
public static class ContentTypeUpdateHelper
{
public ContentTypeUpdateModel CreateContentTypeUpdateModel(IContentType contentType)
public static ContentTypeUpdateModel CreateContentTypeUpdateModel(IContentType contentType)
{
var updateModel = new ContentTypeUpdateModel();
var model = MapBaseProperties<ContentTypeUpdateModel>(contentType, updateModel);
return model;
}
private T MapBaseProperties<T>(IContentType contentType, T model) where T : ContentTypeModelBase
private static T MapBaseProperties<T>(IContentType contentType, T model) where T : ContentTypeModelBase
{
model.Alias = contentType.Alias;
model.Name = contentType.Name;

View File

@@ -67,8 +67,7 @@ public abstract class UmbracoIntegrationTestWithContentEditing : UmbracoIntegrat
Assert.IsTrue(contentTypeAttempt.Success);
var contentTypeResult = contentTypeAttempt.Result;
ContentTypeUpdateHelper contentTypeUpdateHelper = new ContentTypeUpdateHelper();
ContentTypeUpdateModel = contentTypeUpdateHelper.CreateContentTypeUpdateModel(contentTypeResult); ContentTypeUpdateModel.AllowedContentTypes = new[]
ContentTypeUpdateModel = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(contentTypeResult); ContentTypeUpdateModel.AllowedContentTypes = new[]
{
new ContentTypeSort(contentTypeResult.Key, 0, ContentTypeCreateModel.Alias),
};

View File

@@ -37,8 +37,7 @@ public class PublishedContentTypeCacheTests : UmbracoIntegrationTestWithContentE
Assert.IsNotNull(contentType);
Assert.AreEqual(1, ContentType.PropertyTypes.Count());
// Update the content type
ContentTypeUpdateHelper contentTypeUpdateHelper = new ContentTypeUpdateHelper();
var updateModel = contentTypeUpdateHelper.CreateContentTypeUpdateModel(ContentType);
var updateModel = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(ContentType);
updateModel.Properties = new List<ContentTypePropertyTypeModel>();
await ContentTypeEditingService.UpdateAsync(ContentType, updateModel, Constants.Security.SuperUserKey);

View File

@@ -0,0 +1,98 @@
using NUnit.Framework;
using Umbraco.Cms.Core;
using Umbraco.Cms.Core.Cache;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.ContentTypeEditing;
using Umbraco.Cms.Core.Sync;
using Umbraco.Cms.Tests.Common.Builders;
using Umbraco.Cms.Tests.Common.Builders.Extensions;
using Umbraco.Cms.Tests.Common.TestHelpers;
using Umbraco.Cms.Tests.Common.Testing;
using Umbraco.Cms.Tests.Integration.Testing;
using Umbraco.Cms.Tests.Integration.Umbraco.Infrastructure.Services;
namespace Umbraco.Cms.Tests.Integration.Umbraco.Core.PublishedContent;
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)]
public class PublishContentTypeFactoryTest : UmbracoIntegrationTest
{
protected override void CustomTestSetup(IUmbracoBuilder builder)
{
builder.AddNotificationHandler<ContentTypeChangedNotification, ContentTypeChangedDistributedCacheNotificationHandler>();
builder.AddNotificationHandler<DataTypeSavedNotification, DataTypeSavedDistributedCacheNotificationHandler>();
builder.Services.AddUnique<IServerMessenger, ContentEventsTests.LocalServerMessenger>();
base.CustomTestSetup(builder);
}
private ITemplateService TemplateService => GetRequiredService<ITemplateService>();
private IContentTypeEditingService ContentTypeEditingService => GetRequiredService<IContentTypeEditingService>();
private IDataTypeService DataTypeService => GetRequiredService<IDataTypeService>();
private IPublishedContentTypeFactory PublishedContentTypeFactory => GetRequiredService<IPublishedContentTypeFactory>();
[Test]
public async Task Can_Update_Content_Type()
{
// Create a content type
var template = TemplateBuilder.CreateTextPageTemplate("defaultTemplate");
await TemplateService.CreateAsync(template, Constants.Security.SuperUserKey);
var contentTypeCreateModel = ContentTypeEditingBuilder.CreateSimpleContentType("umbTextpage", "Textpage", defaultTemplateKey: template.Key);
var contentTypeAttempt = await ContentTypeEditingService.CreateAsync(contentTypeCreateModel, Constants.Security.SuperUserKey);
Assert.IsTrue(contentTypeAttempt.Success);
Assert.IsNotNull(contentTypeAttempt.Result);
// Fetch the content type to cache data types
var contentType = contentTypeAttempt.Result;
PublishedContentTypeFactory.CreateContentType(contentType);
var dataType = new DataTypeBuilder()
.WithId(0)
.Build();
var dataTypeCreateResult = await DataTypeService.CreateAsync(dataType, Constants.Security.SuperUserKey);
Assert.IsTrue(dataTypeCreateResult.Success);
contentType.AddPropertyGroup("group", "Group");
var propertyTypeAlias = "test";
var propertyType = new PropertyTypeBuilder()
.WithAlias(propertyTypeAlias)
.WithDataTypeId(dataTypeCreateResult.Result.Id)
.Build();
propertyType.DataTypeKey = dataType.Key;
contentType.AddPropertyType(propertyType, "group", "Group");
// Update the content type
var contentTypeUpdate = ContentTypeUpdateHelper.CreateContentTypeUpdateModel(contentType);
var updateResult = await ContentTypeEditingService.UpdateAsync(contentType, contentTypeUpdate, Constants.Security.SuperUserKey);
Assert.IsTrue(updateResult.Success);
var publishedContentType = PublishedContentTypeFactory.CreateContentType(updateResult.Result);
Assert.That(publishedContentType.PropertyTypes.Where(x => x.Alias == propertyTypeAlias), Is.Not.Empty);
}
[Test]
public async Task Can_Get_Updated_Datatype()
{
var dataType = new DataTypeBuilder()
.WithId(0)
.Build();
dataType.EditorUiAlias = "NotUpdated";
var dataTypeCreateResult = await DataTypeService.CreateAsync(dataType, Constants.Security.SuperUserKey);
Assert.IsTrue(dataTypeCreateResult.Success);
var createdDataType = dataTypeCreateResult.Result;
PublishedDataType createdPublishedDataType = PublishedContentTypeFactory.GetDataType(createdDataType.Id);
Assert.That(createdPublishedDataType.EditorUiAlias, Is.EqualTo("NotUpdated"));
createdDataType.EditorUiAlias = "Updated";
var dataTypeUpdateResult = await DataTypeService.UpdateAsync(createdDataType, Constants.Security.SuperUserKey);
Assert.IsTrue(dataTypeUpdateResult.Success);
var updatedPublishedDataType = PublishedContentTypeFactory.GetDataType(createdDataType.Id);
Assert.That(updatedPublishedDataType.EditorUiAlias, Is.EqualTo("Updated"));
}
}