V15: Remove Nucache (#17166)
* Remove nucache reference from Web.Common * Get tests building-ish * Move ReservedFieldNamesService to the right project * Remove IPublishedSnapshotStatus * Added functionality to the INavigationQueryService to get root keys * Fixed issue with navigation * Remove IPublishedSnapshot from UmbracoContext * Begin removing usage of IPublishedSnapshot from PublishedContentExtensions * Fix PublishedContentExtensions.cs * Don't use snapshots in delivery media api * Use IPublishedMediaCache in QueryMediaApiController * Remove more usages of IPublishedSnapshotAccessor * Comment out tests * Remove more usages of PublishedSnapshotAccessor * Remove PublishedSnapshot from property * Fixed test build * Fix errors * Fix some tests * Delete NuCache 🎉 * Implement DatabaseCacheRebuilder * Remove usage of IPublishedSnapshotService * Remove IPublishedSnapshotService * Remove TestPublishedSnapshotAccessor and make tests build * Don't test Snapshot cachelevel It's no longer supported * Fix BlockEditorConverter Element != Element document type * Remember to set cachemanager * Fix RichTextParserTests * Implement TryGetLevel on INavigationQueryService * Fake level and obsolete it in PublishedContent * Remove ChildrenForAllCultures * Hack Path property on PublishedContent * Remove usages of IPublishedSnapshot in tests * More ConvertersTests * Add hybrid cache to integration tests We can actually do this now because we no longer save files on disk * Rename IPublishedSnapshotRebuilder to ICacheRebuilder * Comment out tests * V15: Replacing the usages of Parent (navigation data) from IPublishedContent (#17125) * Fix .Parent references in PublishedContentExtensions * Add missing methods to FriendlyPublishedContentExtensions (ones that you were able to call on the content directly as they now require extra params) * Fix references from the extension methods * Fix dependencies in tests * Replace IPublishedSnapshotAccessor with the content cache in tests * Resolving more .Parent references * Fix unit tests * Obsolete and use extension methods * Remove private method and use extension instead * Moving code around * Fix tests * Fix more references * Cleanup * Fix more usages * Resolve merge conflict * Fix tests * Cleanup * Fix more tests * Fixed unit tests * Cleanup * Replace last usages --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk> * Remove usage of IPublishedSnapshotAccessor from IRequestItemProvider * Post merge fixup * Remo IPublishedSnapshot * Add HasAny to IDocumentUrlService * Fix TextBuilder * Fix modelsbuilder tests * Use explicit types * Implement GetByContentType * Support element types in PublishedContentTypeCache * Run enlistments before publishing notifications * Fix elements cache refreshing * Implement GetByUdi * Implement GetAtRoot * Implement GetByRoute * Reimplement GetRouteById * Fix blocks unit tests * Initialize domain cache on boot * Only return routes with domains on non default lanauges * V15: Replacing the usages of `Children` (navigation data) from `IPublishedContent` (#17159) * Update params in PublishedContentExtensions to the general interfaces for the published cache and navigation service, so that we can use the extension methods on both documents and media * Introduce GetParent() which uses the right services * Fix obsolete message on .Parent * Obsolete .Children * Fix usages of Children for ApiMediaQueryService * Fix usage in internal * Fix usages in views * Fix indentation * Fix issue with delete language * Update nuget pacakges * Clear elements cache when content is deleted instead of trying to update it * Reset publishedModelFactory * Fixed publishing --------- Co-authored-by: Bjarke Berg <mail@bergmania.dk> Co-authored-by: Elitsa Marinovska <21998037+elit0451@users.noreply.github.com> Co-authored-by: kjac <kja@umbraco.dk>
This commit is contained in:
@@ -0,0 +1,16 @@
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Infrastructure.HybridCache.Persistence;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.HybridCache;
|
||||
|
||||
internal class DatabaseCacheRebuilder : IDatabaseCacheRebuilder
|
||||
{
|
||||
private readonly IDatabaseCacheRepository _databaseCacheRepository;
|
||||
|
||||
public DatabaseCacheRebuilder(IDatabaseCacheRepository databaseCacheRepository)
|
||||
{
|
||||
_databaseCacheRepository = databaseCacheRepository;
|
||||
}
|
||||
|
||||
public void Rebuild() => _databaseCacheRepository.Rebuild();
|
||||
}
|
||||
@@ -44,6 +44,7 @@ public static class UmbracoBuilderExtensions
|
||||
builder.Services.AddSingleton<IPublishedContentFactory, PublishedContentFactory>();
|
||||
builder.Services.AddSingleton<ICacheNodeFactory, CacheNodeFactory>();
|
||||
builder.Services.AddSingleton<ICacheManager, CacheManager>();
|
||||
builder.Services.AddSingleton<IDatabaseCacheRebuilder, DatabaseCacheRebuilder>();
|
||||
builder.Services.AddSingleton<IContentCacheDataSerializerFactory>(s =>
|
||||
{
|
||||
IOptions<NuCacheSettings> options = s.GetRequiredService<IOptions<NuCacheSettings>>();
|
||||
@@ -62,8 +63,9 @@ public static class UmbracoBuilderExtensions
|
||||
builder.AddNotificationAsyncHandler<ContentDeletedNotification, CacheRefreshingNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<MediaRefreshNotification, CacheRefreshingNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<MediaDeletedNotification, CacheRefreshingNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<UmbracoApplicationStartedNotification, SeedingNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<ContentTypeRefreshedNotification, CacheRefreshingNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<ContentTypeDeletedNotification, CacheRefreshingNotificationHandler>();
|
||||
builder.AddNotificationAsyncHandler<UmbracoApplicationStartedNotification, SeedingNotificationHandler>();
|
||||
builder.AddCacheSeeding();
|
||||
return builder;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
using Umbraco.Cms.Core;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Navigation;
|
||||
using Umbraco.Cms.Infrastructure.HybridCache.Services;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.HybridCache;
|
||||
|
||||
@@ -34,31 +39,86 @@ public sealed class DocumentCache : IPublishedContentCache
|
||||
|
||||
public IPublishedContentType? GetContentType(string alias) => _publishedContentTypeCache.Get(PublishedItemType.Content, alias);
|
||||
|
||||
|
||||
public IPublishedContentType? GetContentType(Guid key) => _publishedContentTypeCache.Get(PublishedItemType.Content, key);
|
||||
|
||||
// FIXME: These need to be refactored when removing nucache
|
||||
// Thats the time where we can change the IPublishedContentCache interface.
|
||||
// TODO: These are all obsolete and should be removed
|
||||
|
||||
public IPublishedContent? GetById(bool preview, Udi contentId) => throw new NotImplementedException();
|
||||
[Obsolete("Scheduled for removal in v17")]
|
||||
public IPublishedContent? GetById(bool preview, Udi contentId)
|
||||
{
|
||||
if(contentId is not GuidUdi guidUdi)
|
||||
{
|
||||
throw new NotSupportedException("Only GuidUdi is supported");
|
||||
}
|
||||
|
||||
public IPublishedContent? GetById(Udi contentId) => throw new NotImplementedException();
|
||||
return GetById(preview, guidUdi.Guid);
|
||||
}
|
||||
|
||||
public IEnumerable<IPublishedContent> GetAtRoot(bool preview, string? culture = null) => throw new NotImplementedException();
|
||||
[Obsolete("Scheduled for removal in v17")]
|
||||
public IPublishedContent? GetById(Udi contentId)
|
||||
{
|
||||
if(contentId is not GuidUdi guidUdi)
|
||||
{
|
||||
throw new NotSupportedException("Only GuidUdi is supported");
|
||||
}
|
||||
|
||||
public IEnumerable<IPublishedContent> GetAtRoot(string? culture = null) => throw new NotImplementedException();
|
||||
return GetById(guidUdi.Guid);
|
||||
}
|
||||
|
||||
public bool HasContent(bool preview) => throw new NotImplementedException();
|
||||
[Obsolete("Scheduled for removal, use IDocumentNavigationQueryService instead in v17")]
|
||||
public IEnumerable<IPublishedContent> GetAtRoot(bool preview, string? culture = null)
|
||||
{
|
||||
IDocumentNavigationQueryService navigationService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
|
||||
navigationService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
|
||||
|
||||
public bool HasContent() => throw new NotImplementedException();
|
||||
IEnumerable<IPublishedContent> rootContent = rootKeys.Select(key => GetById(preview, key)).WhereNotNull();
|
||||
return culture is null ? rootContent : rootContent.Where(x => x.IsInvariantOrHasCulture(culture));
|
||||
}
|
||||
|
||||
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType) => throw new NotImplementedException();
|
||||
[Obsolete("Scheduled for removal, use IDocumentNavigationQueryService instead in v17")]
|
||||
public IEnumerable<IPublishedContent> GetAtRoot(string? culture = null)
|
||||
{
|
||||
IDocumentNavigationQueryService navigationService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
|
||||
navigationService.TryGetRootKeys(out IEnumerable<Guid> rootKeys);
|
||||
|
||||
public IPublishedContent? GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string? culture = null) => throw new NotImplementedException();
|
||||
IEnumerable<IPublishedContent> rootContent = rootKeys.Select(key => GetById(key)).WhereNotNull();
|
||||
return culture is null ? rootContent : rootContent.Where(x => x.IsInvariantOrHasCulture(culture));
|
||||
}
|
||||
|
||||
public IPublishedContent? GetByRoute(string route, bool? hideTopLevelNode = null, string? culture = null) => throw new NotImplementedException();
|
||||
[Obsolete("Scheduled for removal in v17")]
|
||||
public bool HasContent(bool preview) => HasContent();
|
||||
|
||||
public string? GetRouteById(bool preview, int contentId, string? culture = null) => throw new NotImplementedException();
|
||||
[Obsolete("Scheduled for removal in v17")]
|
||||
public bool HasContent() => StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>().HasAny();
|
||||
|
||||
public string? GetRouteById(int contentId, string? culture = null) => throw new NotImplementedException();
|
||||
[Obsolete]
|
||||
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType)
|
||||
=> _documentCacheService.GetByContentType(contentType);
|
||||
|
||||
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
|
||||
public IPublishedContent? GetByRoute(bool preview, string route, bool? hideTopLevelNode = null, string? culture = null)
|
||||
{
|
||||
IDocumentUrlService documentUrlService = StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>();
|
||||
Guid? key = documentUrlService.GetDocumentKeyByRoute(route, culture, null, preview);
|
||||
return key is not null ? GetById(preview, key.Value) : null;
|
||||
}
|
||||
|
||||
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
|
||||
public IPublishedContent? GetByRoute(string route, bool? hideTopLevelNode = null, string? culture = null)
|
||||
{
|
||||
IDocumentUrlService documentUrlService = StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>();
|
||||
Guid? key = documentUrlService.GetDocumentKeyByRoute(route, culture, null, false);
|
||||
return key is not null ? GetById(key.Value) : null;
|
||||
}
|
||||
|
||||
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
|
||||
public string? GetRouteById(bool preview, int contentId, string? culture = null)
|
||||
{
|
||||
IDocumentUrlService documentUrlService = StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>();
|
||||
IPublishedContent? content = GetById(preview, contentId);
|
||||
return content is not null ? documentUrlService.GetLegacyRouteFormat(content.Key, culture, preview) : null;
|
||||
}
|
||||
|
||||
[Obsolete("Use IDocumentUrlService.GetDocumentKeyByRoute instead, scheduled for removal in v17")]
|
||||
public string? GetRouteById(int contentId, string? culture = null) => GetRouteById(false, contentId, culture);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using StackExchange.Profiling.Internal;
|
||||
using Umbraco.Cms.Core.Media.EmbedProviders;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Strings;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
@@ -17,7 +19,14 @@ internal class CacheNodeFactory : ICacheNodeFactory
|
||||
|
||||
public ContentCacheNode ToContentCacheNode(IContent content, bool preview)
|
||||
{
|
||||
ContentData contentData = GetContentData(content, !preview, preview ? content.TemplateId : content.PublishTemplateId);
|
||||
|
||||
|
||||
ContentData contentData = GetContentData(
|
||||
content,
|
||||
GetPublishedValue(content, preview),
|
||||
GetTemplateId(content, preview),
|
||||
content.PublishCultureInfos!.Values.Select(x=>x.Culture).ToHashSet()
|
||||
);
|
||||
return new ContentCacheNode
|
||||
{
|
||||
Id = content.Id,
|
||||
@@ -31,9 +40,39 @@ internal class CacheNodeFactory : ICacheNodeFactory
|
||||
};
|
||||
}
|
||||
|
||||
private bool GetPublishedValue(IContent content, bool preview)
|
||||
{
|
||||
switch (content.PublishedState)
|
||||
{
|
||||
case PublishedState.Published:
|
||||
return preview;
|
||||
case PublishedState.Publishing:
|
||||
return preview is false || content.Published; // The type changes after this operation
|
||||
case PublishedState.Unpublished:
|
||||
case PublishedState.Unpublishing:
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private int? GetTemplateId(IContent content, bool preview)
|
||||
{
|
||||
switch (content.PublishedState)
|
||||
{
|
||||
case PublishedState.Published:
|
||||
return preview ? content.TemplateId : content.PublishTemplateId;
|
||||
case PublishedState.Publishing:
|
||||
return content.TemplateId;// The type changes after this operation is we need to read the draft values
|
||||
case PublishedState.Unpublished:
|
||||
case PublishedState.Unpublishing:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ContentCacheNode ToContentCacheNode(IMedia media)
|
||||
{
|
||||
ContentData contentData = GetContentData(media, false, null);
|
||||
ContentData contentData = GetContentData(media, false, null, new HashSet<string>());
|
||||
return new ContentCacheNode
|
||||
{
|
||||
Id = media.Id,
|
||||
@@ -47,7 +86,7 @@ internal class CacheNodeFactory : ICacheNodeFactory
|
||||
};
|
||||
}
|
||||
|
||||
private ContentData GetContentData(IContentBase content, bool published, int? templateId)
|
||||
private ContentData GetContentData(IContentBase content, bool published, int? templateId, ISet<string> publishedCultures)
|
||||
{
|
||||
var propertyData = new Dictionary<string, PropertyData[]>();
|
||||
foreach (IProperty prop in content.Properties)
|
||||
@@ -62,7 +101,15 @@ internal class CacheNodeFactory : ICacheNodeFactory
|
||||
}
|
||||
|
||||
// note: at service level, invariant is 'null', but here invariant becomes 'string.Empty'
|
||||
var value = published ? pvalue.PublishedValue : pvalue.EditedValue;
|
||||
if (published && (string.IsNullOrEmpty(pvalue.Culture) is false && publishedCultures.Contains(pvalue.Culture) is false))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var value = published
|
||||
? pvalue.PublishedValue
|
||||
: pvalue.EditedValue;
|
||||
|
||||
if (value != null)
|
||||
{
|
||||
pdatas.Add(new PropertyData
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Events;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
@@ -17,7 +18,8 @@ internal sealed class CacheRefreshingNotificationHandler :
|
||||
INotificationAsyncHandler<ContentDeletedNotification>,
|
||||
INotificationAsyncHandler<MediaRefreshNotification>,
|
||||
INotificationAsyncHandler<MediaDeletedNotification>,
|
||||
INotificationAsyncHandler<ContentTypeRefreshedNotification>
|
||||
INotificationAsyncHandler<ContentTypeRefreshedNotification>,
|
||||
INotificationAsyncHandler<ContentTypeDeletedNotification>
|
||||
{
|
||||
private readonly IDocumentCacheService _documentCacheService;
|
||||
private readonly IMediaCacheService _mediaCacheService;
|
||||
@@ -50,7 +52,7 @@ internal sealed class CacheRefreshingNotificationHandler :
|
||||
{
|
||||
foreach (IContent deletedEntity in notification.DeletedEntities)
|
||||
{
|
||||
await RefreshElementsCacheAsync(deletedEntity);
|
||||
RemoveFromElementsCache(deletedEntity);
|
||||
await _documentCacheService.DeleteItemAsync(deletedEntity);
|
||||
}
|
||||
}
|
||||
@@ -65,7 +67,7 @@ internal sealed class CacheRefreshingNotificationHandler :
|
||||
{
|
||||
foreach (IMedia deletedEntity in notification.DeletedEntities)
|
||||
{
|
||||
await RefreshElementsCacheAsync(deletedEntity);
|
||||
RemoveFromElementsCache(deletedEntity);
|
||||
await _mediaCacheService.DeleteItemAsync(deletedEntity);
|
||||
}
|
||||
}
|
||||
@@ -76,6 +78,8 @@ internal sealed class CacheRefreshingNotificationHandler :
|
||||
IEnumerable<IRelation> childRelations = _relationService.GetByChild(content);
|
||||
|
||||
var ids = parentRelations.Select(x => x.ChildId).Concat(childRelations.Select(x => x.ParentId)).ToHashSet();
|
||||
// We need to add ourselves to the list of ids to clear
|
||||
ids.Add(content.Id);
|
||||
foreach (var id in ids)
|
||||
{
|
||||
if (await _documentCacheService.HasContentByIdAsync(id) is false)
|
||||
@@ -92,20 +96,33 @@ internal sealed class CacheRefreshingNotificationHandler :
|
||||
foreach (IPublishedProperty publishedProperty in publishedContent.Properties)
|
||||
{
|
||||
var property = (PublishedProperty) publishedProperty;
|
||||
if (property.ReferenceCacheLevel != PropertyCacheLevel.Elements)
|
||||
if (property.ReferenceCacheLevel is PropertyCacheLevel.Elements
|
||||
|| property.PropertyType.DeliveryApiCacheLevel is PropertyCacheLevel.Elements
|
||||
|| property.PropertyType.DeliveryApiCacheLevelForExpansion is PropertyCacheLevel.Elements)
|
||||
{
|
||||
continue;
|
||||
_elementsCache.ClearByKey(property.ValuesCacheKey);
|
||||
}
|
||||
|
||||
_elementsCache.ClearByKey(property.ValuesCacheKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveFromElementsCache(IUmbracoEntity content)
|
||||
{
|
||||
// ClearByKey clears by "startsWith" so we'll clear by the cachekey prefix + contentKey
|
||||
// This will clear any and all properties for this content item, this is important because
|
||||
// we cannot resolve the PublishedContent for this entity since it and its content type is deleted.
|
||||
_elementsCache.ClearByKey(GetContentWideCacheKey(content.Key, true));
|
||||
_elementsCache.ClearByKey(GetContentWideCacheKey(content.Key, false));
|
||||
}
|
||||
|
||||
private string GetContentWideCacheKey(Guid contentKey, bool isPreviewing) => isPreviewing
|
||||
? CacheKeys.PreviewPropertyCacheKeyPrefix + contentKey
|
||||
: CacheKeys.PropertyCacheKeyPrefix + contentKey;
|
||||
|
||||
public Task HandleAsync(ContentTypeRefreshedNotification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
const ContentTypeChangeTypes types // only for those that have been refreshed
|
||||
= ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther | ContentTypeChangeTypes.Remove;
|
||||
= ContentTypeChangeTypes.RefreshMain | ContentTypeChangeTypes.RefreshOther;
|
||||
var contentTypeIds = notification.Changes.Where(x => x.ChangeTypes.HasTypesAny(types)).Select(x => x.Item.Id)
|
||||
.ToArray();
|
||||
|
||||
@@ -121,4 +138,14 @@ internal sealed class CacheRefreshingNotificationHandler :
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task HandleAsync(ContentTypeDeletedNotification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
foreach (IContentType deleted in notification.DeletedEntities)
|
||||
{
|
||||
_publishedContentTypeCache.ClearContentType(deleted.Id);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Exceptions;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.PublishedContent;
|
||||
using Umbraco.Cms.Core.Services;
|
||||
using Umbraco.Cms.Core.Services.Navigation;
|
||||
using Umbraco.Cms.Core.PublishedCache;
|
||||
using Umbraco.Extensions;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.HybridCache;
|
||||
@@ -77,8 +79,8 @@ internal class PublishedContent : PublishedContentBase
|
||||
{
|
||||
get
|
||||
{
|
||||
var documentNavigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
|
||||
var idKeyMap = StaticServiceProvider.Instance.GetRequiredService<IIdKeyMap>();
|
||||
IDocumentNavigationQueryService documentNavigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
|
||||
IIdKeyMap idKeyMap = StaticServiceProvider.Instance.GetRequiredService<IIdKeyMap>();
|
||||
|
||||
|
||||
if (documentNavigationQueryService.TryGetAncestorsOrSelfKeys(Key, out var ancestorsOrSelfKeys))
|
||||
@@ -86,7 +88,7 @@ internal class PublishedContent : PublishedContentBase
|
||||
var sb = new StringBuilder("-1");
|
||||
foreach (Guid ancestorsOrSelfKey in ancestorsOrSelfKeys.Reverse())
|
||||
{
|
||||
var idAttempt = idKeyMap.GetIdForKey(ancestorsOrSelfKey, GetObjectType());
|
||||
Attempt<int> idAttempt = idKeyMap.GetIdForKey(ancestorsOrSelfKey, GetObjectType());
|
||||
if (idAttempt.Success)
|
||||
{
|
||||
sb.AppendFormat(",{0}", idAttempt.Result);
|
||||
@@ -130,12 +132,31 @@ internal class PublishedContent : PublishedContentBase
|
||||
// Needed for publishedProperty
|
||||
internal IVariationContextAccessor VariationContextAccessor { get; }
|
||||
|
||||
public override int Level { get; } = 0;
|
||||
[Obsolete("Use the INavigationQueryService instead, scheduled for removal in v17")]
|
||||
public override int Level
|
||||
{
|
||||
get
|
||||
{
|
||||
INavigationQueryService? navigationQueryService = null;
|
||||
switch (_contentNode.ContentType.ItemType)
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IMediaNavigationQueryService>();
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("Level is not implemented for " + _contentNode.ContentType.ItemType);
|
||||
}
|
||||
|
||||
public override IEnumerable<IPublishedContent> ChildrenForAllCultures { get; } = Enumerable.Empty<IPublishedContent>();
|
||||
|
||||
public override IPublishedContent? Parent { get; } = null!;
|
||||
navigationQueryService.TryGetLevel(Key, out int level);
|
||||
return level;
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete("Please use TryGetParentKey() on IDocumentNavigationQueryService or IMediaNavigationQueryService instead. Scheduled for removal in V16.")]
|
||||
public override IPublishedContent? Parent => GetParent();
|
||||
|
||||
/// <inheritdoc />
|
||||
public override IReadOnlyDictionary<string, PublishedCultureInfo> Cultures
|
||||
@@ -238,4 +259,26 @@ internal class PublishedContent : PublishedContentBase
|
||||
// = depends on the culture
|
||||
return _contentNode.HasPublishedCulture(culture);
|
||||
}
|
||||
|
||||
private IPublishedContent? GetParent()
|
||||
{
|
||||
INavigationQueryService? navigationQueryService;
|
||||
IPublishedCache? publishedCache;
|
||||
|
||||
switch (ContentType.ItemType)
|
||||
{
|
||||
case PublishedItemType.Content:
|
||||
publishedCache = StaticServiceProvider.Instance.GetRequiredService<IPublishedContentCache>();
|
||||
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>();
|
||||
break;
|
||||
case PublishedItemType.Media:
|
||||
publishedCache = StaticServiceProvider.Instance.GetRequiredService<IPublishedMediaCache>();
|
||||
navigationQueryService = StaticServiceProvider.Instance.GetRequiredService<IMediaNavigationQueryService>();
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException("Level is not implemented for " + ContentType.ItemType);
|
||||
}
|
||||
|
||||
return this.Parent<IPublishedContent>(publishedCache, navigationQueryService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -80,10 +80,10 @@ internal class PublishedProperty : PublishedPropertyBase
|
||||
{
|
||||
if (previewing)
|
||||
{
|
||||
return "Cache.Property.CacheValues[D:" + contentUid + ":" + typeAlias + "]";
|
||||
return CacheKeys.PreviewPropertyCacheKeyPrefix + contentUid + ":" + typeAlias + "]";
|
||||
}
|
||||
|
||||
return "Cache.Property.CacheValues[P:" + contentUid + ":" + typeAlias + "]";
|
||||
return CacheKeys.PropertyCacheKeyPrefix + contentUid + ":" + typeAlias + "]";
|
||||
}
|
||||
|
||||
// determines whether a property has value
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Extensions.Caching.Hybrid;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Caching.Hybrid;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -96,6 +94,17 @@ internal sealed class DocumentCacheService : IDocumentCacheService
|
||||
return contentCacheNode is null ? null : _publishedContentFactory.ToIPublishedContent(contentCacheNode, preview).CreateModel(_publishedModelFactory);;
|
||||
}
|
||||
|
||||
public IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope();
|
||||
IEnumerable<ContentCacheNode> nodes = _databaseCacheRepository.GetContentByContentTypeKey([contentType.Key]);
|
||||
scope.Complete();
|
||||
|
||||
return nodes
|
||||
.Select(x => _publishedContentFactory.ToIPublishedContent(x, x.IsDraft).CreateModel(_publishedModelFactory))
|
||||
.WhereNotNull();
|
||||
}
|
||||
|
||||
public async Task SeedAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
using ICoreScope scope = _scopeProvider.CreateCoreScope();
|
||||
|
||||
@@ -17,6 +17,7 @@ public class DomainCacheService : IDomainCacheService
|
||||
private readonly IDomainService _domainService;
|
||||
private readonly ICoreScopeProvider _coreScopeProvider;
|
||||
private readonly ConcurrentDictionary<int, Domain> _domains;
|
||||
private bool _initialized = false;
|
||||
|
||||
public DomainCacheService(IDomainService domainService, ICoreScopeProvider coreScopeProvider)
|
||||
{
|
||||
@@ -27,14 +28,26 @@ public class DomainCacheService : IDomainCacheService
|
||||
|
||||
public IEnumerable<Domain> GetAll(bool includeWildcards)
|
||||
{
|
||||
InitializeIfMissing();
|
||||
return includeWildcards == false
|
||||
? _domains.Select(x => x.Value).Where(x => x.IsWildcard == false).OrderBy(x => x.SortOrder)
|
||||
: _domains.Select(x => x.Value).OrderBy(x => x.SortOrder);
|
||||
}
|
||||
|
||||
private void InitializeIfMissing()
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_initialized = true;
|
||||
LoadDomains();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IEnumerable<Domain> GetAssigned(int documentId, bool includeWildcards = false)
|
||||
{
|
||||
InitializeIfMissing();
|
||||
// probably this could be optimized with an index
|
||||
// but then we'd need a custom DomainStore of some sort
|
||||
IEnumerable<Domain> list = _domains.Values.Where(x => x.ContentId == documentId);
|
||||
@@ -48,7 +61,10 @@ public class DomainCacheService : IDomainCacheService
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool HasAssigned(int documentId, bool includeWildcards = false)
|
||||
=> documentId > 0 && GetAssigned(documentId, includeWildcards).Any();
|
||||
{
|
||||
InitializeIfMissing();
|
||||
return documentId > 0 && GetAssigned(documentId, includeWildcards).Any();
|
||||
}
|
||||
|
||||
public void Refresh(DomainCacheRefresher.JsonPayload[] payloads)
|
||||
{
|
||||
@@ -100,12 +116,19 @@ public class DomainCacheService : IDomainCacheService
|
||||
|
||||
private void LoadDomains()
|
||||
{
|
||||
IEnumerable<IDomain> domains = _domainService.GetAll(true);
|
||||
foreach (Domain domain in domains
|
||||
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
|
||||
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId!.Value, x.LanguageIsoCode!, x.IsWildcard, x.SortOrder)))
|
||||
using (ICoreScope scope = _coreScopeProvider.CreateCoreScope())
|
||||
{
|
||||
_domains.AddOrUpdate(domain.Id, domain, (key, oldValue) => domain);
|
||||
scope.ReadLock(Constants.Locks.Domains);
|
||||
IEnumerable<IDomain> domains = _domainService.GetAll(true);
|
||||
foreach (Domain domain in domains
|
||||
.Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false)
|
||||
.Select(x => new Domain(x.Id, x.DomainName, x.RootContentId!.Value, x.LanguageIsoCode!, x.IsWildcard, x.SortOrder)))
|
||||
{
|
||||
_domains.AddOrUpdate(domain.Id, domain, (key, oldValue) => domain);
|
||||
}
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,4 +18,6 @@ public interface IDocumentCacheService
|
||||
Task DeleteItemAsync(IContentBase content);
|
||||
|
||||
void Rebuild(IReadOnlyCollection<int> contentTypeKeys);
|
||||
|
||||
internal IEnumerable<IPublishedContent> GetByContentType(IPublishedContentType contentType);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,12 @@
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Umbraco.Tests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Umbraco.Tests.Common</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Umbraco.Tests.UnitTests</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
|
||||
<_Parameter1>Umbraco.Tests.Integration</_Parameter1>
|
||||
</AssemblyAttribute>
|
||||
|
||||
Reference in New Issue
Block a user