Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle navigation updates in cache refeshers #17161

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 107 additions & 2 deletions src/Umbraco.Core/Cache/Refreshers/Implement/ContentCacheRefresher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
private readonly IDomainService _domainService;
private readonly IDocumentUrlService _documentUrlService;
private readonly IDocumentNavigationQueryService _documentNavigationQueryService;
private readonly IDocumentNavigationManagementService _documentNavigationManagementService;
private readonly IContentService _contentService;
private readonly IIdKeyMap _idKeyMap;
private readonly IPublishedSnapshotService _publishedSnapshotService;

Expand All @@ -40,7 +42,9 @@
eventAggregator,
factory,
StaticServiceProvider.Instance.GetRequiredService<IDocumentUrlService>(),
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>()
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationQueryService>(),
StaticServiceProvider.Instance.GetRequiredService<IDocumentNavigationManagementService>(),
StaticServiceProvider.Instance.GetRequiredService<IContentService>()
)
{

Expand All @@ -55,14 +59,18 @@
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory,
IDocumentUrlService documentUrlService,
IDocumentNavigationQueryService documentNavigationQueryService)
IDocumentNavigationQueryService documentNavigationQueryService,
IDocumentNavigationManagementService documentNavigationManagementService,
IContentService contentService)
: base(appCaches, serializer, eventAggregator, factory)
{
_publishedSnapshotService = publishedSnapshotService;
_idKeyMap = idKeyMap;
_domainService = domainService;
_documentUrlService = documentUrlService;
_documentNavigationQueryService = documentNavigationQueryService;
_documentNavigationManagementService = documentNavigationManagementService;
_contentService = contentService;

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

View check run for this annotation

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

ℹ Getting worse: Constructor Over-Injection

ContentCacheRefresher increases from 9 to 11 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 @@ -126,6 +134,7 @@

HandleRouting(payload);

HandleNavigation(payload);
_idKeyMap.ClearCache(payload.Id);
if (payload.Key.HasValue)
{
Expand Down Expand Up @@ -172,6 +181,102 @@
base.Refresh(payloads);
}

private void HandleNavigation(JsonPayload payload)
{
if (payload.Key is null)
{
return;
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
{
_documentNavigationManagementService.MoveToBin(payload.Key.Value);
_documentNavigationManagementService.RemoveFromBin(payload.Key.Value);
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
_documentNavigationManagementService.RebuildAsync();
_documentNavigationManagementService.RebuildBinAsync();
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshNode))
{
IContent? content = _contentService.GetById(payload.Id);

if (content is null)
{
return;
}

HandleNavigationForSingleContent(content);
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
IContent? content = _contentService.GetById(payload.Id);

if (content is null)
{
return;
}

IEnumerable<IContent> descendants = _contentService.GetPagedDescendants(content.Id, 0, int.MaxValue, out _);
foreach (IContent descendant in content.Yield().Concat(descendants))
{
HandleNavigationForSingleContent(descendant);
}
}
}

Check warning on line 230 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: Complex Method

HandleNavigation has a cyclomatic complexity of 9, 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 230 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: Bumpy Road Ahead

HandleNavigation has 2 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.

private void HandleNavigationForSingleContent(IContent content)
{
// First creation
if (ExistsInNavigation(content.Key) is false && ExistsInNavigationBin(content.Key) is false)
{
_documentNavigationManagementService.Add(content.Key, GetParentKey(content));
if (content.Trashed)
{
// If created as trashed, move to bin
_documentNavigationManagementService.MoveToBin(content.Key);
}
}
else if (ExistsInNavigation(content.Key) && ExistsInNavigationBin(content.Key) is false)
{
if (content.Trashed)
{
// It must have been trashed
_documentNavigationManagementService.MoveToBin(content.Key);
}
else
{
// It must have been saved. Check if parent is different
if (_documentNavigationQueryService.TryGetParentKey(content.Key, out var oldParentKey))
{
Guid? newParentKey = GetParentKey(content);
if (oldParentKey != newParentKey)
{
_documentNavigationManagementService.Move(content.Key, newParentKey);
}
}
}
}
else if (ExistsInNavigation(content.Key) is false && ExistsInNavigationBin(content.Key))
{
if (content.Trashed is false)
{
// It must have been restored
_documentNavigationManagementService.RestoreFromBin(content.Key, GetParentKey(content));
}
}
}

Check warning on line 272 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: Complex Method

HandleNavigationForSingleContent 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 272 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: Bumpy Road Ahead

HandleNavigationForSingleContent 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.

Check warning on line 272 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: Deep, Nested Complexity

HandleNavigationForSingleContent has a nested complexity depth of 5, threshold = 4. This function contains deeply nested logic such as if statements and/or loops. The deeper the nesting, the lower the code health.

private Guid? GetParentKey(IContent content) => (content.ParentId == -1) ? null : _idKeyMap.GetKeyForId(content.ParentId, UmbracoObjectTypes.Document).Result;

private bool ExistsInNavigation(Guid contentKey) => _documentNavigationQueryService.TryGetParentKey(contentKey, out _);

private bool ExistsInNavigationBin(Guid contentKey) => _documentNavigationQueryService.TryGetParentKeyInBin(contentKey, out _);

private void HandleRouting(JsonPayload payload)
{
if(payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
Expand Down
138 changes: 123 additions & 15 deletions src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@
using Umbraco.Cms.Core.Serialization;
using Umbraco.Cms.Core.Services;
using Umbraco.Cms.Core.Services.Changes;
using Umbraco.Cms.Core.Services.Navigation;
using Umbraco.Extensions;

namespace Umbraco.Cms.Core.Cache;

public sealed class MediaCacheRefresher : PayloadCacheRefresherBase<MediaCacheRefresherNotification, MediaCacheRefresher.JsonPayload>
{
private readonly IIdKeyMap _idKeyMap;
private readonly IMediaNavigationQueryService _mediaNavigationQueryService;
private readonly IMediaNavigationManagementService _mediaNavigationManagementService;
private readonly IMediaService _mediaService;
private readonly IPublishedSnapshotService _publishedSnapshotService;

public MediaCacheRefresher(
Expand All @@ -21,11 +25,17 @@
IPublishedSnapshotService publishedSnapshotService,
IIdKeyMap idKeyMap,
IEventAggregator eventAggregator,
ICacheRefresherNotificationFactory factory)
ICacheRefresherNotificationFactory factory,
IMediaNavigationQueryService mediaNavigationQueryService,
IMediaNavigationManagementService mediaNavigationManagementService,
IMediaService mediaService)
: base(appCaches, serializer, eventAggregator, factory)
{
_publishedSnapshotService = publishedSnapshotService;
_idKeyMap = idKeyMap;
_mediaNavigationQueryService = mediaNavigationQueryService;
_mediaNavigationManagementService = mediaNavigationManagementService;
_mediaService = mediaService;

Check notice on line 38 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

ℹ Getting worse: Constructor Over-Injection

MediaCacheRefresher increases from 6 to 9 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 @@ -84,35 +94,133 @@
_idKeyMap.ClearCache(payload.Id);
}

if (!mediaCache.Success)
if (mediaCache.Success)
{
continue;
// repository cache
// it *was* done for each pathId but really that does not make sense
// only need to do it for the current media
mediaCache.Result?.Clear(RepositoryCacheKeys.GetKey<IMedia, int>(payload.Id));
mediaCache.Result?.Clear(RepositoryCacheKeys.GetKey<IMedia, Guid?>(payload.Key));

// remove those that are in the branch
if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.RefreshBranch | TreeChangeTypes.Remove))
{
var pathid = "," + payload.Id + ",";
mediaCache.Result?.ClearOfType<IMedia>((_, v) => v.Path?.Contains(pathid) ?? false);
}
}

// repository cache
// it *was* done for each pathId but really that does not make sense
// only need to do it for the current media
mediaCache.Result?.Clear(RepositoryCacheKeys.GetKey<IMedia, int>(payload.Id));
mediaCache.Result?.Clear(RepositoryCacheKeys.GetKey<IMedia, Guid?>(payload.Key));

// remove those that are in the branch
if (payload.ChangeTypes.HasTypesAny(TreeChangeTypes.RefreshBranch | TreeChangeTypes.Remove))
{
var pathid = "," + payload.Id + ",";
mediaCache.Result?.ClearOfType<IMedia>((_, v) => v.Path?.Contains(pathid) ?? false);
}
HandleNavigation(payload);
}

_publishedSnapshotService.Notify(payloads, out var hasPublishedDataChanged);
// we only need to clear this if the published cache has changed
if (hasPublishedDataChanged)
{
AppCaches.ClearPartialViewCache();
}


Check notice on line 123 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

✅ No longer an issue: Complex Method

Refresh is no longer above the threshold for cyclomatic complexity. 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 123 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

❌ New issue: Bumpy Road Ahead

Refresh has 2 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.
base.Refresh(payloads);
}

private void HandleNavigation(JsonPayload payload)
{
if (payload.Key is null)
{
return;
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.Remove))
{
_mediaNavigationManagementService.MoveToBin(payload.Key.Value);
_mediaNavigationManagementService.RemoveFromBin(payload.Key.Value);
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshAll))
{
_mediaNavigationManagementService.RebuildAsync();
_mediaNavigationManagementService.RebuildBinAsync();
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshNode))
{
IMedia? media = _mediaService.GetById(payload.Id);

if (media is null)
{
return;
}

HandleNavigationForSingleMedia(media);
}

if (payload.ChangeTypes.HasType(TreeChangeTypes.RefreshBranch))
{
IMedia? media = _mediaService.GetById(payload.Id);

if (media is null)
{
return;
}

IEnumerable<IMedia> descendants = _mediaService.GetPagedDescendants(media.Id, 0, int.MaxValue, out _);
foreach (IMedia descendant in media.Yield().Concat(descendants))
{
HandleNavigationForSingleMedia(descendant);
}
}
}

Check warning on line 173 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

❌ New issue: Complex Method

HandleNavigation has a cyclomatic complexity of 9, 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 173 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

❌ New issue: Bumpy Road Ahead

HandleNavigation has 2 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.

private void HandleNavigationForSingleMedia(IMedia media)
{
// First creation
if (ExistsInNavigation(media.Key) is false && ExistsInNavigationBin(media.Key) is false)
{
_mediaNavigationManagementService.Add(media.Key, GetParentKey(media));
if (media.Trashed)
{
// If created as trashed, move to bin
_mediaNavigationManagementService.MoveToBin(media.Key);
}
}
else if (ExistsInNavigation(media.Key) && ExistsInNavigationBin(media.Key) is false)
{
if (media.Trashed)
{
// It must have been trashed
_mediaNavigationManagementService.MoveToBin(media.Key);
}
else
{
// It must have been saved. Check if parent is different
if (_mediaNavigationQueryService.TryGetParentKey(media.Key, out var oldParentKey))
{
Guid? newParentKey = GetParentKey(media);
if (oldParentKey != newParentKey)
{
_mediaNavigationManagementService.Move(media.Key, newParentKey);
}
}
}
}
else if (ExistsInNavigation(media.Key) is false && ExistsInNavigationBin(media.Key))
{
if (media.Trashed is false)
{
// It must have been restored
_mediaNavigationManagementService.RestoreFromBin(media.Key, GetParentKey(media));
}
}
}

Check warning on line 215 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

❌ New issue: Complex Method

HandleNavigationForSingleMedia 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 215 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

❌ New issue: Bumpy Road Ahead

HandleNavigationForSingleMedia 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.

Check warning on line 215 in src/Umbraco.Core/Cache/Refreshers/Implement/MediaCacheRefresher.cs

View check run for this annotation

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

❌ New issue: Deep, Nested Complexity

HandleNavigationForSingleMedia has a nested complexity depth of 5, threshold = 4. This function contains deeply nested logic such as if statements and/or loops. The deeper the nesting, the lower the code health.

private Guid? GetParentKey(IMedia media) => (media.ParentId == -1) ? null : _idKeyMap.GetKeyForId(media.ParentId, UmbracoObjectTypes.Media).Result;

private bool ExistsInNavigation(Guid contentKey) => _mediaNavigationQueryService.TryGetParentKey(contentKey, out _);

private bool ExistsInNavigationBin(Guid contentKey) => _mediaNavigationQueryService.TryGetParentKeyInBin(contentKey, out _);


// these events should never trigger
// everything should be JSON
public override void RefreshAll() => throw new NotSupportedException();
Expand Down
42 changes: 0 additions & 42 deletions src/Umbraco.Core/Factories/NavigationFactory.cs

This file was deleted.

Loading
Loading