From a996d46b6ff85bd927b0a331f37de6d36f123529 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 17 Apr 2019 14:41:54 +0200 Subject: [PATCH] Refactor IPublishedContent.GetCultureFromDomains() --- .../LegacyXmlPublishedCache/DomainCache.cs | 9 +- .../PublishedContentCache.cs | 8 +- src/Umbraco.Web/Editors/ContentController.cs | 2 +- .../Editors/MacroRenderingController.cs | 20 ++--- .../PublishedCache/IDomainCache.cs | 25 ++++-- .../PublishedCache/NuCache/ContentCache.cs | 12 ++- .../PublishedCache/NuCache/DomainCache.cs | 19 ++++- .../NuCache/PublishedSnapshotService.cs | 5 +- src/Umbraco.Web/PublishedContentExtensions.cs | 25 ++++++ src/Umbraco.Web/Routing/AliasUrlProvider.cs | 7 +- .../Routing/ContentFinderByConfigured404.cs | 2 +- .../Routing/ContentFinderByRedirectUrl.cs | 2 +- src/Umbraco.Web/Routing/ContentFinderByUrl.cs | 2 +- .../Routing/ContentFinderByUrlAndTemplate.cs | 2 +- src/Umbraco.Web/Routing/DefaultUrlProvider.cs | 10 +-- src/Umbraco.Web/Routing/DomainAndUri.cs | 2 +- .../{DomainHelper.cs => DomainUtilities.cs} | 83 +++++++++++++------ src/Umbraco.Web/Routing/PublishedRouter.cs | 4 +- src/Umbraco.Web/Umbraco.Web.csproj | 2 +- src/Umbraco.Web/UmbracoContext.cs | 20 ----- src/Umbraco.Web/UmbracoHelper.cs | 6 -- 21 files changed, 153 insertions(+), 114 deletions(-) rename src/Umbraco.Web/Routing/{DomainHelper.cs => DomainUtilities.cs} (81%) diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs index cde2077551..abaa239598 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/DomainCache.cs @@ -27,13 +27,18 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache } /// - public IEnumerable GetAssigned(int contentId, bool includeWildcards) + public IEnumerable GetAssigned(int documentId, bool includeWildcards = false) { - return _domainService.GetAssignedDomains(contentId, includeWildcards) + return _domainService.GetAssignedDomains(documentId, includeWildcards) .Where(x => x.RootContentId.HasValue && x.LanguageIsoCode.IsNullOrWhiteSpace() == false) .Select(x => new Domain(x.Id, x.DomainName, x.RootContentId.Value, CultureInfo.GetCultureInfo(x.LanguageIsoCode), x.IsWildcard)); } + /// + public bool HasAssigned(int documentId, bool includeWildcards = false) + => documentId > 0 && GetAssigned(documentId, includeWildcards).Any(); + + /// public string DefaultCulture { get; } } } diff --git a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs index 1ad6e045c6..1ccbbf950b 100644 --- a/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Tests/LegacyXmlPublishedCache/PublishedContentCache.cs @@ -22,7 +22,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache private readonly IUmbracoContextAccessor _umbracoContextAccessor; private readonly RoutesCache _routesCache; private readonly IDomainCache _domainCache; - private readonly DomainHelper _domainHelper; private readonly PublishedContentTypeCache _contentTypeCache; // initialize a PublishedContentCache instance with @@ -48,7 +47,6 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache _routesCache = routesCache; // may be null for unit-testing _contentTypeCache = contentTypeCache; _domainCache = domainCache; - _domainHelper = new DomainHelper(_domainCache, siteDomainHelper); _xmlStore = xmlStore; _xml = _xmlStore.Xml; // capture - because the cache has to remain consistent @@ -107,7 +105,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // that would be returned - the "deepest" route - and that is the route we want to cache, *not* the // longer one - so make sure we don't cache the wrong route - var deepest = DomainHelper.ExistsDomainInPath(_domainCache.GetAll(false), content.Path, domainRootNodeId) == false; + var deepest = DomainUtilities.ExistsDomainInPath(_domainCache.GetAll(false), content.Path, domainRootNodeId) == false; if (deepest) _routesCache.Store(content.Id, route, true); // trusted route @@ -267,7 +265,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // or we reach the content root, collecting urls in the way var pathParts = new List(); var n = node; - var hasDomains = _domainHelper.NodeHasDomains(n.Id); + var hasDomains = _domainCache.HasAssigned(n.Id); while (hasDomains == false && n != null) // n is null at root { // get the url @@ -276,7 +274,7 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache // move to parent node n = n.Parent; - hasDomains = n != null && _domainHelper.NodeHasDomains(n.Id); + hasDomains = n != null && _domainCache.HasAssigned(n.Id); } // no domain, respect HideTopLevelNodeFromPath for legacy purposes diff --git a/src/Umbraco.Web/Editors/ContentController.cs b/src/Umbraco.Web/Editors/ContentController.cs index 4b23e46a6c..a8824d416f 100644 --- a/src/Umbraco.Web/Editors/ContentController.cs +++ b/src/Umbraco.Web/Editors/ContentController.cs @@ -1656,7 +1656,7 @@ namespace Umbraco.Web.Editors { try { - var uri = DomainHelper.ParseUriFromDomainName(domain.Name, Request.RequestUri); + var uri = DomainUtilities.ParseUriFromDomainName(domain.Name, Request.RequestUri); } catch (UriFormatException) { diff --git a/src/Umbraco.Web/Editors/MacroRenderingController.cs b/src/Umbraco.Web/Editors/MacroRenderingController.cs index 64706a7f04..0c3b1626d0 100644 --- a/src/Umbraco.Web/Editors/MacroRenderingController.cs +++ b/src/Umbraco.Web/Editors/MacroRenderingController.cs @@ -123,23 +123,17 @@ namespace Umbraco.Web.Editors // Since a Macro might contain thing thats related to the culture of the "IPublishedContent" (ie Dictionary keys) we want // to set the current culture to the culture related to the content item. This is hacky but it works. - // fixme I don't even know how this ever worked?! + // fixme + // in a 1:1 situation we do not handle the language being edited + // so the macro renders in the wrong language - // assume this was some sort of "the culture of the item" - // but... with multilingual it does not make any sense?! - //var culture = publishedContent.GetCulture(); - - string culture = ""; // needs to be eg fr-FR + var culture = publishedContent.GetCultureFromDomains(); if (culture != null) - { Thread.CurrentThread.CurrentCulture = Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture); - _variationContextAccessor.VariationContext = new VariationContext(culture); - } - else - { - _variationContextAccessor.VariationContext = new VariationContext(); //must have an active variation context! - } + + // must have an active variation context! + _variationContextAccessor.VariationContext = new VariationContext(culture); var result = Request.CreateResponse(); //need to create a specific content result formatted as HTML since this controller has been configured diff --git a/src/Umbraco.Web/PublishedCache/IDomainCache.cs b/src/Umbraco.Web/PublishedCache/IDomainCache.cs index dbee8908a0..3ec84c9d48 100644 --- a/src/Umbraco.Web/PublishedCache/IDomainCache.cs +++ b/src/Umbraco.Web/PublishedCache/IDomainCache.cs @@ -1,4 +1,6 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.Routing; namespace Umbraco.Web.PublishedCache @@ -6,20 +8,29 @@ namespace Umbraco.Web.PublishedCache public interface IDomainCache { /// - /// Returns all in the current domain cache including any domains that may be referenced by content items that are no longer published + /// Gets all in the current domain cache, including any domains that may be referenced by documents that are no longer published. /// /// /// IEnumerable GetAll(bool includeWildcards); /// - /// Returns all assigned for the content id specified even if the content item is not published + /// Gets all assigned for specified document, even if it is not published. /// - /// - /// - /// - IEnumerable GetAssigned(int contentId, bool includeWildcards); + /// The document identifier. + /// A value indicating whether to consider wildcard domains. + IEnumerable GetAssigned(int documentId, bool includeWildcards = false); + /// + /// Determines whether a document has domains. + /// + /// The document identifier. + /// A value indicating whether to consider wildcard domains. + bool HasAssigned(int documentId, bool includeWildcards = false); + + /// + /// Gets the system default culture. + /// string DefaultCulture { get; } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs index 08664f0a7a..705ce17595 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/ContentCache.cs @@ -23,9 +23,8 @@ namespace Umbraco.Web.PublishedCache.NuCache private readonly ContentStore.Snapshot _snapshot; private readonly IAppCache _snapshotCache; private readonly IAppCache _elementsCache; - private readonly DomainHelper _domainHelper; + private readonly IDomainCache _domainCache; private readonly IGlobalSettings _globalSettings; - private readonly ILocalizationService _localizationService; #region Constructor @@ -34,15 +33,14 @@ namespace Umbraco.Web.PublishedCache.NuCache // it's too late for UmbracoContext which has captured previewDefault and stuff into these ctor vars // but, no, UmbracoContext returns snapshot.Content which comes from elements SO a resync should create a new cache - public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, DomainHelper domainHelper, IGlobalSettings globalSettings, ILocalizationService localizationService) + public ContentCache(bool previewDefault, ContentStore.Snapshot snapshot, IAppCache snapshotCache, IAppCache elementsCache, IDomainCache domainCache, IGlobalSettings globalSettings) : base(previewDefault) { _snapshot = snapshot; _snapshotCache = snapshotCache; _elementsCache = elementsCache; - _domainHelper = domainHelper; + _domainCache = domainCache; _globalSettings = globalSettings; - _localizationService = localizationService; } private bool HideTopLevelNodeFromPath => _globalSettings.HideTopLevelNodeFromPath; @@ -150,7 +148,7 @@ namespace Umbraco.Web.PublishedCache.NuCache var pathParts = new List(); var n = node; var urlSegment = n.UrlSegment(culture); - var hasDomains = _domainHelper.NodeHasDomains(n.Id); + var hasDomains = _domainCache.HasAssigned(n.Id); while (hasDomains == false && n != null) // n is null at root { // no segment indicates this is not published when this is a variant @@ -163,7 +161,7 @@ namespace Umbraco.Web.PublishedCache.NuCache if (n != null) urlSegment = n.UrlSegment(culture); - hasDomains = n != null && _domainHelper.NodeHasDomains(n.Id); + hasDomains = n != null && _domainCache.HasAssigned(n.Id); } // at this point this will be the urlSegment of the root, no segment indicates this is not published when this is a variant diff --git a/src/Umbraco.Web/PublishedCache/NuCache/DomainCache.cs b/src/Umbraco.Web/PublishedCache/NuCache/DomainCache.cs index 896a04a0b3..6bc0de7268 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/DomainCache.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/DomainCache.cs @@ -4,16 +4,23 @@ using Umbraco.Web.Routing; namespace Umbraco.Web.PublishedCache.NuCache { + /// + /// Implements for NuCache. + /// internal class DomainCache : IDomainCache { private readonly SnapDictionary.Snapshot _snapshot; + /// + /// Initializes a new instance of the class. + /// public DomainCache(SnapDictionary.Snapshot snapshot, string defaultCulture) { _snapshot = snapshot; - DefaultCulture = defaultCulture; // capture - fast + DefaultCulture = defaultCulture; } + /// public IEnumerable GetAll(bool includeWildcards) { var list = _snapshot.GetAll(); @@ -21,17 +28,23 @@ namespace Umbraco.Web.PublishedCache.NuCache return list; } - public IEnumerable GetAssigned(int contentId, bool includeWildcards) + /// + public IEnumerable GetAssigned(int documentId, bool includeWildcards = false) { // probably this could be optimized with an index // but then we'd need a custom DomainStore of some sort var list = _snapshot.GetAll(); - list = list.Where(x => x.ContentId == contentId); + list = list.Where(x => x.ContentId == documentId); if (includeWildcards == false) list = list.Where(x => x.IsWildcard == false); return list; } + /// + public bool HasAssigned(int documentId, bool includeWildcards = false) + => documentId > 0 && GetAssigned(documentId, includeWildcards).Any(); + + /// public string DefaultCulture { get; } } } diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 3b683cdd4e..ce19764fb6 100755 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -4,13 +4,11 @@ using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; -using System.Web; using CSharpTest.Net.Collections; using Newtonsoft.Json; using Umbraco.Core; using Umbraco.Core.Cache; using Umbraco.Core.Configuration; -using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; @@ -1074,11 +1072,10 @@ namespace Umbraco.Web.PublishedCache.NuCache var defaultCulture = _defaultCultureAccessor.DefaultCulture; var domainCache = new DomainCache(domainSnap, defaultCulture); - var domainHelper = new DomainHelper(domainCache, _siteDomainHelper); return new PublishedSnapshot.PublishedSnapshotElements { - ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainHelper, _globalSettings, _serviceContext.LocalizationService), + ContentCache = new ContentCache(previewDefault, contentSnap, snapshotCache, elementsCache, domainCache, _globalSettings), MediaCache = new MediaCache(previewDefault, mediaSnap, snapshotCache, elementsCache), MemberCache = new MemberCache(previewDefault, snapshotCache, _serviceContext.MemberService, memberTypeCache, PublishedSnapshotAccessor, VariationContextAccessor, _umbracoContextAccessor, _entitySerializer), DomainCache = domainCache, diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index d7996034a8..a243d6e77a 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -11,6 +11,7 @@ using Umbraco.Core.Services; using Umbraco.Examine; using Umbraco.Web.Composing; using Umbraco.Web.PublishedCache; +using Umbraco.Web.Routing; namespace Umbraco.Web { @@ -20,9 +21,12 @@ namespace Umbraco.Web public static class PublishedContentExtensions { // see notes in PublishedElementExtensions + // (yes, this is not pretty, but works for now) // private static IPublishedValueFallback PublishedValueFallback => Current.PublishedValueFallback; private static IPublishedSnapshot PublishedSnapshot => Current.PublishedSnapshot; + private static UmbracoContext UmbracoContext => Current.UmbracoContext; + private static ISiteDomainHelper SiteDomainHelper => Current.Factory.GetInstance(); #region IsComposedOf @@ -186,6 +190,27 @@ namespace Umbraco.Web return contents.Where(x => !x.ContentType.VariesByCulture() || x.HasCulture(culture)); } + /// + /// Gets the culture assigned to a document by domains, in the context of a current Uri. + /// + /// The document. + /// An optional current Uri. + /// The culture assigned to the document by domains. + /// + /// In 1:1 multilingual setup, a document contains several cultures (there is not + /// one document per culture), and domains, withing the context of a current Uri, assign + /// a culture to that document. + /// + public static string GetCultureFromDomains(this IPublishedContent content, Uri current = null) + { + var umbracoContext = UmbracoContext; + + if (umbracoContext == null) + throw new InvalidOperationException("A current UmbracoContext is required."); + + return DomainUtilities.GetCultureFromDomains(content.Id, content.Path, current, umbracoContext, SiteDomainHelper); + } + #endregion #region Search diff --git a/src/Umbraco.Web/Routing/AliasUrlProvider.cs b/src/Umbraco.Web/Routing/AliasUrlProvider.cs index bbe3a9db8c..411fabbf35 100644 --- a/src/Umbraco.Web/Routing/AliasUrlProvider.cs +++ b/src/Umbraco.Web/Routing/AliasUrlProvider.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; @@ -60,16 +59,14 @@ namespace Umbraco.Web.Routing if (!node.HasProperty(Constants.Conventions.Content.UrlAlias)) yield break; - var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper); - // look for domains, walking up the tree var n = node; - var domainUris = domainHelper.DomainsForNode(n.Id, current, false); + var domainUris = DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainHelper, n.Id, current, false); while (domainUris == null && n != null) // n is null at root { // move to parent node n = n.Parent; - domainUris = n == null ? null : domainHelper.DomainsForNode(n.Id, current, excludeDefault: false); + domainUris = n == null ? null : DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainHelper, n.Id, current, excludeDefault: false); } // determine whether the alias property varies diff --git a/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs b/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs index e3cad25c6f..e5bb23bfce 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByConfigured404.cs @@ -53,7 +53,7 @@ namespace Umbraco.Web.Routing } if (node != null) { - var d = DomainHelper.FindWildcardDomainInPath(frequest.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), node.Path, null); + var d = DomainUtilities.FindWildcardDomainInPath(frequest.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), node.Path, null); if (d != null) errorCulture = d.Culture; } diff --git a/src/Umbraco.Web/Routing/ContentFinderByRedirectUrl.cs b/src/Umbraco.Web/Routing/ContentFinderByRedirectUrl.cs index eae2b57378..d7b4c9925c 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByRedirectUrl.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByRedirectUrl.cs @@ -33,7 +33,7 @@ namespace Umbraco.Web.Routing public bool TryFindContent(PublishedRequest frequest) { var route = frequest.HasDomain - ? frequest.Domain.ContentId + DomainHelper.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded()) + ? frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded()) : frequest.Uri.GetAbsolutePathDecoded(); var redirectUrl = _redirectUrlService.GetMostRecentRedirectUrl(route); diff --git a/src/Umbraco.Web/Routing/ContentFinderByUrl.cs b/src/Umbraco.Web/Routing/ContentFinderByUrl.cs index 94b2b9dbf2..9aa52782d1 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByUrl.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByUrl.cs @@ -28,7 +28,7 @@ namespace Umbraco.Web.Routing { string route; if (frequest.HasDomain) - route = frequest.Domain.ContentId + DomainHelper.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded()); + route = frequest.Domain.ContentId + DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, frequest.Uri.GetAbsolutePathDecoded()); else route = frequest.Uri.GetAbsolutePathDecoded(); diff --git a/src/Umbraco.Web/Routing/ContentFinderByUrlAndTemplate.cs b/src/Umbraco.Web/Routing/ContentFinderByUrlAndTemplate.cs index 1e86b40a79..39c80afd56 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByUrlAndTemplate.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByUrlAndTemplate.cs @@ -38,7 +38,7 @@ namespace Umbraco.Web.Routing var path = frequest.Uri.GetAbsolutePathDecoded(); if (frequest.HasDomain) - path = DomainHelper.PathRelativeToDomain(frequest.Domain.Uri, path); + path = DomainUtilities.PathRelativeToDomain(frequest.Domain.Uri, path); // no template if "/" if (path == "/") diff --git a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs index 98ba743fe5..06f275a685 100644 --- a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs @@ -47,15 +47,13 @@ namespace Umbraco.Web.Routing return null; } - var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper); - // extract domainUri and path // route is / or / var pos = route.IndexOf('/'); var path = pos == 0 ? route : route.Substring(pos); var domainUri = pos == 0 ? null - : domainHelper.DomainForNode(int.Parse(route.Substring(0, pos)), current, culture); + : DomainUtilities.DomainForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainHelper, int.Parse(route.Substring(0, pos)), current, culture); // assemble the url from domainUri (maybe null) and path var url = AssembleUrl(domainUri, path, current, mode).ToString(); @@ -84,15 +82,13 @@ namespace Umbraco.Web.Routing if (node == null) yield break; - var domainHelper = umbracoContext.GetDomainHelper(_siteDomainHelper); - // look for domains, walking up the tree var n = node; - var domainUris = domainHelper.DomainsForNode(n.Id, current, false); + var domainUris = DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainHelper, n.Id, current, false); while (domainUris == null && n != null) // n is null at root { n = n.Parent; // move to parent node - domainUris = n == null ? null : domainHelper.DomainsForNode(n.Id, current, excludeDefault: true); + domainUris = n == null ? null : DomainUtilities.DomainsForNode(umbracoContext.PublishedSnapshot.Domains, _siteDomainHelper, n.Id, current, excludeDefault: true); } // no domains = exit diff --git a/src/Umbraco.Web/Routing/DomainAndUri.cs b/src/Umbraco.Web/Routing/DomainAndUri.cs index 1151055621..46dc085998 100644 --- a/src/Umbraco.Web/Routing/DomainAndUri.cs +++ b/src/Umbraco.Web/Routing/DomainAndUri.cs @@ -22,7 +22,7 @@ namespace Umbraco.Web.Routing { try { - Uri = DomainHelper.ParseUriFromDomainName(Name, currentUri); + Uri = DomainUtilities.ParseUriFromDomainName(Name, currentUri); } catch (UriFormatException) { diff --git a/src/Umbraco.Web/Routing/DomainHelper.cs b/src/Umbraco.Web/Routing/DomainUtilities.cs similarity index 81% rename from src/Umbraco.Web/Routing/DomainHelper.cs rename to src/Umbraco.Web/Routing/DomainUtilities.cs index 95d97653a0..fb0c56b28d 100644 --- a/src/Umbraco.Web/Routing/DomainHelper.cs +++ b/src/Umbraco.Web/Routing/DomainUtilities.cs @@ -2,29 +2,69 @@ using System.Collections.Generic; using System.Linq; using Umbraco.Core; -using Umbraco.Web.PublishedCache; // published snapshot +using Umbraco.Web.PublishedCache; namespace Umbraco.Web.Routing { /// /// Provides utilities to handle domains. /// - public class DomainHelper + public static class DomainUtilities { - private readonly IDomainCache _domainCache; - private readonly ISiteDomainHelper _siteDomainHelper; + #region Document Culture - public DomainHelper(IDomainCache domainCache, ISiteDomainHelper siteDomainHelper) + /// + /// Gets the culture assigned to a document by domains, in the context of a current Uri. + /// + /// The document identifier. + /// The document path. + /// An optional current Uri. + /// An Umbraco context. + /// The site domain helper. + /// The culture assigned to the document by domains. + /// + /// In 1:1 multilingual setup, a document contains several cultures (there is not + /// one document per culture), and domains, withing the context of a current Uri, assign + /// a culture to that document. + /// + internal static string GetCultureFromDomains(int contentId, string contentPath, Uri current, UmbracoContext umbracoContext, ISiteDomainHelper siteDomainHelper) { - _domainCache = domainCache; - _siteDomainHelper = siteDomainHelper; + if (umbracoContext == null) + throw new InvalidOperationException("A current UmbracoContext is required."); + + if (current == null) + current = umbracoContext.CleanedUmbracoUrl; + + // get the published route, else the preview route + // if both are null then the content does not exist + var route = umbracoContext.Content.GetRouteById(contentId) ?? + umbracoContext.Content.GetRouteById(true, contentId); + + if (route == null) + return null; + + var pos = route.IndexOf('/'); + var domain = pos == 0 + ? null + : DomainForNode(umbracoContext.Domains, siteDomainHelper, int.Parse(route.Substring(0, pos)), current); + + var rootContentId = domain?.ContentId ?? -1; + var wcDomain = FindWildcardDomainInPath(umbracoContext.Domains.GetAll(true), contentPath, rootContentId); + + if (wcDomain != null) return wcDomain.Culture.Name; + if (domain != null) return domain.Culture.Name; + return umbracoContext.Domains.DefaultCulture; } - #region Domain for Node + #endregion + + #region Domain for Document /// /// Finds the domain for the specified node, if any, that best matches a specified uri. /// + /// A domain cache. + /// The site domain helper. /// The node identifier. /// The uri, or null. /// The culture, or null. @@ -35,14 +75,14 @@ namespace Umbraco.Web.Routing /// If culture is null, uses the default culture for the installation instead. Otherwise, /// will try with the specified culture, else return null. /// - internal DomainAndUri DomainForNode(int nodeId, Uri current, string culture = null) + internal static DomainAndUri DomainForNode(IDomainCache domainCache, ISiteDomainHelper siteDomainHelper, int nodeId, Uri current, string culture = null) { // be safe if (nodeId <= 0) return null; // get the domains on that node - var domains = _domainCache.GetAssigned(nodeId, false).ToArray(); + var domains = domainCache.GetAssigned(nodeId).ToArray(); // none? if (domains.Length == 0) @@ -50,37 +90,28 @@ namespace Umbraco.Web.Routing // else filter // it could be that none apply (due to culture) - return SelectDomain(domains, current, culture, _domainCache.DefaultCulture, - (cdomainAndUris, ccurrent, cculture, cdefaultCulture) => _siteDomainHelper.MapDomain(cdomainAndUris, ccurrent, cculture, cdefaultCulture)); - } - - /// - /// Gets a value indicating whether a specified node has domains. - /// - /// The node identifier. - /// True if the node has domains, else false. - internal bool NodeHasDomains(int nodeId) - { - return nodeId > 0 && _domainCache.GetAssigned(nodeId, false).Any(); + return SelectDomain(domains, current, culture, domainCache.DefaultCulture, siteDomainHelper.MapDomain); } /// /// Find the domains for the specified node, if any, that match a specified uri. /// + /// A domain cache. + /// The site domain helper. /// The node identifier. /// The uri, or null. /// A value indicating whether to exclude the current/default domain. True by default. /// The domains and their uris, that match the specified uri, else null. /// If at least a domain is set on the node then the method returns the domains that /// best match the specified uri, else it returns null. - internal IEnumerable DomainsForNode(int nodeId, Uri current, bool excludeDefault = true) + internal static IEnumerable DomainsForNode(IDomainCache domainCache, ISiteDomainHelper siteDomainHelper, int nodeId, Uri current, bool excludeDefault = true) { // be safe if (nodeId <= 0) return null; // get the domains on that node - var domains = _domainCache.GetAssigned(nodeId, false).ToArray(); + var domains = domainCache.GetAssigned(nodeId).ToArray(); // none? if (domains.Length == 0) @@ -90,7 +121,7 @@ namespace Umbraco.Web.Routing var domainAndUris = SelectDomains(domains, current).ToArray(); // filter - return _siteDomainHelper.MapDomains(domainAndUris, current, excludeDefault, null, _domainCache.DefaultCulture).ToArray(); + return siteDomainHelper.MapDomains(domainAndUris, current, excludeDefault, null, domainCache.DefaultCulture).ToArray(); } #endregion @@ -252,7 +283,7 @@ namespace Umbraco.Web.Routing } /// - /// Parses a domain name into a URI. + /// Parses a domain name into a URI. /// /// The domain name to parse /// The currently requested URI. If the domain name is relative, the authority of URI will be used. diff --git a/src/Umbraco.Web/Routing/PublishedRouter.cs b/src/Umbraco.Web/Routing/PublishedRouter.cs index aeb329a9e9..2e772cb175 100644 --- a/src/Umbraco.Web/Routing/PublishedRouter.cs +++ b/src/Umbraco.Web/Routing/PublishedRouter.cs @@ -284,7 +284,7 @@ namespace Umbraco.Web.Routing var defaultCulture = domainsCache.DefaultCulture; // try to find a domain matching the current request - var domainAndUri = DomainHelper.SelectDomain(domains, request.Uri, defaultCulture: defaultCulture); + var domainAndUri = DomainUtilities.SelectDomain(domains, request.Uri, defaultCulture: defaultCulture); // handle domain - always has a contentId and a culture if (domainAndUri != null) @@ -328,7 +328,7 @@ namespace Umbraco.Web.Routing var nodePath = request.PublishedContent.Path; _logger.Debug("{TracePrefix}Path={NodePath}", tracePrefix, nodePath); var rootNodeId = request.HasDomain ? request.Domain.ContentId : (int?)null; - var domain = DomainHelper.FindWildcardDomainInPath(request.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), nodePath, rootNodeId); + var domain = DomainUtilities.FindWildcardDomainInPath(request.UmbracoContext.PublishedSnapshot.Domains.GetAll(true), nodePath, rootNodeId); // always has a contentId and a culture if (domain != null) diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 42a1a766e5..28337e6d2c 100755 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1137,7 +1137,7 @@ - + diff --git a/src/Umbraco.Web/UmbracoContext.cs b/src/Umbraco.Web/UmbracoContext.cs index a39535ba6e..04052e8be3 100644 --- a/src/Umbraco.Web/UmbracoContext.cs +++ b/src/Umbraco.Web/UmbracoContext.cs @@ -3,12 +3,10 @@ using System.Collections.Generic; using System.Web; using Umbraco.Core; using Umbraco.Core.Configuration; -using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Models.PublishedContent; using Umbraco.Web.PublishedCache; using Umbraco.Web.Routing; -using Umbraco.Web.Runtime; using Umbraco.Web.Security; namespace Umbraco.Web @@ -20,7 +18,6 @@ namespace Umbraco.Web { private readonly IGlobalSettings _globalSettings; private readonly Lazy _publishedSnapshot; - private DomainHelper _domainHelper; private string _previewToken; private bool? _previewing; @@ -107,9 +104,6 @@ namespace Umbraco.Web /// public IPublishedSnapshot PublishedSnapshot => _publishedSnapshot.Value; - // for unit tests - internal bool HasPublishedSnapshot => _publishedSnapshot.IsValueCreated; - /// /// Gets the published content cache. /// @@ -162,20 +156,6 @@ namespace Umbraco.Web /// public IVariationContextAccessor VariationContextAccessor { get; } - /// - /// Creates and caches an instance of a DomainHelper - /// - /// - /// We keep creating new instances of DomainHelper, it would be better if we didn't have to do that so instead we can - /// have one attached to the UmbracoContext. This method accepts an external ISiteDomainHelper otherwise the UmbracoContext - /// ctor will have to have another parameter added only for this one method which is annoying and doesn't make a ton of sense - /// since the UmbracoContext itself doesn't use this. - /// - /// TODO: The alternative is to have a IDomainHelperAccessor singleton which is cached per UmbracoContext - /// - internal DomainHelper GetDomainHelper(ISiteDomainHelper siteDomainHelper) - => _domainHelper ?? (_domainHelper = new DomainHelper(PublishedSnapshot.Domains, siteDomainHelper)); - /// /// Gets a value indicating whether the request has debugging enabled /// diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 1c6eb28b92..6e7b05691e 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -809,11 +809,5 @@ namespace Umbraco.Web } #endregion - - - - - - } }