public async Task <SearchModel> Handle(GetSearch request, CancellationToken cancellationToken) { if (request.Model == null) { request.Model = new SearchModel(); } var searchTerms = request.Model.q; if (searchTerms == null) { searchTerms = ""; } searchTerms = searchTerms.Trim(); if (request.Model.Box) { request.Model.sid = _catalogSettings.SearchByDescription; } if (request.Model.sid) { request.Model.adv = true; } //view/sorting/page size var options = await _mediator.Send(new GetViewSortSizeOptions() { Command = request.Command, PagingFilteringModel = request.Model.PagingFilteringContext, Language = request.Language, AllowCustomersToSelectPageSize = _catalogSettings.SearchPageAllowCustomersToSelectPageSize, PageSizeOptions = _catalogSettings.SearchPagePageSizeOptions, PageSize = _catalogSettings.SearchPageProductsPerPage }); request.Model.PagingFilteringContext = options.pagingFilteringModel; request.Command = options.command; string cacheKey = string.Format(CacheKeyConst.SEARCH_CATEGORIES_MODEL_KEY, request.Language.Id, string.Join(",", request.Customer.GetCustomerGroupIds()), request.Store.Id); var categories = await _cacheBase.GetAsync(cacheKey, async() => { var categoriesModel = new List <SearchModel.CategoryModel>(); //all categories var allCategories = await _categoryService.GetAllCategories(parentId: "", storeId: request.Store.Id); foreach (var c in allCategories) { //generate full category name (breadcrumb) string categoryBreadcrumb = ""; var breadcrumb = _categoryService.GetCategoryBreadCrumb(c, allCategories); for (int i = 0; i <= breadcrumb.Count - 1; i++) { categoryBreadcrumb += breadcrumb[i].GetTranslation(x => x.Name, request.Language.Id); if (i != breadcrumb.Count - 1) { categoryBreadcrumb += " >> "; } } categoriesModel.Add(new SearchModel.CategoryModel { Id = c.Id, Breadcrumb = categoryBreadcrumb }); } return(categoriesModel); }); if (categories.Any()) { //first empty entry request.Model.AvailableCategories.Add(new SelectListItem { Value = "", Text = _translationService.GetResource("Common.All") }); //all other categories foreach (var c in categories) { request.Model.AvailableCategories.Add(new SelectListItem { Value = c.Id.ToString(), Text = c.Breadcrumb, Selected = request.Model.cid == c.Id }); } } var collections = await _collectionService.GetAllCollections(); if (collections.Any()) { request.Model.AvailableCollections.Add(new SelectListItem { Value = "", Text = _translationService.GetResource("Common.All") }); foreach (var m in collections) { request.Model.AvailableCollections.Add(new SelectListItem { Value = m.Id.ToString(), Text = m.GetTranslation(x => x.Name, request.Language.Id), Selected = request.Model.mid == m.Id }); } } request.Model.asv = _vendorSettings.AllowSearchByVendor; if (request.Model.asv) { var vendors = await _vendorService.GetAllVendors(); if (vendors.Any()) { request.Model.AvailableVendors.Add(new SelectListItem { Value = "", Text = _translationService.GetResource("Common.All") }); foreach (var vendor in vendors) { request.Model.AvailableVendors.Add(new SelectListItem { Value = vendor.Id.ToString(), Text = vendor.GetTranslation(x => x.Name, request.Language.Id), Selected = request.Model.vid == vendor.Id }); } } } IPagedList <Product> products = new PagedList <Product>(new List <Product>(), 0, 1); if (request.IsSearchTermSpecified) { if (searchTerms.Length < _catalogSettings.ProductSearchTermMinimumLength) { request.Model.Warning = string.Format(_translationService.GetResource("Search.SearchTermMinimumLengthIsNCharacters"), _catalogSettings.ProductSearchTermMinimumLength); } else { var categoryIds = new List <string>(); string collectionId = ""; double?minPriceConverted = null; double?maxPriceConverted = null; bool searchInDescriptions = false; string vendorId = ""; if (request.Model.adv) { //advanced search var categoryId = request.Model.cid; if (!String.IsNullOrEmpty(categoryId)) { categoryIds.Add(categoryId); //include subcategories categoryIds.AddRange(await _mediator.Send(new GetChildCategoryIds() { ParentCategoryId = categoryId, Customer = request.Customer, Store = request.Store })); } collectionId = request.Model.mid; //min price if (!string.IsNullOrEmpty(request.Model.pf)) { double minPrice; if (double.TryParse(request.Model.pf, out minPrice)) { minPriceConverted = await _currencyService.ConvertToPrimaryStoreCurrency(minPrice, request.Currency); } } //max price if (!string.IsNullOrEmpty(request.Model.pt)) { double maxPrice; if (double.TryParse(request.Model.pt, out maxPrice)) { maxPriceConverted = await _currencyService.ConvertToPrimaryStoreCurrency(maxPrice, request.Currency); } } searchInDescriptions = request.Model.sid; if (request.Model.asv) { vendorId = request.Model.vid; } } var searchInProductTags = searchInDescriptions; IList <string> alreadyFilteredSpecOptionIds = await request.Model.PagingFilteringContext.SpecificationFilter.GetAlreadyFilteredSpecOptionIds (_httpContextAccessor, _specificationAttributeService); //products var searchproducts = (await _mediator.Send(new GetSearchProductsQuery() { LoadFilterableSpecificationAttributeOptionIds = !_catalogSettings.IgnoreFilterableSpecAttributeOption, CategoryIds = categoryIds, CollectionId = collectionId, Customer = request.Customer, StoreId = request.Store.Id, VisibleIndividuallyOnly = true, PriceMin = minPriceConverted, PriceMax = maxPriceConverted, Keywords = searchTerms, SearchDescriptions = searchInDescriptions, SearchSku = searchInDescriptions, SearchProductTags = searchInProductTags, FilteredSpecs = alreadyFilteredSpecOptionIds, LanguageId = request.Language.Id, OrderBy = (ProductSortingEnum)request.Command.OrderBy, PageIndex = request.Command.PageNumber - 1, PageSize = request.Command.PageSize, VendorId = vendorId })); request.Model.Products = (await _mediator.Send(new GetProductOverview() { Products = searchproducts.products, PrepareSpecificationAttributes = _catalogSettings.ShowSpecAttributeOnCatalogPages })).ToList(); request.Model.PagingFilteringContext.LoadPagedList(searchproducts.products); //specs await request.Model.PagingFilteringContext.SpecificationFilter.PrepareSpecsFilters(alreadyFilteredSpecOptionIds, searchproducts.filterableSpecificationAttributeOptionIds, _specificationAttributeService, _httpContextAccessor, _cacheBase, request.Language.Id); request.Model.NoResults = !request.Model.Products.Any(); //search term statistics if (!String.IsNullOrEmpty(searchTerms)) { var searchTerm = await _searchTermService.GetSearchTermByKeyword(searchTerms, request.Store.Id); if (searchTerm != null) { searchTerm.Count++; await _searchTermService.UpdateSearchTerm(searchTerm); } else { searchTerm = new SearchTerm { Keyword = searchTerms, StoreId = request.Store.Id, Count = 1 }; await _searchTermService.InsertSearchTerm(searchTerm); } } } } return(request.Model); }
public async Task <IList <SearchAutoCompleteModel> > Handle(GetSearchAutoComplete request, CancellationToken cancellationToken) { var model = new List <SearchAutoCompleteModel>(); var productNumber = _catalogSettings.ProductSearchAutoCompleteNumberOfProducts > 0 ? _catalogSettings.ProductSearchAutoCompleteNumberOfProducts : 10; var storeId = request.Store.Id; var categoryIds = new List <string>(); if (!string.IsNullOrEmpty(request.CategoryId)) { categoryIds.Add(request.CategoryId); if (_catalogSettings.ShowProductsFromSubcategoriesInSearchBox) { //include subcategories categoryIds.AddRange(await _mediator.Send(new GetChildCategoryIds() { ParentCategoryId = request.CategoryId, Customer = request.Customer, Store = request.Store })); } } var products = (await _mediator.Send(new GetSearchProductsQuery() { Customer = request.Customer, StoreId = storeId, Keywords = request.Term, CategoryIds = categoryIds, SearchSku = _catalogSettings.SearchBySku, SearchDescriptions = _catalogSettings.SearchByDescription, LanguageId = request.Language.Id, VisibleIndividuallyOnly = true, PageSize = productNumber })).products; var categories = new List <string>(); var manufacturers = new List <string>(); var storeurl = _webHelper.GetStoreLocation(); foreach (var item in products) { var pictureUrl = ""; if (_catalogSettings.ShowProductImagesInSearchAutoComplete) { var picture = item.ProductPictures.OrderBy(x => x.DisplayOrder).FirstOrDefault(); if (picture != null) { pictureUrl = await _pictureService.GetPictureUrl(picture.PictureId, _mediaSettings.AutoCompleteSearchThumbPictureSize); } } var rating = await _mediator.Send(new GetProductReviewOverview() { Language = request.Language, Product = item, Store = request.Store }); var price = await PreparePrice(item, request); model.Add(new SearchAutoCompleteModel() { SearchType = "Product", Label = item.GetLocalized(x => x.Name, request.Language.Id) ?? "", Desc = item.GetLocalized(x => x.ShortDescription, request.Language.Id) ?? "", PictureUrl = pictureUrl, AllowCustomerReviews = rating.AllowCustomerReviews, Rating = rating.TotalReviews > 0 ? (((rating.RatingSum * 100) / rating.TotalReviews) / 5) : 0, Price = price.Price, PriceWithDiscount = price.PriceWithDiscount, Url = $"{storeurl}{item.SeName}" }); foreach (var category in item.ProductCategories) { categories.Add(category.CategoryId); } foreach (var manufacturer in item.ProductManufacturers) { manufacturers.Add(manufacturer.ManufacturerId); } } foreach (var item in manufacturers.Distinct()) { var manufacturer = await _manufacturerService.GetManufacturerById(item); if (manufacturer != null && manufacturer.Published) { var allow = true; if (!_catalogSettings.IgnoreAcl) { if (!_aclService.Authorize(manufacturer)) { allow = false; } } if (!_catalogSettings.IgnoreStoreLimitations) { if (!_storeMappingService.Authorize(manufacturer)) { allow = false; } } if (allow) { var desc = ""; if (_catalogSettings.SearchByDescription) { desc = "&sid=true"; } model.Add(new SearchAutoCompleteModel() { SearchType = "Manufacturer", Label = manufacturer.GetLocalized(x => x.Name, request.Language.Id), Desc = "", PictureUrl = "", Url = $"{storeurl}search?q={request.Term}&adv=true&mid={item}{desc}" }); } } } foreach (var item in categories.Distinct()) { var category = await _categoryService.GetCategoryById(item); if (category != null && category.Published) { var allow = true; if (!_catalogSettings.IgnoreAcl) { if (!_aclService.Authorize(category)) { allow = false; } } if (!_catalogSettings.IgnoreStoreLimitations) { if (!_storeMappingService.Authorize(category)) { allow = false; } } if (allow) { var desc = ""; if (_catalogSettings.SearchByDescription) { desc = "&sid=true"; } model.Add(new SearchAutoCompleteModel() { SearchType = "Category", Label = category.GetLocalized(x => x.Name, request.Language.Id), Desc = "", PictureUrl = "", Url = $"{storeurl}search?q={request.Term}&adv=true&cid={item}{desc}" }); } } } if (_blogSettings.ShowBlogPostsInSearchAutoComplete) { var posts = await _blogService.GetAllBlogPosts(storeId : storeId, pageSize : productNumber, blogPostName : request.Term); foreach (var item in posts) { model.Add(new SearchAutoCompleteModel() { SearchType = "Blog", Label = item.GetLocalized(x => x.Title, request.Language.Id), Desc = "", PictureUrl = "", Url = $"{storeurl}{item.SeName}" }); } } //search term statistics if (!String.IsNullOrEmpty(request.Term) && _catalogSettings.SaveSearchAutoComplete) { var searchTerm = await _searchTermService.GetSearchTermByKeyword(request.Term, request.Store.Id); if (searchTerm != null) { searchTerm.Count++; await _searchTermService.UpdateSearchTerm(searchTerm); } else { searchTerm = new SearchTerm { Keyword = request.Term, StoreId = storeId, Count = 1 }; await _searchTermService.InsertSearchTerm(searchTerm); } } return(model); }
public override SearchModel PrepareSearchModel(SearchModel model, CatalogPagingFilteringModel command) { if (model == null) { throw new ArgumentNullException(nameof(model)); } var searchTerms = model.q ?? string.Empty; searchTerms = searchTerms.Trim(); //sorting PrepareSortingOptions(model.PagingFilteringContext, command); //view mode PrepareViewModes(model.PagingFilteringContext, command); //page size PreparePageSizeOptions(model.PagingFilteringContext, command, _catalogSettings.SearchPageAllowCustomersToSelectPageSize, _catalogSettings.SearchPagePageSizeOptions, _catalogSettings.SearchPageProductsPerPage); var categoriesModels = new List <SearchModel.CategoryModel>(); //all categories var allCategories = _categoryService.GetAllCategories(storeId: _storeContext.CurrentStore.Id); foreach (var c in allCategories) { //generate full category name (breadcrumb) var categoryBreadcrumb = string.Empty; var breadcrumb = _categoryService.GetCategoryBreadCrumb(c, allCategories); for (var i = 0; i <= breadcrumb.Count - 1; i++) { categoryBreadcrumb += _localizationService.GetLocalized(breadcrumb[i], x => x.Name); if (i != breadcrumb.Count - 1) { categoryBreadcrumb += " >> "; } } categoriesModels.Add(new SearchModel.CategoryModel { Id = c.Id, Breadcrumb = categoryBreadcrumb }); } if (categoriesModels.Any()) { //first empty entry model.AvailableCategories.Add(new SelectListItem { Value = "0", Text = _localizationService.GetResource("Common.All") }); //all other categories foreach (var c in categoriesModels) { model.AvailableCategories.Add(new SelectListItem { Value = c.Id.ToString(), Text = c.Breadcrumb, Selected = model.cid == c.Id }); } } var manufacturers = _manufacturerService.GetAllManufacturers(storeId: _storeContext.CurrentStore.Id); if (manufacturers.Any()) { model.AvailableManufacturers.Add(new SelectListItem { Value = "0", Text = _localizationService.GetResource("Common.All") }); foreach (var m in manufacturers) { model.AvailableManufacturers.Add(new SelectListItem { Value = m.Id.ToString(), Text = _localizationService.GetLocalized(m, x => x.Name), Selected = model.mid == m.Id }); } } model.asv = _vendorSettings.AllowSearchByVendor; if (model.asv) { var vendors = _vendorService.GetAllVendors(); if (vendors.Any()) { model.AvailableVendors.Add(new SelectListItem { Value = "0", Text = _localizationService.GetResource("Common.All") }); foreach (var vendor in vendors) { model.AvailableVendors.Add(new SelectListItem { Value = vendor.Id.ToString(), Text = _localizationService.GetLocalized(vendor, x => x.Name), Selected = model.vid == vendor.Id }); } } } IPagedList <Product> products = new PagedList <Product>(new List <Product>(), 0, 1); // only search if query string search keyword is set (used to avoid searching or displaying search term min length error message on /search page load) //we don't use "!string.IsNullOrEmpty(searchTerms)" in cases of "ProductSearchTermMinimumLength" set to 0 but searching by other parameters (e.g. category or price filter) var isSearchTermSpecified = _httpContextAccessor.HttpContext.Request.Query.ContainsKey("q"); if (isSearchTermSpecified) { if (searchTerms.Length < _catalogSettings.ProductSearchTermMinimumLength) { model.Warning = string.Format(_localizationService.GetResource("Search.SearchTermMinimumLengthIsNCharacters"), _catalogSettings.ProductSearchTermMinimumLength); } else { var categoryIds = new List <int>(); var manufacturerId = 0; decimal?minPriceConverted = null; decimal?maxPriceConverted = null; var searchInDescriptions = false; var vendorId = 0; if (model.adv) { //advanced search var categoryId = model.cid; if (categoryId > 0) { categoryIds.Add(categoryId); if (model.isc) { //include subcategories categoryIds.AddRange(_categoryService.GetChildCategoryIds(categoryId, _storeContext.CurrentStore.Id)); } } manufacturerId = model.mid; //min price if (!string.IsNullOrEmpty(model.pf)) { if (decimal.TryParse(model.pf, out decimal minPrice)) { minPriceConverted = _currencyService.ConvertToPrimaryStoreCurrency(minPrice, _workContext.WorkingCurrency); } } //max price if (!string.IsNullOrEmpty(model.pt)) { if (decimal.TryParse(model.pt, out decimal maxPrice)) { maxPriceConverted = _currencyService.ConvertToPrimaryStoreCurrency(maxPrice, _workContext.WorkingCurrency); } } if (model.asv) { vendorId = model.vid; } searchInDescriptions = model.sid; } //var searchInProductTags = false; var searchInProductTags = searchInDescriptions; /////////////////////////////////////////////////////// ////// Lucene Search ////////////////////////////////// /////////////////////////////////////////////////////// if (_luceneSettings.Enabled) { _luceneService.GetLuceneDirectory(); var luceneProducts = _luceneService.Search(model.q); products = new PagedList <Product>(luceneProducts.AsQueryable(), command.PageNumber - 1, command.PageSize); } else { //products products = _productService.SearchProducts( categoryIds: categoryIds, manufacturerId: manufacturerId, storeId: _storeContext.CurrentStore.Id, visibleIndividuallyOnly: true, priceMin: minPriceConverted, priceMax: maxPriceConverted, keywords: searchTerms, searchDescriptions: searchInDescriptions, searchProductTags: searchInProductTags, languageId: _workContext.WorkingLanguage.Id, orderBy: (ProductSortingEnum)command.OrderBy, pageIndex: command.PageNumber - 1, pageSize: command.PageSize, vendorId: vendorId); } ////////////////////////////////////////////////////////// model.Products = _productModelFactory.PrepareProductOverviewModels(products).ToList(); model.NoResults = !model.Products.Any(); //search term statistics if (!string.IsNullOrEmpty(searchTerms)) { var searchTerm = _searchTermService.GetSearchTermByKeyword(searchTerms, _storeContext.CurrentStore.Id); if (searchTerm != null) { searchTerm.Count++; _searchTermService.UpdateSearchTerm(searchTerm); } else { searchTerm = new SearchTerm { Keyword = searchTerms, StoreId = _storeContext.CurrentStore.Id, Count = 1 }; _searchTermService.InsertSearchTerm(searchTerm); } } //event _eventPublisher.Publish(new ProductSearchEvent { SearchTerm = searchTerms, SearchInDescriptions = searchInDescriptions, CategoryIds = categoryIds, ManufacturerId = manufacturerId, WorkingLanguageId = _workContext.WorkingLanguage.Id, VendorId = vendorId }); } } model.PagingFilteringContext.LoadPagedList(products); return(model); }
public virtual SearchModel PrepareSearchModel(SearchModel model, CatalogPagingFilteringModel command) { if (model == null) { throw new ArgumentNullException("model"); } var searchTerms = model.q; if (searchTerms == null) { searchTerms = ""; } searchTerms = searchTerms.Trim(); //sorting PrepareSortingOptions(model.PagingFilteringContext, command); //view mode PrepareViewModes(model.PagingFilteringContext, command); //page size PreparePageSizeOptions(model.PagingFilteringContext, command, _catalogSettings.SearchPageAllowCustomersToSelectPageSize, _catalogSettings.SearchPagePageSizeOptions, _catalogSettings.SearchPageProductsPerPage); string cacheKey = string.Format(ModelCacheEventConsumer.SEARCH_CATEGORIES_MODEL_KEY, _workContext.WorkingLanguage.Id, string.Join(",", _workContext.CurrentCustomer.GetCustomerRoleIds()), _storeContext.CurrentStore.Id); var categories = _cacheManager.Get(cacheKey, () => { var categoriesModel = new List <SearchModel.CategoryModel>(); //all categories var allCategories = _categoryService.GetAllCategories(storeId: _storeContext.CurrentStore.Id); foreach (var c in allCategories) { //generate full category name (breadcrumb) string categoryBreadcrumb = ""; var breadcrumb = c.GetCategoryBreadCrumb(allCategories, _aclService, _storeMappingService); for (int i = 0; i <= breadcrumb.Count - 1; i++) { categoryBreadcrumb += breadcrumb[i].GetLocalized(x => x.Name); if (i != breadcrumb.Count - 1) { categoryBreadcrumb += " >> "; } } categoriesModel.Add(new SearchModel.CategoryModel { Id = c.Id, Breadcrumb = categoryBreadcrumb }); } return(categoriesModel); }); if (categories.Any()) { //first empty entry model.AvailableCategories.Add(new SelectListItem { Value = "0", Text = _localizationService.GetResource("Common.All") }); //all other categories foreach (var c in categories) { model.AvailableCategories.Add(new SelectListItem { Value = c.Id.ToString(), Text = c.Breadcrumb, Selected = model.cid == c.Id }); } } IPagedList <Product> products = new PagedList <Product>(new List <Product>(), 0, 1); var isSearchTermSpecified = false; try { // only search if query string search keyword is set (used to avoid searching or displaying search term min length error message on /search page load) isSearchTermSpecified = _httpContext.Request.Params["q"] != null; } catch { //the "A potentially dangerous Request.QueryString value was detected from the client" exception could be thrown here when some wrong char is specified (e.g. <) //although we [ValidateInput(false)] attribute here we try to access "Request.Params" directly //that's why we do not re-throw it //just ensure that some search term is specified (0 length is not supported inthis case) isSearchTermSpecified = !String.IsNullOrEmpty(searchTerms); } if (isSearchTermSpecified) { if (searchTerms.Length < _catalogSettings.ProductSearchTermMinimumLength) { model.Warning = string.Format(_localizationService.GetResource("Search.SearchTermMinimumLengthIsNCharacters"), _catalogSettings.ProductSearchTermMinimumLength); } else { var categoryIds = new List <int>(); bool searchInDescriptions = false; if (model.adv) { //advanced search var categoryId = model.cid; if (categoryId > 0) { categoryIds.Add(categoryId); if (model.isc) { //include subcategories categoryIds.AddRange(GetChildCategoryIds(categoryId)); } } searchInDescriptions = model.sid; } //var searchInProductTags = false; var searchInProductTags = searchInDescriptions; //products products = _productService.SearchProducts( categoryIds: categoryIds, storeId: _storeContext.CurrentStore.Id, visibleIndividuallyOnly: true, keywords: searchTerms, searchDescriptions: searchInDescriptions, searchProductTags: searchInProductTags, languageId: _workContext.WorkingLanguage.Id, orderBy: (ProductSortingEnum)command.OrderBy, pageIndex: command.PageNumber - 1, pageSize: command.PageSize); model.Products = _productModelFactory.PrepareProductOverviewModels(products).ToList(); model.NoResults = !model.Products.Any(); //search term statistics if (!String.IsNullOrEmpty(searchTerms)) { var searchTerm = _searchTermService.GetSearchTermByKeyword(searchTerms, _storeContext.CurrentStore.Id); if (searchTerm != null) { searchTerm.Count++; _searchTermService.UpdateSearchTerm(searchTerm); } else { searchTerm = new SearchTerm { Keyword = searchTerms, StoreId = _storeContext.CurrentStore.Id, Count = 1 }; _searchTermService.InsertSearchTerm(searchTerm); } } //event _eventPublisher.Publish(new ProductSearchEvent { SearchTerm = searchTerms, SearchInDescriptions = searchInDescriptions, CategoryIds = categoryIds, WorkingLanguageId = _workContext.WorkingLanguage.Id, }); } } model.PagingFilteringContext.LoadPagedList(products); return(model); }
/// <summary> /// Gets a search term record by keyword /// </summary> /// <param name="keyword">Search term keyword</param> /// <param name="storeId">Store identifier</param> /// <returns>Search term</returns> public SearchTerm GetSearchTermByKeyword(string keyword, int storeId) { return(_searchTermService.GetSearchTermByKeyword(keyword, storeId)); }