diff --git a/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs b/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs new file mode 100644 index 0000000000..95bb1fd92c --- /dev/null +++ b/src/Umbraco.Web.Common/DependencyInjection/StaticServiceProvider.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel; + +namespace Umbraco.Cms.Web.Common.DependencyInjection +{ + /// + /// INTERNAL Service locator. Should only be used if no other ways exist. + /// + /// + /// It is created with only two goals in mind + /// 1) Continue to have the same extension methods on IPublishedContent and IPublishedElement as in V8. To make migration easier. + /// 2) To have a tool to avoid breaking changes in minor versions. All methods using this should in theory be obsolete. + /// + /// Keep in mind, everything this is used, the code becomes basically untestable. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static class StaticServiceProvider + { + /// + /// The service locator. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + internal static IServiceProvider Instance { get; set; } + } +} diff --git a/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs b/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs index d843bfb4aa..f8ca73e283 100644 --- a/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs +++ b/src/Umbraco.Web.Common/DependencyInjection/UmbracoStartupFilter.cs @@ -19,6 +19,7 @@ namespace Umbraco.Cms.Web.Common.DependencyInjection public Action Configure(Action next) => app => { + StaticServiceProvider.Instance = app.ApplicationServices; _options.Value.PreUmbracoPipeline(app); app.UseUmbraco(); diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs new file mode 100644 index 0000000000..92456813f8 --- /dev/null +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedContentExtensions.cs @@ -0,0 +1,134 @@ +using System; +using System.Collections.Generic; +using Examine; +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Core.Routing; +using Umbraco.Cms.Core.Services; +using Umbraco.Cms.Core.Web; +using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Extensions; + +namespace Umbraco.FriendlyExtensions +{ + public static class FriendlyPublishedContentExtensions + { + private static IVariationContextAccessor VariationContextAccessor { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + private static IPublishedModelFactory PublishedModelFactory { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + private static IPublishedUrlProvider PublishedUrlProvider { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + private static IUserService UserService { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + private static IUmbracoContextAccessor UmbracoContextAccessor { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + private static ISiteDomainHelper SiteDomainHelper { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + private static IExamineManager ExamineManager { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + + /// + /// Creates a strongly typed published content model for an internal published content. + /// + /// The internal published content. + /// The strongly typed published content model. + public static IPublishedContent CreateModel( + this IPublishedContent content) + => content.CreateModel(PublishedModelFactory); + + /// + /// Gets the name of the content item. + /// + /// The content item. + /// The specific culture to get the name for. If null is used the current culture is used (Default is null). + public static string Name( + this IPublishedContent content, + string culture = null) + => content.Name(VariationContextAccessor, culture); + + /// + /// Gets the URL segment of the content item. + /// + /// The content item. + /// The specific culture to get the URL segment for. If null is used the current culture is used (Default is null). + public static string UrlSegment( + this IPublishedContent content, + string culture = null) + => content.UrlSegment(VariationContextAccessor, culture); + + /// + /// Gets the url for a media. + /// + /// The content item. + /// The culture (use current culture by default). + /// The url mode (use site configuration by default). + /// The alias of the property (use 'umbracoFile' by default). + /// The url for the media. + /// + /// The value of this property is contextual. It depends on the 'current' request uri, + /// if any. In addition, when the content type is multi-lingual, this is the url for the + /// specified culture. Otherwise, it is the invariant url. + /// + public static string MediaUrl( + this IPublishedContent content, + string culture = null, + UrlMode mode = UrlMode.Default, + string propertyAlias = Constants.Conventions.Media.File) + => content.MediaUrl(PublishedUrlProvider, culture, mode, propertyAlias); + + /// + /// Gets the name of the content item creator. + /// + /// The content item. + public static string CreatorName(this IPublishedContent content) => + content.CreatorName(UserService); + + /// + /// Gets the name of the content item writer. + /// + /// The content item. + public static string WriterName(this IPublishedContent content) => + content.WriterName(UserService); + + /// + /// 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) + => content.GetCultureFromDomains(UmbracoContextAccessor, SiteDomainHelper, current); + + + public static IEnumerable SearchDescendants( + this IPublishedContent content, + string term, + string indexName = null) + => content.SearchDescendants(ExamineManager, UmbracoContextAccessor, term, indexName); + + + public static IEnumerable SearchChildren( + this IPublishedContent content, + string term, + string indexName = null) + => content.SearchChildren(ExamineManager, UmbracoContextAccessor, term, indexName); + + + } +} diff --git a/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs new file mode 100644 index 0000000000..d99220e33b --- /dev/null +++ b/src/Umbraco.Web.Common/Extensions/FriendlyPublishedElementExtensions.cs @@ -0,0 +1,75 @@ +using Microsoft.Extensions.DependencyInjection; +using Umbraco.Cms.Core.Models.PublishedContent; +using Umbraco.Cms.Web.Common.DependencyInjection; +using Umbraco.Extensions; + +namespace Umbraco.FriendlyExtensions +{ + public static class FriendlyPublishedElementExtensions + { + private static IPublishedValueFallback PublishedValueFallback { get; } = + StaticServiceProvider.Instance.GetRequiredService(); + + /// + /// Gets the value of a content's property identified by its alias. + /// + /// The content. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// The default value. + /// The value of the content's property identified by the alias, if it exists, otherwise a default value. + /// + /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. + /// If no property with the specified alias exists, or if the property has no value, returns . + /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. + /// The alias is case-insensitive. + /// + public static object Value( + this IPublishedElement content, + string alias, + string culture = null, + string segment = null, + Fallback fallback = default, + object defaultValue = default) + => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue); + + /// + /// Gets the value of a content's property identified by its alias, converted to a specified type. + /// + /// The target property type. + /// The content. + /// The property alias. + /// The variation language. + /// The variation segment. + /// Optional fallback strategy. + /// The default value. + /// The value of the content's property identified by the alias, converted to the specified type. + /// + /// The value comes from IPublishedProperty field Value ie it is suitable for use when rendering content. + /// If no property with the specified alias exists, or if the property has no value, or if it could not be converted, returns default(T). + /// If eg a numeric property wants to default to 0 when value source is empty, this has to be done in the converter. + /// The alias is case-insensitive. + /// + public static T Value( + this IPublishedElement content, + string alias, + string culture = null, + string segment = null, + Fallback fallback = default, + T defaultValue = default) + => content.Value(PublishedValueFallback, alias, culture, segment, fallback, defaultValue); + + /// + /// Gets a value indicating whether the content is visible. + /// + /// The content. + /// A value indicating whether the content is visible. + /// A content is not visible if it has an umbracoNaviHide property with a value of "1". Otherwise, + /// the content is visible. + public static bool IsVisible(this IPublishedElement content) => content.IsVisible(PublishedValueFallback); + + + } +} diff --git a/src/Umbraco.Web.Website/Extensions/PublishedContentExtensions.cs b/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs similarity index 99% rename from src/Umbraco.Web.Website/Extensions/PublishedContentExtensions.cs rename to src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs index c33d5e6ef3..c02e609372 100644 --- a/src/Umbraco.Web.Website/Extensions/PublishedContentExtensions.cs +++ b/src/Umbraco.Web.Common/Extensions/PublishedContentExtensions.cs @@ -3,12 +3,12 @@ using System.Collections.Generic; using System.Web; using Examine; using Microsoft.AspNetCore.Html; +using Umbraco.Cms.Core; using Umbraco.Cms.Core.Models.PublishedContent; using Umbraco.Cms.Core.Routing; using Umbraco.Cms.Core.Services; using Umbraco.Cms.Core.Web; using Umbraco.Cms.Infrastructure.Examine; -using Constants = Umbraco.Cms.Core.Constants; namespace Umbraco.Extensions {