using System; using System.Collections.Generic; using System.Linq; using Examine; using Umbraco.Core; using Umbraco.Core.Mapping; using Umbraco.Core.Models; using Umbraco.Core.Models.Entities; using Umbraco.Core.Persistence; using Umbraco.Core.Services; using Umbraco.Examine; using Umbraco.Web.Models.ContentEditing; using Umbraco.Web.Models.Mapping; using Umbraco.Web.Routing; using Umbraco.Web.Trees; namespace Umbraco.Web.Search { /// /// Used for internal Umbraco implementations of /// public class UmbracoTreeSearcher { private readonly ILocalizationService _languageService; private readonly IEntityService _entityService; private readonly UmbracoMapper _mapper; private readonly ISqlContext _sqlContext; private readonly IBackOfficeExamineSearcher _backOfficeExamineSearcher; private readonly IPublishedUrlProvider _publishedUrlProvider; public UmbracoTreeSearcher( ILocalizationService languageService, IEntityService entityService, UmbracoMapper mapper, ISqlContext sqlContext, IBackOfficeExamineSearcher backOfficeExamineSearcher, IPublishedUrlProvider publishedUrlProvider) { _languageService = languageService; _entityService = entityService; _mapper = mapper; _sqlContext = sqlContext; _backOfficeExamineSearcher = backOfficeExamineSearcher; _publishedUrlProvider = publishedUrlProvider; } /// /// Searches Examine for results based on the entity type /// /// /// /// /// /// /// A starting point for the search, generally a node id, but for members this is a member type alias /// /// /// /// If set to true, user and group start node permissions will be ignored. /// public IEnumerable ExamineSearch( string query, UmbracoEntityTypes entityType, int pageSize, long pageIndex, out long totalFound, string culture = null, string searchFrom = null, bool ignoreUserStartNodes = false) { var pagedResult = _backOfficeExamineSearcher.Search(query, entityType, pageSize, pageIndex, out totalFound, searchFrom, ignoreUserStartNodes); switch (entityType) { case UmbracoEntityTypes.Member: return MemberFromSearchResults(pagedResult.ToArray()); case UmbracoEntityTypes.Media: return MediaFromSearchResults(pagedResult); case UmbracoEntityTypes.Document: return ContentFromSearchResults(pagedResult, culture); default: throw new NotSupportedException("The " + typeof(UmbracoTreeSearcher) + " currently does not support searching against object type " + entityType); } } /// /// Searches with the for results based on the entity type /// /// /// /// /// /// /// /// public IEnumerable EntitySearch(UmbracoObjectTypes objectType, string query, int pageSize, long pageIndex, out long totalFound, string searchFrom = null) { //if it's a GUID, match it Guid.TryParse(query, out var g); var results = _entityService.GetPagedDescendants(objectType, pageIndex, pageSize, out totalFound, filter: _sqlContext.Query().Where(x => x.Name.Contains(query) || x.Key == g)); return _mapper.MapEnumerable(results); } /// /// Returns a collection of entities for media based on search results /// /// /// private IEnumerable MemberFromSearchResults(IEnumerable results) { //add additional data foreach (var result in results) { var m = _mapper.Map(result); //if no icon could be mapped, it will be set to document, so change it to picture if (m.Icon == Constants.Icons.DefaultIcon) { m.Icon = Constants.Icons.Member; } if (result.Values.ContainsKey("email") && result.Values["email"] != null) { m.AdditionalData["Email"] = result.Values["email"]; } if (result.Values.ContainsKey(UmbracoExamineFieldNames.NodeKeyFieldName) && result.Values[UmbracoExamineFieldNames.NodeKeyFieldName] != null) { if (Guid.TryParse(result.Values[UmbracoExamineFieldNames.NodeKeyFieldName], out var key)) { m.Key = key; } } yield return m; } } /// /// Returns a collection of entities for media based on search results /// /// /// private IEnumerable MediaFromSearchResults(IEnumerable results) => _mapper.Map>(results); /// /// Returns a collection of entities for content based on search results /// /// /// /// private IEnumerable ContentFromSearchResults(IEnumerable results, string culture = null) { var defaultLang = _languageService.GetDefaultLanguageIsoCode(); foreach (var result in results) { var entity = _mapper.Map(result, context => { if(culture != null) { context.SetCulture(culture); } } ); var intId = entity.Id.TryConvertTo(); if (intId.Success) { //if it varies by culture, return the default language URL if (result.Values.TryGetValue(UmbracoExamineFieldNames.VariesByCultureFieldName, out var varies) && varies == "y") { entity.AdditionalData["Url"] = _publishedUrlProvider.GetUrl(intId.Result, culture: culture ?? defaultLang); } else { entity.AdditionalData["Url"] = _publishedUrlProvider.GetUrl(intId.Result); } } yield return entity; } } } }