using System; using Umbraco.Cms.Core.Events; using Umbraco.Cms.Core.Models; using Umbraco.Cms.Core.PublishedCache; using Umbraco.Cms.Core.Serialization; using Umbraco.Cms.Core.Services.Changes; using static Umbraco.Cms.Core.Cache.LanguageCacheRefresher.JsonPayload; namespace Umbraco.Cms.Core.Cache { public sealed class LanguageCacheRefresher : PayloadCacheRefresherBase { public LanguageCacheRefresher( AppCaches appCaches, IJsonSerializer serializer, IPublishedSnapshotService publishedSnapshotService, IEventAggregator eventAggregator) : base(appCaches, serializer, eventAggregator) { _publishedSnapshotService = publishedSnapshotService; } #region Define public static readonly Guid UniqueId = Guid.Parse("3E0F95D8-0BE5-44B8-8394-2B8750B62654"); private readonly IPublishedSnapshotService _publishedSnapshotService; public override Guid RefresherUniqueId => UniqueId; public override string Name => "Language Cache Refresher"; #endregion #region Refresher public override void Refresh(JsonPayload[] payloads) { if (payloads.Length == 0) return; var clearDictionary = false; var clearContent = false; //clear all no matter what type of payload ClearAllIsolatedCacheByEntityType(); foreach (var payload in payloads) { switch (payload.ChangeType) { case LanguageChangeType.Update: clearDictionary = true; break; case LanguageChangeType.Remove: case LanguageChangeType.ChangeCulture: clearDictionary = true; clearContent = true; break; } } if (clearDictionary) { ClearAllIsolatedCacheByEntityType(); } //if this flag is set, we will tell the published snapshot service to refresh ALL content and evict ALL IContent items if (clearContent) { //clear all domain caches RefreshDomains(); ContentCacheRefresher.RefreshContentTypes(AppCaches); // we need to evict all IContent items //now refresh all nucache var clearContentPayload = new[] { new ContentCacheRefresher.JsonPayload(0, null, TreeChangeTypes.RefreshAll) }; ContentCacheRefresher.NotifyPublishedSnapshotService(_publishedSnapshotService, AppCaches, clearContentPayload); } // then trigger event base.Refresh(payloads); } // these events should never trigger // everything should be PAYLOAD/JSON public override void RefreshAll() => throw new NotSupportedException(); public override void Refresh(int id) => throw new NotSupportedException(); public override void Refresh(Guid id) => throw new NotSupportedException(); public override void Remove(int id) => throw new NotSupportedException(); #endregion /// /// Clears all domain caches /// private void RefreshDomains() { ClearAllIsolatedCacheByEntityType(); // note: must do what's above FIRST else the repositories still have the old cached // content and when the PublishedCachesService is notified of changes it does not see // the new content... var payloads = new[] { new DomainCacheRefresher.JsonPayload(0, DomainChangeTypes.RefreshAll) }; _publishedSnapshotService.Notify(payloads); } #region Json public class JsonPayload { public JsonPayload(int id, string isoCode, LanguageChangeType changeType) { Id = id; IsoCode = isoCode; ChangeType = changeType; } public int Id { get; } public string IsoCode { get; } public LanguageChangeType ChangeType { get; } public enum LanguageChangeType { /// /// A new languages has been added /// Add = 0, /// /// A language has been deleted /// Remove = 1, /// /// A language has been updated - but it's culture remains the same /// Update = 2, /// /// A language has been updated - it's culture has changed /// ChangeCulture = 3 } } #endregion } }