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;