flamingo.me/flamingo-commerce/v3@v3.11.0/category/interfaces/controller/querycommand.go (about) 1 package controller 2 3 import ( 4 "context" 5 "net/url" 6 "strconv" 7 8 "flamingo.me/flamingo/v3/framework/web" 9 10 "flamingo.me/flamingo-commerce/v3/category/domain" 11 productApplication "flamingo.me/flamingo-commerce/v3/product/application" 12 13 searchApplication "flamingo.me/flamingo-commerce/v3/search/application" 14 searchDomain "flamingo.me/flamingo-commerce/v3/search/domain" 15 "flamingo.me/flamingo-commerce/v3/search/utils" 16 ) 17 18 //go:generate go run github.com/vektra/mockery/v2@v2.42.3 --name ProductSearchService --case snake 19 20 type ( 21 // QueryHandler provides the base command logic that is agnostic to the actual view type 22 QueryHandler interface { 23 Execute(ctx context.Context, req Request) (*Result, *RedirectResult, error) 24 } 25 26 // ProductSearchService interface that describes the expected dependency. (Is fulfilled by the product package) 27 ProductSearchService interface { 28 Find(ctx context.Context, searchRequest *searchApplication.SearchRequest) (*productApplication.SearchResult, error) 29 } 30 31 // QueryHandlerImpl is the default implementation of QueryHandler 32 QueryHandlerImpl struct { 33 categoryService domain.CategoryService 34 productSearchService ProductSearchService 35 } 36 37 // Request is a request for a category view 38 Request struct { 39 Code string 40 Name string 41 QueryAll url.Values 42 URL url.URL 43 } 44 45 // Result for found category 46 Result struct { 47 ProductSearchResult *productApplication.SearchResult 48 Category domain.Category 49 CategoryTree domain.Tree 50 SearchMeta searchDomain.SearchMeta 51 PaginationInfo utils.PaginationInfo 52 } 53 54 // RedirectResult signals that a request for a category view shall be redirected using the defined parameters 55 RedirectResult struct { 56 Code string 57 Name string 58 } 59 ) 60 61 var _ QueryHandler = (*QueryHandlerImpl)(nil) 62 63 // Inject injects dependencies 64 func (c *QueryHandlerImpl) Inject( 65 categoryService domain.CategoryService, 66 searchService ProductSearchService, 67 ) { 68 c.categoryService = categoryService 69 c.productSearchService = searchService 70 } 71 72 // Execute Action to display a category page for any view 73 // error might be domain.ErrNotFound to indicate that the category was not found 74 func (c *QueryHandlerImpl) Execute(ctx context.Context, req Request) (*Result, *RedirectResult, error) { 75 treeRoot, err := c.categoryService.Tree(ctx, req.Code) 76 if err != nil { 77 return nil, nil, err 78 } 79 80 currentCategory, err := c.categoryService.Get(ctx, req.Code) 81 if err != nil { 82 return nil, nil, err 83 } 84 85 // Normalize url if required: 86 expectedName := web.URLTitle(currentCategory.Name()) 87 if expectedName != req.Name { 88 return nil, &RedirectResult{Code: currentCategory.Code(), Name: expectedName}, nil 89 } 90 91 searchRequest := &searchApplication.SearchRequest{} 92 for k, v := range req.QueryAll { 93 switch k { 94 case "page": 95 page, _ := strconv.ParseInt(v[0], 10, 64) 96 searchRequest.SetAdditionalFilter(searchDomain.NewPaginationPageFilter(int(page))) 97 98 default: 99 searchRequest.SetAdditionalFilter(searchDomain.NewKeyValueFilter(k, v)) 100 } 101 } 102 searchRequest.SetAdditionalFilter(domain.NewCategoryFacet(currentCategory.Code())) 103 104 products, err := c.productSearchService.Find(ctx, searchRequest) 105 if err != nil { 106 return nil, nil, err 107 } 108 109 return &Result{ 110 Category: currentCategory, 111 CategoryTree: treeRoot, 112 ProductSearchResult: products, 113 SearchMeta: products.SearchMeta, 114 PaginationInfo: products.PaginationInfo, 115 }, nil, nil 116 }