Skip to content

Commit

Permalink
Temp commit, move to cache refreshers.
Browse files Browse the repository at this point in the history
  • Loading branch information
bergmania committed Sep 10, 2024
1 parent c85853b commit 87e9797
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 41 deletions.
36 changes: 35 additions & 1 deletion src/Umbraco.Cms.Api.Management/Factories/DocumentUrlFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Umbraco.Cms.Api.Management.ViewModels.Content;
using Umbraco.Cms.Api.Management.ViewModels.Document;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.PublishedContent;
using Umbraco.Cms.Core.Routing;
Expand All @@ -21,7 +23,9 @@ public class DocumentUrlFactory : IDocumentUrlFactory
private readonly ILoggerFactory _loggerFactory;
private readonly UriUtility _uriUtility;
private readonly IPublishedUrlProvider _publishedUrlProvider;
private readonly IDocumentUrlService _documentUrlService;

[Obsolete("Use the non-obsolete constructor. This will be removed in Umbraco 16")]
public DocumentUrlFactory(
IPublishedRouter publishedRouter,
IUmbracoContextAccessor umbracoContextAccessor,
Expand All @@ -32,6 +36,33 @@ public DocumentUrlFactory(
ILoggerFactory loggerFactory,
UriUtility uriUtility,
IPublishedUrlProvider publishedUrlProvider)
:this(
publishedRouter,
umbracoContextAccessor,
languageService,
localizedTextService,
contentService,
variationContextAccessor,
loggerFactory,
uriUtility,
publishedUrlProvider,
StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>())
{

}


public DocumentUrlFactory(
IPublishedRouter publishedRouter,
IUmbracoContextAccessor umbracoContextAccessor,
ILanguageService languageService,
ILocalizedTextService localizedTextService,
IContentService contentService,
IVariationContextAccessor variationContextAccessor,
ILoggerFactory loggerFactory,
UriUtility uriUtility,
IPublishedUrlProvider publishedUrlProvider,
IDocumentUrlService documentUrlService)
{
_publishedRouter = publishedRouter;
_umbracoContextAccessor = umbracoContextAccessor;
Expand All @@ -42,12 +73,15 @@ public DocumentUrlFactory(
_loggerFactory = loggerFactory;
_uriUtility = uriUtility;
_publishedUrlProvider = publishedUrlProvider;
_documentUrlService = documentUrlService;

Check notice on line 76 in src/Umbraco.Cms.Api.Management/Factories/DocumentUrlFactory.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

ℹ New issue: Constructor Over-Injection

DocumentUrlFactory has 10 arguments, threshold = 5. This constructor has too many arguments, indicating an object with low cohesion or missing function argument abstraction. Avoid adding more arguments.
}

public async Task<IEnumerable<DocumentUrlInfo>> CreateUrlsAsync(IContent content)
{
IUmbracoContext umbracoContext = _umbracoContextAccessor.GetRequiredUmbracoContext();

// var urls = await _documentUrlService.ListUrlsAsync(content.Key);

//TODO replace with documentUrlService
IEnumerable<UrlInfo> urlInfos = await content.GetContentUrlsAsync(
_publishedRouter,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
using Microsoft.Extensions.DependencyInjection;
using Umbraco.Cms.Core.DependencyInjection;
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
Expand All @@ -14,9 +16,11 @@ public sealed class ContentCacheRefresher : PayloadCacheRefresherBase<ContentCac
ContentCacheRefresher.JsonPayload>
{
private readonly IDomainService _domainService;
private readonly IDocumentUrlService _documentUrlService;
private readonly IIdKeyMap _idKeyMap;
private readonly IPublishedSnapshotService _publishedSnapshotService;

[Obsolete("Use non-obsolete constructor. This will be removed in Umbraco 16")]
public ContentCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
Expand All @@ -25,11 +29,34 @@ public ContentCacheRefresher(
IDomainService domainService,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory)
: this(
appCaches,
serializer,
publishedSnapshotService,
idKeyMap,
domainService,
eventAggregator,
factory,
StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>())
{

}

public ContentCacheRefresher(
AppCaches appCaches,
IJsonSerializer serializer,
IPublishedSnapshotService publishedSnapshotService,
IIdKeyMap idKeyMap,
IDomainService domainService,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IDocumentUrlService documentUrlService)
: base(appCaches, serializer, eventAggregator, factory)
{
_publishedSnapshotService = publishedSnapshotService;
_idKeyMap = idKeyMap;
_domainService = domainService;
_documentUrlService = documentUrlService;

Check notice on line 59 in src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

ℹ New issue: Constructor Over-Injection

ContentCacheRefresher has 8 arguments, threshold = 5. This constructor has too many arguments, indicating an object with low cohesion or missing function argument abstraction. Avoid adding more arguments.
}

#region Indirect
Expand Down Expand Up @@ -75,6 +102,7 @@ public override void Refresh(JsonPayload[] payloads)
// By GUID Key
isolatedCache.Clear(RepositoryCacheKeys.GetKey<IContent, Guid?>(payload.Key));


_idKeyMap.ClearCache(payload.Id);

// remove those that are in the branch
Expand All @@ -89,6 +117,10 @@ public override void Refresh(JsonPayload[] payloads)
{
idsRemoved.Add(payload.Id);
}


HandleRouting(payload);

}

if (idsRemoved.Count > 0)
Expand Down Expand Up @@ -129,6 +161,35 @@ public override void Refresh(JsonPayload[] payloads)
base.Refresh(payloads);
}

private void HandleRouting(JsonPayload payload)
{
//TODO test at denne methode bliver kaldt ved save også.

if(payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
{
var key = payload.Key ?? _idKeyMap.GetKeyForId(payload.Id, UmbracoObjectTypes.Document).Result;
_documentUrlService.DeleteUrlsAndDescendantsAsync(key).GetAwaiter().GetResult();
}
if(payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
//TODO Force rebuilt instead
_documentUrlService.RebuildAllUrlsAsync().GetAwaiter().GetResult(); //TODO make async
}

if(payload.ChangeTypes.HasType(TreeChangeTypes.RefreshNode))
{
var key = payload.Key ?? _idKeyMap.GetKeyForId(payload.Id, UmbracoObjectTypes.Document).Result;
_documentUrlService.CreateOrUpdateUrlSegmentsAsync(key).GetAwaiter().GetResult();
}

if(payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
var key = payload.Key ?? _idKeyMap.GetKeyForId(payload.Id, UmbracoObjectTypes.Document).Result;
_documentUrlService.CreateOrUpdateUrlSegmentsWithDescendantsAsync(key).GetAwaiter().GetResult();
}

}

// these events should never trigger
// everything should be PAYLOAD/JSON
public override void RefreshAll() => throw new NotSupportedException();
Expand Down
61 changes: 31 additions & 30 deletions src/Umbraco.Core/Handlers/RoutingNotificationHandler.cs
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
using Umbraco.Cms.Core.Events;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Notifications;
using Umbraco.Cms.Core.Services;

namespace Umbraco.Cms.Core.Handlers;

public class RoutingNotificationHandler
: INotificationAsyncHandler<ContentPublishedNotification>,
INotificationAsyncHandler<ContentDeletedNotification>,
INotificationAsyncHandler<ContentUnpublishedNotification>,
INotificationAsyncHandler<ContentSavedNotification>
{
private readonly IDocumentUrlService _documentUrlService;
private readonly IContentService _contentService;
private readonly IIdKeyMap _idKeyMap;

public RoutingNotificationHandler(IDocumentUrlService documentUrlService, IContentService contentService, IIdKeyMap idKeyMap)
{
_documentUrlService = documentUrlService;
_contentService = contentService;
_idKeyMap = idKeyMap;
}

public async Task HandleAsync(ContentPublishedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.CreateOrUpdateUrlSegmentsAsync(notification.PublishedEntities);
public async Task HandleAsync(ContentDeletedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.DeleteUrlsAsync(notification.DeletedEntities);
public async Task HandleAsync(ContentUnpublishedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.DeleteUrlsAsync(notification.UnpublishedEntities);

public async Task HandleAsync(ContentSavedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.CreateOrUpdateUrlSegmentsAsync(notification.SavedEntities);
}
// using Umbraco.Cms.Core.Events;
// using Umbraco.Cms.Core.Models;
// using Umbraco.Cms.Core.Notifications;
// using Umbraco.Cms.Core.Services;
//
// namespace Umbraco.Cms.Core.Handlers;
//
// public class RoutingNotificationHandler
// : INotificationAsyncHandler<ContentPublishedNotification>,
// INotificationAsyncHandler<ContentDeletedNotification>,
// INotificationAsyncHandler<ContentUnpublishedNotification>,
// INotificationAsyncHandler<ContentSavedNotification>
// {
// private readonly IDocumentUrlService _documentUrlService;
// private readonly IContentService _contentService;
// private readonly IIdKeyMap _idKeyMap;
//
// public RoutingNotificationHandler(IDocumentUrlService documentUrlService, IContentService contentService, IIdKeyMap idKeyMap)
// {
// _documentUrlService = documentUrlService;
// _contentService = contentService;
// _idKeyMap = idKeyMap;
// }
//
// // TODO move to content refreshers
// public async Task HandleAsync(ContentPublishedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.CreateOrUpdateUrlSegmentsAsync(notification.PublishedEntities);
// public async Task HandleAsync(ContentDeletedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.DeleteUrlsAsync(notification.DeletedEntities);
// public async Task HandleAsync(ContentUnpublishedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.DeleteUrlsAsync(notification.UnpublishedEntities);
//
// public async Task HandleAsync(ContentSavedNotification notification, CancellationToken cancellationToken) => await _documentUrlService.CreateOrUpdateUrlSegmentsAsync(notification.SavedEntities);
// }
47 changes: 47 additions & 0 deletions src/Umbraco.Core/Services/DocumentUrlService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
using Umbraco.Cms.Core.Configuration.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Persistence.Repositories;
using Umbraco.Cms.Core.Routing;
using Umbraco.Cms.Core.Scoping;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Cms.Core.Strings;
Expand Down Expand Up @@ -415,6 +416,52 @@ public async Task DeleteUrlsAsync(IEnumerable<IContent> documents)
return runnerKey;
}

Check warning on line 417 in src/Umbraco.Core/Services/DocumentUrlService.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

❌ New issue: Complex Method

GetDocumentKeyByRoute has a cyclomatic complexity of 12, threshold = 9. This function has many conditional statements (e.g. if, for, while), leading to lower code health. Avoid adding more conditionals and code to it without refactoring.

Check warning on line 417 in src/Umbraco.Core/Services/DocumentUrlService.cs

View check run for this annotation

CodeScene Delta Analysis / CodeScene Cloud Delta Analysis (v15/dev)

❌ New issue: Bumpy Road Ahead

GetDocumentKeyByRoute has 4 blocks with nested conditional logic. Any nesting of 2 or deeper is considered. Threshold is one single, nested block per function. The Bumpy Road code smell is a function that contains multiple chunks of nested conditional logic. The deeper the nesting and the more bumps, the lower the code health.

// public async Task<IEnumerable<UrlInfo>> ListUrlsAsync(Guid contentKey)
// {
// if(_documentNavigationQueryService.TryGetAncestorsKeys(contentKey, out var ancestorsKeys))
// {
// var languages = await _languageService.GetAllAsync();
// var cultures = languages.Select(x=>x.IsoCode);
//
// foreach (Guid ancestorKey in ancestorsKeys)
// {
// TODO her skal vi lave skabe en full url med domainer.
//
// foreach (var culture in cultures)
// {
// if (_cache.TryGetValue(CreateCacheKey(ancestorKey, culture, false), out PublishedDocumentUrlSegment? urlSegment))
// {
// //yield return new UrlInfo(urlSegment.UrlSegment, true, culture);
// }
// }
// }
// }
// }

public async Task CreateOrUpdateUrlSegmentsWithDescendantsAsync(Guid key)
{
var id = _idKeyMap.GetIdForKey(key, UmbracoObjectTypes.Document).Result;
IEnumerable<IContent> contents = _contentService.GetPagedDescendants(id, 0, int.MaxValue, out _);
await CreateOrUpdateUrlSegmentsAsync(contents);
}

public async Task DeleteUrlsAndDescendantsAsync(Guid key)
{
var id = _idKeyMap.GetIdForKey(key, UmbracoObjectTypes.Document).Result;
IEnumerable<IContent> contents = _contentService.GetPagedDescendants(id, 0, int.MaxValue, out _);
await DeleteUrlsAsync(contents);
}

public async Task CreateOrUpdateUrlSegmentsAsync(Guid key)
{
IContent? content = _contentService.GetById(key);

if (content is not null)
{
await CreateOrUpdateUrlSegmentsAsync(content.Yield());
}
}

//TODO test cases:
// - Find the root, when a domain is set
// - Find a nested child, when a domain is set
Expand Down
6 changes: 6 additions & 0 deletions src/Umbraco.Core/Services/IDocumentUrlService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using Umbraco.Cms.Core.Media.EmbedProviders;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Routing;

namespace Umbraco.Cms.Core.Services;

Expand All @@ -13,6 +14,7 @@ public interface IDocumentUrlService
/// <returns></returns>
Task InitAsync(bool forceEmpty, CancellationToken cancellationToken);

Task RebuildAllUrlsAsync();
/// <summary>
/// Gets the Url from a document key, culture and segment. Preview urls are returned if isPreview is true.
/// </summary>
Expand All @@ -29,4 +31,8 @@ public interface IDocumentUrlService
Task DeleteUrlsAsync(IEnumerable<IContent> documents);

Guid? GetDocumentKeyByRoute(string route, string? culture, int? documentStartNodeId, bool isDraft);
//Task<IEnumerable<UrlInfo>> ListUrlsAsync(Guid contentKey);
Task CreateOrUpdateUrlSegmentsWithDescendantsAsync(Guid key);
Task DeleteUrlsAndDescendantsAsync(Guid key);
Task CreateOrUpdateUrlSegmentsAsync(Guid key);
}
Original file line number Diff line number Diff line change
Expand Up @@ -416,11 +416,11 @@ public static IUmbracoBuilder AddCoreNotifications(this IUmbracoBuilder builder)
.AddNotificationAsyncHandler<ContentTypeSavedNotification, WarnDocumentTypeElementSwitchNotificationHandler>();

// Handlers for routing
builder
.AddNotificationAsyncHandler<ContentPublishedNotification, RoutingNotificationHandler>()
.AddNotificationAsyncHandler<ContentUnpublishedNotification, RoutingNotificationHandler>()
.AddNotificationAsyncHandler<ContentDeletedNotification, RoutingNotificationHandler>()
.AddNotificationAsyncHandler<ContentSavedNotification, RoutingNotificationHandler>();
// builder
// .AddNotificationAsyncHandler<ContentPublishedNotification, RoutingNotificationHandler>()
// .AddNotificationAsyncHandler<ContentUnpublishedNotification, RoutingNotificationHandler>()
// .AddNotificationAsyncHandler<ContentDeletedNotification, RoutingNotificationHandler>()
// .AddNotificationAsyncHandler<ContentSavedNotification, RoutingNotificationHandler>();

return builder;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ public class DocumentUrlServiceTest : UmbracoIntegrationTestWithContent

protected override void CustomTestSetup(IUmbracoBuilder builder)
{
builder
.AddNotificationAsyncHandler<ContentPublishedNotification, RoutingNotificationHandler>()
.AddNotificationAsyncHandler<ContentUnpublishedNotification, RoutingNotificationHandler>()
.AddNotificationAsyncHandler<ContentDeletedNotification, RoutingNotificationHandler>()
.AddNotificationAsyncHandler<ContentSavedNotification, RoutingNotificationHandler>();
// builder
// .AddNotificationAsyncHandler<ContentPublishedNotification, RoutingNotificationHandler>()
// .AddNotificationAsyncHandler<ContentUnpublishedNotification, RoutingNotificationHandler>()
// .AddNotificationAsyncHandler<ContentDeletedNotification, RoutingNotificationHandler>()
// .AddNotificationAsyncHandler<ContentSavedNotification, RoutingNotificationHandler>();

}
//
Expand Down

0 comments on commit 87e9797

Please sign in to comment.