From 9e89e184928ec9d0e87492fc9b156fe87b9ca08b Mon Sep 17 00:00:00 2001 From: Andy Butland Date: Fri, 31 Jan 2020 15:33:31 +0100 Subject: [PATCH] Migrated various IPublishedContent extension methods from web to core, removin use of service location. Kept the original methods passing through to the core ones, providing the service located dependencies. Used one of these migrated methods in the Umbraco.Infrastructure.PublishedCache project. --- .../PublishedContentExtensions.cs | 713 +++++++++++++++++- .../PublishedElementExtensions.cs | 27 + .../PublishedCacheBase.cs | 16 +- src/Umbraco.Web/PublishedContentExtensions.cs | 453 +---------- src/Umbraco.Web/PublishedElementExtensions.cs | 14 - .../Routing/RedirectTrackingComponent.cs | 1 + 6 files changed, 783 insertions(+), 441 deletions(-) create mode 100644 src/Umbraco.Abstractions/PublishedElementExtensions.cs diff --git a/src/Umbraco.Abstractions/PublishedContentExtensions.cs b/src/Umbraco.Abstractions/PublishedContentExtensions.cs index 11444a274b..53618ea632 100644 --- a/src/Umbraco.Abstractions/PublishedContentExtensions.cs +++ b/src/Umbraco.Abstractions/PublishedContentExtensions.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; -using Umbraco.Core.Composing; using Umbraco.Core.Models.PublishedContent; using Umbraco.Core.Services; +using Umbraco.Web.PublishedCache; namespace Umbraco.Core { @@ -101,7 +101,6 @@ namespace Umbraco.Core return culture != "" && content.Cultures.TryGetValue(culture, out var infos) ? infos.Date : DateTime.MinValue; } - /// /// Gets the children of the content item. /// @@ -137,6 +136,8 @@ namespace Umbraco.Core : children.Where(x => x.IsInvariantOrHasCulture(culture)); } + #region Writer and creator + public static string GetCreatorName(this IPublishedContent content, IUserService userService) { var user = userService.GetProfileById(content.CreatorId); @@ -148,5 +149,713 @@ namespace Umbraco.Core var user = userService.GetProfileById(content.WriterId); return user?.Name; } + + #endregion + + #region Axes: ancestors, ancestors-or-self + + // as per XPath 1.0 specs �2.2, + // - the ancestor axis contains the ancestors of the context node; the ancestors of the context node consist + // of the parent of context node and the parent's parent and so on; thus, the ancestor axis will always + // include the root node, unless the context node is the root node. + // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus, + // the ancestor axis will always include the root node. + // + // as per XPath 2.0 specs �3.2.1.1, + // - the ancestor axis is defined as the transitive closure of the parent axis; it contains the ancestors + // of the context node (the parent, the parent of the parent, and so on) - The ancestor axis includes the + // root node of the tree in which the context node is found, unless the context node is the root node. + // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus, + // the ancestor-or-self axis will always include the root node. + // + // the ancestor and ancestor-or-self axis are reverse axes ie they contain the context node or nodes that + // are before the context node in document order. + // + // document order is defined by �2.4.1 as: + // - the root node is the first node. + // - every node occurs before all of its children and descendants. + // - the relative order of siblings is the order in which they occur in the children property of their parent node. + // - children and descendants occur before following siblings. + + /// + /// Gets the ancestors of the content. + /// + /// The content. + /// The ancestors of the content, in down-top order. + /// Does not consider the content itself. + public static IEnumerable Ancestors(this IPublishedContent content) + { + return content.AncestorsOrSelf(false, null); + } + + /// + /// Gets the ancestors of the content, at a level lesser or equal to a specified level. + /// + /// The content. + /// The level. + /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order. + /// Does not consider the content itself. Only content that are "high enough" in the tree are returned. + public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel) + { + return content.AncestorsOrSelf(false, n => n.Level <= maxLevel); + } + + /// + /// Gets the ancestors of the content, of a specified content type. + /// + /// The content. + /// The content type. + /// The ancestors of the content, of the specified content type, in down-top order. + /// Does not consider the content itself. Returns all ancestors, of the specified content type. + public static IEnumerable Ancestors(this IPublishedContent content, string contentTypeAlias) + { + return content.AncestorsOrSelf(false, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias)); + } + + /// + /// Gets the ancestors of the content, of a specified content type. + /// + /// The content type. + /// The content. + /// The ancestors of the content, of the specified content type, in down-top order. + /// Does not consider the content itself. Returns all ancestors, of the specified content type. + public static IEnumerable Ancestors(this IPublishedContent content) + where T : class, IPublishedContent + { + return content.Ancestors().OfType(); + } + + /// + /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content type. + /// + /// The content type. + /// The content. + /// The level. + /// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified + /// content type, in down-top order. + /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the + /// specified content type, are returned. + public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel) + where T : class, IPublishedContent + { + return content.Ancestors(maxLevel).OfType(); + } + + /// + /// Gets the content and its ancestors. + /// + /// The content. + /// The content and its ancestors, in down-top order. + public static IEnumerable AncestorsOrSelf(this IPublishedContent content) + { + return content.AncestorsOrSelf(true, null); + } + + /// + /// Gets the content and its ancestors, at a level lesser or equal to a specified level. + /// + /// The content. + /// The level. + /// The content and its ancestors, at a level lesser or equal to the specified level, + /// in down-top order. + /// Only content that are "high enough" in the tree are returned. So it may or may not begin + /// with the content itself, depending on its level. + public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel) + { + return content.AncestorsOrSelf(true, n => n.Level <= maxLevel); + } + + /// + /// Gets the content and its ancestors, of a specified content type. + /// + /// The content. + /// The content type. + /// The content and its ancestors, of the specified content type, in down-top order. + /// May or may not begin with the content itself, depending on its content type. + public static IEnumerable AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias) + { + return content.AncestorsOrSelf(true, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias)); + } + + /// + /// Gets the content and its ancestors, of a specified content type. + /// + /// The content type. + /// The content. + /// The content and its ancestors, of the specified content type, in down-top order. + /// May or may not begin with the content itself, depending on its content type. + public static IEnumerable AncestorsOrSelf(this IPublishedContent content) + where T : class, IPublishedContent + { + return content.AncestorsOrSelf().OfType(); + } + + /// + /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content type. + /// + /// The content type. + /// The content. + /// The level. + /// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified + /// content type, in down-top order. + /// May or may not begin with the content itself, depending on its level and content type. + public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel) + where T : class, IPublishedContent + { + return content.AncestorsOrSelf(maxLevel).OfType(); + } + + /// + /// Gets the ancestor of the content, ie its parent. + /// + /// The content. + /// The ancestor of the content. + /// This method is here for consistency purposes but does not make much sense. + public static IPublishedContent Ancestor(this IPublishedContent content) + { + return content.Parent; + } + + /// + /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level. + /// + /// The content. + /// The level. + /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level. + /// Does not consider the content itself. May return null. + public static IPublishedContent Ancestor(this IPublishedContent content, int maxLevel) + { + return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel); + } + + /// + /// Gets the nearest ancestor of the content, of a specified content type. + /// + /// The content. + /// The content type alias. + /// The nearest (in down-top order) ancestor of the content, of the specified content type. + /// Does not consider the content itself. May return null. + public static IPublishedContent Ancestor(this IPublishedContent content, string contentTypeAlias) + { + return content.EnumerateAncestors(false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + } + + /// + /// Gets the nearest ancestor of the content, of a specified content type. + /// + /// The content type. + /// The content. + /// The nearest (in down-top order) ancestor of the content, of the specified content type. + /// Does not consider the content itself. May return null. + public static T Ancestor(this IPublishedContent content) + where T : class, IPublishedContent + { + return content.Ancestors().FirstOrDefault(); + } + + /// + /// Gets the nearest ancestor of the content, at the specified level and of the specified content type. + /// + /// The content type. + /// The content. + /// The level. + /// The ancestor of the content, at the specified level and of the specified content type. + /// Does not consider the content itself. If the ancestor at the specified level is + /// not of the specified type, returns null. + public static T Ancestor(this IPublishedContent content, int maxLevel) + where T : class, IPublishedContent + { + return content.Ancestors(maxLevel).FirstOrDefault(); + } + + /// + /// Gets the content or its nearest ancestor. + /// + /// The content. + /// The content. + /// This method is here for consistency purposes but does not make much sense. + public static IPublishedContent AncestorOrSelf(this IPublishedContent content) + { + return content; + } + + /// + /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level. + /// + /// The content. + /// The level. + /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level. + /// May or may not return the content itself depending on its level. May return null. + public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel) + { + return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel); + } + + /// + /// Gets the content or its nearest ancestor, of a specified content type. + /// + /// The content. + /// The content type. + /// The content or its nearest (in down-top order) ancestor, of the specified content type. + /// May or may not return the content itself depending on its content type. May return null. + public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias) + { + return content.EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + } + + /// + /// Gets the content or its nearest ancestor, of a specified content type. + /// + /// The content type. + /// The content. + /// The content or its nearest (in down-top order) ancestor, of the specified content type. + /// May or may not return the content itself depending on its content type. May return null. + public static T AncestorOrSelf(this IPublishedContent content) + where T : class, IPublishedContent + { + return content.AncestorsOrSelf().FirstOrDefault(); + } + + /// + /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified content type. + /// + /// The content type. + /// The content. + /// The level. + /// + public static T AncestorOrSelf(this IPublishedContent content, int maxLevel) + where T : class, IPublishedContent + { + return content.AncestorsOrSelf(maxLevel).FirstOrDefault(); + } + + public static IEnumerable AncestorsOrSelf(this IPublishedContent content, bool orSelf, Func func) + { + var ancestorsOrSelf = content.EnumerateAncestors(orSelf); + return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func); + } + + /// + /// Enumerates ancestors of the content, bottom-up. + /// + /// The content. + /// Indicates whether the content should be included. + /// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc). + internal static IEnumerable EnumerateAncestors(this IPublishedContent content, bool orSelf) + { + if (content == null) throw new ArgumentNullException(nameof(content)); + if (orSelf) yield return content; + while ((content = content.Parent) != null) + yield return content; + } + + #endregion + + #region Axes: descendants, descendants-or-self + + /// + /// Returns all DescendantsOrSelf of all content referenced + /// + /// + /// Variation context accessor. + /// + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// + /// + /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot + /// + public static IEnumerable DescendantsOrSelfOfType(this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string docTypeAlias, string culture = null) + { + return parentNodes.SelectMany(x => x.DescendantsOrSelfOfType(variationContextAccessor, docTypeAlias, culture)); + } + + /// + /// Returns all DescendantsOrSelf of all content referenced + /// + /// + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// + /// + /// This can be useful in order to return all nodes in an entire site by a type when combined with TypedContentAtRoot + /// + public static IEnumerable DescendantsOrSelf(this IEnumerable parentNodes, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return parentNodes.SelectMany(x => x.DescendantsOrSelf(variationContextAccessor, culture)); + } + + + // as per XPath 1.0 specs �2.2, + // - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus + // the descendant axis never contains attribute or namespace nodes. + // - the descendant-or-self axis contains the context node and the descendants of the context node. + // + // as per XPath 2.0 specs �3.2.1.1, + // - the descendant axis is defined as the transitive closure of the child axis; it contains the descendants of the context node (the + // children, the children of the children, and so on). + // - the descendant-or-self axis contains the context node and the descendants of the context node. + // + // the descendant and descendant-or-self axis are forward axes ie they contain the context node or nodes that are after the context + // node in document order. + // + // document order is defined by �2.4.1 as: + // - the root node is the first node. + // - every node occurs before all of its children and descendants. + // - the relative order of siblings is the order in which they occur in the children property of their parent node. + // - children and descendants occur before following siblings. + + public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return content.DescendantsOrSelf(variationContextAccessor, false, null, culture); + } + + public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + { + return content.DescendantsOrSelf(variationContextAccessor, false, p => p.Level >= level, culture); + } + + public static IEnumerable DescendantsOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.DescendantsOrSelf(variationContextAccessor, false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); + } + + public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.Descendants(variationContextAccessor, culture).OfType(); + } + + public static IEnumerable Descendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + where T : class, IPublishedContent + { + return content.Descendants(variationContextAccessor, level, culture).OfType(); + } + + public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return content.DescendantsOrSelf(variationContextAccessor, true, null, culture); + } + + public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + { + return content.DescendantsOrSelf(variationContextAccessor, true, p => p.Level >= level, culture); + } + + public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.DescendantsOrSelf(variationContextAccessor, true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); + } + + public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.DescendantsOrSelf(variationContextAccessor, culture).OfType(); + } + + public static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + where T : class, IPublishedContent + { + return content.DescendantsOrSelf(variationContextAccessor, level, culture).OfType(); + } + + public static IPublishedContent Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return content.Children(variationContextAccessor, culture).FirstOrDefault(); + } + + public static IPublishedContent Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + { + return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.Level == level); + } + + public static IPublishedContent DescendantOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + } + + public static T Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.EnumerateDescendants(variationContextAccessor, false, culture).FirstOrDefault(x => x is T) as T; + } + + public static T Descendant(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + where T : class, IPublishedContent + { + return content.Descendant(variationContextAccessor, level, culture) as T; + } + + public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return content; + } + + public static IPublishedContent DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + { + return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.Level == level); + } + + public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + } + + public static T DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.EnumerateDescendants(variationContextAccessor, true, culture).FirstOrDefault(x => x is T) as T; + } + + public static T DescendantOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, int level, string culture = null) + where T : class, IPublishedContent + { + return content.DescendantOrSelf(variationContextAccessor, level, culture) as T; + } + + internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, bool orSelf, Func func, string culture = null) + { + return content.EnumerateDescendants(variationContextAccessor, orSelf, culture).Where(x => func == null || func(x)); + } + + internal static IEnumerable EnumerateDescendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, bool orSelf, string culture = null) + { + if (content == null) throw new ArgumentNullException(nameof(content)); + if (orSelf) yield return content; + + foreach (var desc in content.Children(variationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(variationContextAccessor, culture))) + yield return desc; + } + + internal static IEnumerable EnumerateDescendants(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + yield return content; + + foreach (var desc in content.Children(variationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(variationContextAccessor, culture))) + yield return desc; + } + + #endregion + + #region Axes: children + + /// + /// Gets the children of the content, filtered by a predicate. + /// + /// The content. + /// Published snapshot instance + /// The predicate. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The children of the content, filtered by the predicate. + /// + /// Children are sorted by their sortOrder. + /// + public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string culture = null) + { + return content.Children(variationContextAccessor, culture).Where(predicate); + } + + /// + /// Gets the children of the content, of any of the specified types. + /// + /// The content. + /// Published snapshot instance + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The content type alias. + /// The children of the content, of any of the specified types. + public static IEnumerable ChildrenOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.Children(variationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); + } + + /// + /// Gets the children of the content, of a given content type. + /// + /// The content type. + /// The content. + /// Published snapshot instance + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The children of content, of the given content type. + /// + /// Children are sorted by their sortOrder. + /// + public static IEnumerable Children(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.Children(variationContextAccessor, culture).OfType(); + } + + public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return content.Children(variationContextAccessor, culture).FirstOrDefault(); + } + + /// + /// Gets the first child of the content, of a given content type. + /// + public static IPublishedContent FirstChildOfType(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture).FirstOrDefault(); + } + + public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string culture = null) + { + return content.Children(variationContextAccessor, predicate, culture).FirstOrDefault(); + } + + public static IPublishedContent FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Guid uniqueId, string culture = null) + { + return content.Children(variationContextAccessor, x => x.Key == uniqueId, culture).FirstOrDefault(); + } + + public static T FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.Children(variationContextAccessor, culture).FirstOrDefault(); + } + + public static T FirstChild(this IPublishedContent content, IVariationContextAccessor variationContextAccessor, Func predicate, string culture = null) + where T : class, IPublishedContent + { + return content.Children(variationContextAccessor, culture).FirstOrDefault(predicate); + } + + #endregion + + #region Axes: parent + + // Parent is native + + /// + /// Gets the parent of the content, of a given content type. + /// + /// The content type. + /// The content. + /// The parent of content, of the given content type, else null. + public static T Parent(this IPublishedContent content) + where T : class, IPublishedContent + { + if (content == null) throw new ArgumentNullException(nameof(content)); + return content.Parent as T; + } + + #endregion + + #region Axes: Siblings + + /// + /// Gets the siblings of the content. + /// + /// The content. + /// Published snapshot instance + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The siblings of the content. + /// + /// Note that in V7 this method also return the content node self. + /// + public static IEnumerable Siblings(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture).Where(x => x.Id != content.Id); + } + + /// + /// Gets the siblings of the content, of a given content type. + /// + /// The content. + /// Published snapshot instance + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The content type alias. + /// The siblings of the content, of the given content type. + /// + /// Note that in V7 this method also return the content node self. + /// + public static IEnumerable SiblingsOfType(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return SiblingsAndSelfOfType(content, publishedSnapshot, variationContextAccessor, contentTypeAlias, culture).Where(x => x.Id != content.Id); + } + + /// + /// Gets the siblings of the content, of a given content type. + /// + /// The content type. + /// The content. + /// Published snapshot instance + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The siblings of the content, of the given content type. + /// + /// Note that in V7 this method also return the content node self. + /// + public static IEnumerable Siblings(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return SiblingsAndSelf(content, publishedSnapshot, variationContextAccessor, culture).Where(x => x.Id != content.Id); + } + + /// + /// Gets the siblings of the content including the node itself to indicate the position. + /// + /// The content. + /// Published snapshot instance + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The siblings of the content including the node itself. + public static IEnumerable SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null) + { + return content.Parent != null + ? content.Parent.Children(variationContextAccessor, culture) + : publishedSnapshot.Content.GetAtRoot().WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + } + + /// + /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. + /// + /// The content. + /// Published snapshot instance + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The content type alias. + /// The siblings of the content including the node itself, of the given content type. + public static IEnumerable SiblingsAndSelfOfType(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string contentTypeAlias, string culture = null) + { + return content.Parent != null + ? content.Parent.ChildrenOfType(variationContextAccessor, contentTypeAlias, culture) + : publishedSnapshot.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + } + + /// + /// Gets the siblings of the content including the node itself to indicate the position, of a given content type. + /// + /// The content type. + /// The content. + /// Published snapshot instance + /// Variation context accessor. + /// The specific culture to filter for. If null is used the current culture is used. (Default is null) + /// The siblings of the content including the node itself, of the given content type. + public static IEnumerable SiblingsAndSelf(this IPublishedContent content, IPublishedSnapshot publishedSnapshot, IVariationContextAccessor variationContextAccessor, string culture = null) + where T : class, IPublishedContent + { + return content.Parent != null + ? content.Parent.Children(variationContextAccessor, culture) + : publishedSnapshot.Content.GetAtRoot().OfType().WhereIsInvariantOrHasCulture(variationContextAccessor, culture); + } + + #endregion + + #region Axes: custom + + /// + /// Gets the root content for this content. + /// + /// The content. + /// The 'site' content ie AncestorOrSelf(1). + public static IPublishedContent Root(this IPublishedContent content) + { + return content.AncestorOrSelf(1); + } + + #endregion } } diff --git a/src/Umbraco.Abstractions/PublishedElementExtensions.cs b/src/Umbraco.Abstractions/PublishedElementExtensions.cs new file mode 100644 index 0000000000..77b6b1516a --- /dev/null +++ b/src/Umbraco.Abstractions/PublishedElementExtensions.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core; +using Umbraco.Core.Models.PublishedContent; + +namespace Umbraco.Core +{ + /// + /// Provides extension methods for IPublishedElement. + /// + public static class PublishedElementExtensions + { + #region OfTypes + + // the .OfType() filter is nice when there's only one type + // this is to support filtering with multiple types + public static IEnumerable OfTypes(this IEnumerable contents, params string[] types) + where T : IPublishedElement + { + if (types == null || types.Length == 0) return Enumerable.Empty(); + + return contents.Where(x => types.InvariantContains(x.ContentType.Alias)); + } + + #endregion + } +} diff --git a/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs b/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs index 50ee48e1ba..28bc218f54 100644 --- a/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs +++ b/src/Umbraco.Infrastructure.PublishedCache/PublishedCacheBase.cs @@ -10,6 +10,13 @@ namespace Umbraco.Web.PublishedCache { abstract class PublishedCacheBase : IPublishedCache { + private readonly IVariationContextAccessor _variationContextAccessor; + + public PublishedCacheBase(IVariationContextAccessor variationContextAccessor) + { + _variationContextAccessor = variationContextAccessor ?? throw new ArgumentNullException(nameof(variationContextAccessor)); + + } public bool PreviewDefault { get; } protected PublishedCacheBase(bool previewDefault) @@ -94,14 +101,11 @@ namespace Umbraco.Web.PublishedCache public virtual IEnumerable GetByContentType(IPublishedContentType contentType) { - // TODO: move this extension method and get working again. - // this is probably not super-efficient, but works // some cache implementation may want to override it, though - return Enumerable.Empty(); - //return GetAtRoot() - // .SelectMany(x => x.DescendantsOrSelf()) - // .Where(x => x.ContentType.Id == contentType.Id); + return GetAtRoot() + .SelectMany(x => x.DescendantsOrSelf(_variationContextAccessor)) + .Where(x => x.ContentType.Id == contentType.Id); } } } diff --git a/src/Umbraco.Web/PublishedContentExtensions.cs b/src/Umbraco.Web/PublishedContentExtensions.cs index 0eaabe0ff6..fe42d5a165 100644 --- a/src/Umbraco.Web/PublishedContentExtensions.cs +++ b/src/Umbraco.Web/PublishedContentExtensions.cs @@ -365,305 +365,6 @@ namespace Umbraco.Web #endregion - #region Axes: ancestors, ancestors-or-self - - // as per XPath 1.0 specs �2.2, - // - the ancestor axis contains the ancestors of the context node; the ancestors of the context node consist - // of the parent of context node and the parent's parent and so on; thus, the ancestor axis will always - // include the root node, unless the context node is the root node. - // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus, - // the ancestor axis will always include the root node. - // - // as per XPath 2.0 specs �3.2.1.1, - // - the ancestor axis is defined as the transitive closure of the parent axis; it contains the ancestors - // of the context node (the parent, the parent of the parent, and so on) - The ancestor axis includes the - // root node of the tree in which the context node is found, unless the context node is the root node. - // - the ancestor-or-self axis contains the context node and the ancestors of the context node; thus, - // the ancestor-or-self axis will always include the root node. - // - // the ancestor and ancestor-or-self axis are reverse axes ie they contain the context node or nodes that - // are before the context node in document order. - // - // document order is defined by �2.4.1 as: - // - the root node is the first node. - // - every node occurs before all of its children and descendants. - // - the relative order of siblings is the order in which they occur in the children property of their parent node. - // - children and descendants occur before following siblings. - - /// - /// Gets the ancestors of the content. - /// - /// The content. - /// The ancestors of the content, in down-top order. - /// Does not consider the content itself. - public static IEnumerable Ancestors(this IPublishedContent content) - { - return content.AncestorsOrSelf(false, null); - } - - /// - /// Gets the ancestors of the content, at a level lesser or equal to a specified level. - /// - /// The content. - /// The level. - /// The ancestors of the content, at a level lesser or equal to the specified level, in down-top order. - /// Does not consider the content itself. Only content that are "high enough" in the tree are returned. - public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel) - { - return content.AncestorsOrSelf(false, n => n.Level <= maxLevel); - } - - /// - /// Gets the ancestors of the content, of a specified content type. - /// - /// The content. - /// The content type. - /// The ancestors of the content, of the specified content type, in down-top order. - /// Does not consider the content itself. Returns all ancestors, of the specified content type. - public static IEnumerable Ancestors(this IPublishedContent content, string contentTypeAlias) - { - return content.AncestorsOrSelf(false, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias)); - } - - /// - /// Gets the ancestors of the content, of a specified content type. - /// - /// The content type. - /// The content. - /// The ancestors of the content, of the specified content type, in down-top order. - /// Does not consider the content itself. Returns all ancestors, of the specified content type. - public static IEnumerable Ancestors(this IPublishedContent content) - where T : class, IPublishedContent - { - return content.Ancestors().OfType(); - } - - /// - /// Gets the ancestors of the content, at a level lesser or equal to a specified level, and of a specified content type. - /// - /// The content type. - /// The content. - /// The level. - /// The ancestors of the content, at a level lesser or equal to the specified level, and of the specified - /// content type, in down-top order. - /// Does not consider the content itself. Only content that are "high enough" in the trees, and of the - /// specified content type, are returned. - public static IEnumerable Ancestors(this IPublishedContent content, int maxLevel) - where T : class, IPublishedContent - { - return content.Ancestors(maxLevel).OfType(); - } - - /// - /// Gets the content and its ancestors. - /// - /// The content. - /// The content and its ancestors, in down-top order. - public static IEnumerable AncestorsOrSelf(this IPublishedContent content) - { - return content.AncestorsOrSelf(true, null); - } - - /// - /// Gets the content and its ancestors, at a level lesser or equal to a specified level. - /// - /// The content. - /// The level. - /// The content and its ancestors, at a level lesser or equal to the specified level, - /// in down-top order. - /// Only content that are "high enough" in the tree are returned. So it may or may not begin - /// with the content itself, depending on its level. - public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel) - { - return content.AncestorsOrSelf(true, n => n.Level <= maxLevel); - } - - /// - /// Gets the content and its ancestors, of a specified content type. - /// - /// The content. - /// The content type. - /// The content and its ancestors, of the specified content type, in down-top order. - /// May or may not begin with the content itself, depending on its content type. - public static IEnumerable AncestorsOrSelf(this IPublishedContent content, string contentTypeAlias) - { - return content.AncestorsOrSelf(true, n => n.ContentType.Alias.InvariantEquals(contentTypeAlias)); - } - - /// - /// Gets the content and its ancestors, of a specified content type. - /// - /// The content type. - /// The content. - /// The content and its ancestors, of the specified content type, in down-top order. - /// May or may not begin with the content itself, depending on its content type. - public static IEnumerable AncestorsOrSelf(this IPublishedContent content) - where T : class, IPublishedContent - { - return content.AncestorsOrSelf().OfType(); - } - - /// - /// Gets the content and its ancestor, at a lever lesser or equal to a specified level, and of a specified content type. - /// - /// The content type. - /// The content. - /// The level. - /// The content and its ancestors, at a level lesser or equal to the specified level, and of the specified - /// content type, in down-top order. - /// May or may not begin with the content itself, depending on its level and content type. - public static IEnumerable AncestorsOrSelf(this IPublishedContent content, int maxLevel) - where T : class, IPublishedContent - { - return content.AncestorsOrSelf(maxLevel).OfType(); - } - - /// - /// Gets the ancestor of the content, ie its parent. - /// - /// The content. - /// The ancestor of the content. - /// This method is here for consistency purposes but does not make much sense. - public static IPublishedContent Ancestor(this IPublishedContent content) - { - return content.Parent; - } - - /// - /// Gets the nearest ancestor of the content, at a lever lesser or equal to a specified level. - /// - /// The content. - /// The level. - /// The nearest (in down-top order) ancestor of the content, at a level lesser or equal to the specified level. - /// Does not consider the content itself. May return null. - public static IPublishedContent Ancestor(this IPublishedContent content, int maxLevel) - { - return content.EnumerateAncestors(false).FirstOrDefault(x => x.Level <= maxLevel); - } - - /// - /// Gets the nearest ancestor of the content, of a specified content type. - /// - /// The content. - /// The content type alias. - /// The nearest (in down-top order) ancestor of the content, of the specified content type. - /// Does not consider the content itself. May return null. - public static IPublishedContent Ancestor(this IPublishedContent content, string contentTypeAlias) - { - return content.EnumerateAncestors(false).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); - } - - /// - /// Gets the nearest ancestor of the content, of a specified content type. - /// - /// The content type. - /// The content. - /// The nearest (in down-top order) ancestor of the content, of the specified content type. - /// Does not consider the content itself. May return null. - public static T Ancestor(this IPublishedContent content) - where T : class, IPublishedContent - { - return content.Ancestors().FirstOrDefault(); - } - - /// - /// Gets the nearest ancestor of the content, at the specified level and of the specified content type. - /// - /// The content type. - /// The content. - /// The level. - /// The ancestor of the content, at the specified level and of the specified content type. - /// Does not consider the content itself. If the ancestor at the specified level is - /// not of the specified type, returns null. - public static T Ancestor(this IPublishedContent content, int maxLevel) - where T : class, IPublishedContent - { - return content.Ancestors(maxLevel).FirstOrDefault(); - } - - /// - /// Gets the content or its nearest ancestor. - /// - /// The content. - /// The content. - /// This method is here for consistency purposes but does not make much sense. - public static IPublishedContent AncestorOrSelf(this IPublishedContent content) - { - return content; - } - - /// - /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level. - /// - /// The content. - /// The level. - /// The content or its nearest (in down-top order) ancestor, at a level lesser or equal to the specified level. - /// May or may not return the content itself depending on its level. May return null. - public static IPublishedContent AncestorOrSelf(this IPublishedContent content, int maxLevel) - { - return content.EnumerateAncestors(true).FirstOrDefault(x => x.Level <= maxLevel); - } - - /// - /// Gets the content or its nearest ancestor, of a specified content type. - /// - /// The content. - /// The content type. - /// The content or its nearest (in down-top order) ancestor, of the specified content type. - /// May or may not return the content itself depending on its content type. May return null. - public static IPublishedContent AncestorOrSelf(this IPublishedContent content, string contentTypeAlias) - { - return content.EnumerateAncestors(true).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); - } - - /// - /// Gets the content or its nearest ancestor, of a specified content type. - /// - /// The content type. - /// The content. - /// The content or its nearest (in down-top order) ancestor, of the specified content type. - /// May or may not return the content itself depending on its content type. May return null. - public static T AncestorOrSelf(this IPublishedContent content) - where T : class, IPublishedContent - { - return content.AncestorsOrSelf().FirstOrDefault(); - } - - /// - /// Gets the content or its nearest ancestor, at a lever lesser or equal to a specified level, and of a specified content type. - /// - /// The content type. - /// The content. - /// The level. - /// - public static T AncestorOrSelf(this IPublishedContent content, int maxLevel) - where T : class, IPublishedContent - { - return content.AncestorsOrSelf(maxLevel).FirstOrDefault(); - } - - public static IEnumerable AncestorsOrSelf(this IPublishedContent content, bool orSelf, Func func) - { - var ancestorsOrSelf = content.EnumerateAncestors(orSelf); - return func == null ? ancestorsOrSelf : ancestorsOrSelf.Where(func); - } - - /// - /// Enumerates ancestors of the content, bottom-up. - /// - /// The content. - /// Indicates whether the content should be included. - /// Enumerates bottom-up ie walking up the tree (parent, grand-parent, etc). - internal static IEnumerable EnumerateAncestors(this IPublishedContent content, bool orSelf) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - if (orSelf) yield return content; - while ((content = content.Parent) != null) - yield return content; - } - - #endregion - #region Axes: descendants, descendants-or-self /// @@ -678,7 +379,7 @@ namespace Umbraco.Web /// public static IEnumerable DescendantsOrSelfOfType(this IEnumerable parentNodes, string docTypeAlias, string culture = null) { - return parentNodes.SelectMany(x => x.DescendantsOrSelfOfType(docTypeAlias, culture)); + return parentNodes.DescendantsOrSelfOfType(VariationContextAccessor, docTypeAlias, culture); } /// @@ -693,176 +394,110 @@ namespace Umbraco.Web public static IEnumerable DescendantsOrSelf(this IEnumerable parentNodes, string culture = null) where T : class, IPublishedContent { - return parentNodes.SelectMany(x => x.DescendantsOrSelf(culture)); + return parentNodes.DescendantsOrSelf(VariationContextAccessor, culture); } - - - // as per XPath 1.0 specs �2.2, - // - the descendant axis contains the descendants of the context node; a descendant is a child or a child of a child and so on; thus - // the descendant axis never contains attribute or namespace nodes. - // - the descendant-or-self axis contains the context node and the descendants of the context node. - // - // as per XPath 2.0 specs �3.2.1.1, - // - the descendant axis is defined as the transitive closure of the child axis; it contains the descendants of the context node (the - // children, the children of the children, and so on). - // - the descendant-or-self axis contains the context node and the descendants of the context node. - // - // the descendant and descendant-or-self axis are forward axes ie they contain the context node or nodes that are after the context - // node in document order. - // - // document order is defined by �2.4.1 as: - // - the root node is the first node. - // - every node occurs before all of its children and descendants. - // - the relative order of siblings is the order in which they occur in the children property of their parent node. - // - children and descendants occur before following siblings. - + public static IEnumerable Descendants(this IPublishedContent content, string culture = null) { - return content.DescendantsOrSelf(false, null, culture); + return content.Descendants(VariationContextAccessor, culture); } public static IEnumerable Descendants(this IPublishedContent content, int level, string culture = null) { - return content.DescendantsOrSelf(false, p => p.Level >= level, culture); + return content.Descendants(VariationContextAccessor, level, culture); } public static IEnumerable DescendantsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.DescendantsOrSelf(false, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); + return content.DescendantsOfType(VariationContextAccessor, contentTypeAlias, culture); } public static IEnumerable Descendants(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.Descendants(culture).OfType(); + return content.Descendants(VariationContextAccessor, culture); } public static IEnumerable Descendants(this IPublishedContent content, int level, string culture = null) where T : class, IPublishedContent { - return content.Descendants(level, culture).OfType(); + return content.Descendants(VariationContextAccessor, level, culture); } public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null) { - return content.DescendantsOrSelf(true, null, culture); + return content.DescendantsOrSelf(VariationContextAccessor, culture); } public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string culture = null) { - return content.DescendantsOrSelf(true, p => p.Level >= level, culture); + return content.DescendantsOrSelf(VariationContextAccessor, level, culture); } public static IEnumerable DescendantsOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.DescendantsOrSelf(true, p => p.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); + return content.DescendantsOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture); } public static IEnumerable DescendantsOrSelf(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.DescendantsOrSelf(culture).OfType(); + return content.DescendantsOrSelf(VariationContextAccessor, culture); } public static IEnumerable DescendantsOrSelf(this IPublishedContent content, int level, string culture = null) where T : class, IPublishedContent { - return content.DescendantsOrSelf(level, culture).OfType(); + return content.DescendantsOrSelf(VariationContextAccessor, level, culture); } public static IPublishedContent Descendant(this IPublishedContent content, string culture = null) { - return content.Children(VariationContextAccessor, culture).FirstOrDefault(); + return content.Descendant(VariationContextAccessor, culture); } public static IPublishedContent Descendant(this IPublishedContent content, int level, string culture = null) { - return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.Level == level); + return content.Descendant(VariationContextAccessor, level, culture); } public static IPublishedContent DescendantOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + return content.DescendantOfType(VariationContextAccessor, contentTypeAlias, culture); } public static T Descendant(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.EnumerateDescendants(false, culture).FirstOrDefault(x => x is T) as T; + return content.Descendant(VariationContextAccessor, culture); } public static T Descendant(this IPublishedContent content, int level, string culture = null) where T : class, IPublishedContent { - return content.Descendant(level, culture) as T; - } - - public static IPublishedContent DescendantOrSelf(this IPublishedContent content, string culture = null) - { - return content; + return content.Descendant(VariationContextAccessor, level, culture); } public static IPublishedContent DescendantOrSelf(this IPublishedContent content, int level, string culture = null) { - return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.Level == level); + return content.DescendantOrSelf(VariationContextAccessor, level, culture); } public static IPublishedContent DescendantOrSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias)); + return content.DescendantOrSelfOfType(VariationContextAccessor, contentTypeAlias, culture); } public static T DescendantOrSelf(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.EnumerateDescendants(true, culture).FirstOrDefault(x => x is T) as T; + return content.DescendantOrSelf(VariationContextAccessor, culture); } public static T DescendantOrSelf(this IPublishedContent content, int level, string culture = null) where T : class, IPublishedContent { - return content.DescendantOrSelf(level, culture) as T; - } - - internal static IEnumerable DescendantsOrSelf(this IPublishedContent content, bool orSelf, Func func, string culture = null) - { - return content.EnumerateDescendants(orSelf, culture).Where(x => func == null || func(x)); - } - - internal static IEnumerable EnumerateDescendants(this IPublishedContent content, bool orSelf, string culture = null) - { - if (content == null) throw new ArgumentNullException(nameof(content)); - if (orSelf) yield return content; - - foreach (var desc in content.Children(VariationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(culture))) - yield return desc; - } - - internal static IEnumerable EnumerateDescendants(this IPublishedContent content, string culture = null) - { - yield return content; - - foreach (var desc in content.Children(VariationContextAccessor, culture).SelectMany(x => x.EnumerateDescendants(culture))) - yield return desc; - } - - #endregion - - #region Axes: parent - - // Parent is native - - /// - /// Gets the parent of the content, of a given content type. - /// - /// The content type. - /// The content. - /// The parent of content, of the given content type, else null. - public static T Parent(this IPublishedContent content) - where T : class, IPublishedContent - { - if (content == null) throw new ArgumentNullException(nameof(content)); - return content.Parent as T; + return content.DescendantOrSelf(VariationContextAccessor, level, culture); } #endregion @@ -893,7 +528,7 @@ namespace Umbraco.Web /// The children of the content, of any of the specified types. public static IEnumerable ChildrenOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.Children(x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); + return content.Children(VariationContextAccessor, x => x.ContentType.Alias.InvariantEquals(contentTypeAlias), culture); } /// @@ -922,29 +557,29 @@ namespace Umbraco.Web /// public static IPublishedContent FirstChildOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.ChildrenOfType(contentTypeAlias, culture).FirstOrDefault(); + return content.ChildrenOfType(VariationContextAccessor, contentTypeAlias, culture).FirstOrDefault(); } public static IPublishedContent FirstChild(this IPublishedContent content, Func predicate, string culture = null) { - return content.Children(predicate, culture).FirstOrDefault(); + return content.Children(VariationContextAccessor, predicate, culture).FirstOrDefault(); } public static IPublishedContent FirstChild(this IPublishedContent content, Guid uniqueId, string culture = null) { - return content.Children(x=>x.Key == uniqueId, culture).FirstOrDefault(); + return content.Children(VariationContextAccessor, x => x.Key == uniqueId, culture).FirstOrDefault(); } public static T FirstChild(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.Children(culture).FirstOrDefault(); + return content.Children(VariationContextAccessor, culture).FirstOrDefault(); } public static T FirstChild(this IPublishedContent content, Func predicate, string culture = null) where T : class, IPublishedContent { - return content.Children(culture).FirstOrDefault(predicate); + return content.Children(VariationContextAccessor, culture).FirstOrDefault(predicate); } /// @@ -1040,7 +675,7 @@ namespace Umbraco.Web /// public static IEnumerable Siblings(this IPublishedContent content, string culture = null) { - return SiblingsAndSelf(content, culture).Where(x => x.Id != content.Id); + return content.Siblings(PublishedSnapshot, VariationContextAccessor, culture); } /// @@ -1055,7 +690,7 @@ namespace Umbraco.Web /// public static IEnumerable SiblingsOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return SiblingsAndSelfOfType(content, contentTypeAlias, culture).Where(x => x.Id != content.Id); + return content.SiblingsOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture); } /// @@ -1071,7 +706,7 @@ namespace Umbraco.Web public static IEnumerable Siblings(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return SiblingsAndSelf(content, culture).Where(x => x.Id != content.Id); + return content.Siblings(PublishedSnapshot, VariationContextAccessor, culture); } /// @@ -1082,9 +717,7 @@ namespace Umbraco.Web /// The siblings of the content including the node itself. public static IEnumerable SiblingsAndSelf(this IPublishedContent content, string culture = null) { - return content.Parent != null - ? content.Parent.Children(VariationContextAccessor, culture) - : PublishedSnapshot.Content.GetAtRoot().WhereIsInvariantOrHasCulture(VariationContextAccessor, culture); + return content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture); } /// @@ -1096,9 +729,7 @@ namespace Umbraco.Web /// The siblings of the content including the node itself, of the given content type. public static IEnumerable SiblingsAndSelfOfType(this IPublishedContent content, string contentTypeAlias, string culture = null) { - return content.Parent != null - ? content.Parent.ChildrenOfType(contentTypeAlias, culture) - : PublishedSnapshot.Content.GetAtRoot().OfTypes(contentTypeAlias).WhereIsInvariantOrHasCulture(VariationContextAccessor, culture); + return content.SiblingsAndSelfOfType(PublishedSnapshot, VariationContextAccessor, contentTypeAlias, culture); } /// @@ -1111,23 +742,7 @@ namespace Umbraco.Web public static IEnumerable SiblingsAndSelf(this IPublishedContent content, string culture = null) where T : class, IPublishedContent { - return content.Parent != null - ? content.Parent.Children(culture) - : PublishedSnapshot.Content.GetAtRoot().OfType().WhereIsInvariantOrHasCulture(VariationContextAccessor, culture); - } - - #endregion - - #region Axes: custom - - /// - /// Gets the root content for this content. - /// - /// The content. - /// The 'site' content ie AncestorOrSelf(1). - public static IPublishedContent Root(this IPublishedContent content) - { - return content.AncestorOrSelf(1); + return content.SiblingsAndSelf(PublishedSnapshot, VariationContextAccessor, culture); } #endregion diff --git a/src/Umbraco.Web/PublishedElementExtensions.cs b/src/Umbraco.Web/PublishedElementExtensions.cs index 982f5566f5..661c740d90 100644 --- a/src/Umbraco.Web/PublishedElementExtensions.cs +++ b/src/Umbraco.Web/PublishedElementExtensions.cs @@ -157,20 +157,6 @@ namespace Umbraco.Web #endregion - #region OfTypes - - // the .OfType() filter is nice when there's only one type - // this is to support filtering with multiple types - public static IEnumerable OfTypes(this IEnumerable contents, params string[] types) - where T : IPublishedElement - { - if (types == null || types.Length == 0) return Enumerable.Empty(); - - return contents.Where(x => types.InvariantContains(x.ContentType.Alias)); - } - - #endregion - #region IsSomething /// diff --git a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs index fcf6f55f44..dffb956b1a 100644 --- a/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs +++ b/src/Umbraco.Web/Routing/RedirectTrackingComponent.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Umbraco.Core; using Umbraco.Core.Composing; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Events;