public IEnumerable <IPublishedContent> ConvertSearchResultToPublishedContentWithTemplate( IEnumerable <SearchResult> rawSearchResults, IPublishedContentCache cache, UmbracoContext context) { //remove duplicated nodes/ids - fixed with hashset var nodesWithOutDuplicates = new HashSet <IPublishedContent>(); var excludedDocTypesAliases = new HashSet <string>(_configHelper.GetValue("SiteSearchExcludedDocTypes").Split(',')); //I would know that it's under the correct Language because of the parent ID of the IndexSet var searchResults = rawSearchResults.ToList(); foreach (var r in searchResults) { var content = cache.GetById(context, false, r.Id); if (content != null) { IPublishedContent nodeToAdd = content; if (content.TemplateId == 0) { nodeToAdd = _umbracoTree.GetFirstParentWithTemplate(content); } if (nodeToAdd != null && !excludedDocTypesAliases.Contains(nodeToAdd.DocumentTypeAlias)) { nodesWithOutDuplicates.Add(nodeToAdd); } } } return(nodesWithOutDuplicates.ToList()); }
private void StoreOldRoute(IContent entity, OldRoutesDictionary oldRoutes) { if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out IPublishedSnapshot? publishedSnapshot)) { return; } IPublishedContentCache?contentCache = publishedSnapshot?.Content; IPublishedContent? entityContent = contentCache?.GetById(entity.Id); if (entityContent is null) { return; } // get the default affected cultures by going up the tree until we find the first culture variant entity (default to no cultures) var defaultCultures = entityContent.AncestorsOrSelf().FirstOrDefault(a => a.Cultures.Any())?.Cultures.Keys .ToArray() ?? Array.Empty <string>(); foreach (IPublishedContent publishedContent in entityContent.DescendantsOrSelf(_variationContextAccessor)) { // if this entity defines specific cultures, use those instead of the default ones IEnumerable <string> cultures = publishedContent.Cultures.Any() ? publishedContent.Cultures.Keys : defaultCultures; foreach (var culture in cultures) { var route = contentCache?.GetRouteById(publishedContent.Id, culture); if (!IsNotRoute(route)) { oldRoutes[new ContentIdAndCulture(publishedContent.Id, culture)] = new ContentKeyAndOldRoute(publishedContent.Key, route !); } else if (string.IsNullOrEmpty(culture)) { // Retry using all languages, if this is invariant but has a variant ancestor var languages = _localizationService.GetAllLanguages(); foreach (var language in languages) { route = contentCache?.GetRouteById(publishedContent.Id, language.IsoCode); if (!IsNotRoute(route)) { oldRoutes[new ContentIdAndCulture(publishedContent.Id, language.IsoCode)] = new ContentKeyAndOldRoute(publishedContent.Key, route !); } } } } } }
private void StoreOldRoute(IContent entity, OldRoutesDictionary oldRoutes) { if (!_publishedSnapshotAccessor.TryGetPublishedSnapshot(out var publishedSnapshot)) { return; } IPublishedContentCache?contentCache = publishedSnapshot?.Content; IPublishedContent? entityContent = contentCache?.GetById(entity.Id); if (entityContent is null) { return; } // get the default affected cultures by going up the tree until we find the first culture variant entity (default to no cultures) var defaultCultures = entityContent.AncestorsOrSelf()?.FirstOrDefault(a => a.Cultures.Any())?.Cultures.Keys.ToArray() ?? Array.Empty <string>(); foreach (IPublishedContent publishedContent in entityContent.DescendantsOrSelf(_variationContextAccessor)) { // if this entity defines specific cultures, use those instead of the default ones IEnumerable <string> cultures = publishedContent.Cultures.Any() ? publishedContent.Cultures.Keys : defaultCultures; foreach (var culture in cultures) { var route = contentCache?.GetRouteById(publishedContent.Id, culture); if (IsNotRoute(route)) { continue; } oldRoutes[new ContentIdAndCulture(publishedContent.Id, culture)] = new ContentKeyAndOldRoute(publishedContent.Key, route !); } } }
private IPublishedContent?FindContentByAlias(IPublishedContentCache?cache, int rootNodeId, string?culture, string alias) { if (alias == null) { throw new ArgumentNullException(nameof(alias)); } // the alias may be "foo/bar" or "/foo/bar" // there may be spaces as in "/foo/bar, /foo/nil" // these should probably be taken care of earlier on // TODO: can we normalize the values so that they contain no whitespaces, and no leading slashes? // and then the comparisons in IsMatch can be way faster - and allocate way less strings const string propertyAlias = Constants.Conventions.Content.UrlAlias; var test1 = alias.TrimStart(Constants.CharArrays.ForwardSlash) + ","; var test2 = ",/" + test1; // test2 is ",/alias," test1 = "," + test1; // test1 is ",alias," bool IsMatch(IPublishedContent c, string a1, string a2) { // this basically implements the original XPath query ;-( // // "//* [@isDoc and (" + // "contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',{0},')" + // " or contains(concat(',',translate(umbracoUrlAlias, ' ', ''),','),',/{0},')" + // ")]" if (!c.HasProperty(propertyAlias)) { return(false); } IPublishedProperty?p = c.GetProperty(propertyAlias); var varies = p !.PropertyType?.VariesByCulture(); string?v; if (varies ?? false) { if (!c.HasCulture(culture)) { return(false); } v = c.Value <string>(_publishedValueFallback, propertyAlias, culture); } else { v = c.Value <string>(_publishedValueFallback, propertyAlias); } if (string.IsNullOrWhiteSpace(v)) { return(false); } v = "," + v.Replace(" ", string.Empty) + ","; return(v.InvariantContains(a1) || v.InvariantContains(a2)); } // TODO: even with Linq, what happens below has to be horribly slow // but the only solution is to entirely refactor URL providers to stop being dynamic if (rootNodeId > 0) { IPublishedContent?rootNode = cache?.GetById(rootNodeId); return(rootNode?.Descendants(_variationContextAccessor).FirstOrDefault(x => IsMatch(x, test1, test2))); } if (cache is not null) { foreach (IPublishedContent rootContent in cache.GetAtRoot()) { IPublishedContent?c = rootContent.DescendantsOrSelf(_variationContextAccessor).FirstOrDefault(x => IsMatch(x, test1, test2)); if (c != null) { return(c); } } } return(null); }