7
7
use Magento \Directory \Model \Currency as DirCurrency ;
8
8
use Magento \Framework \App \Filesystem \DirectoryList ;
9
9
use Magento \Framework \DataObject ;
10
+ use Magento \Framework \Exception \LocalizedException ;
10
11
use Magento \Framework \Locale \Currency ;
11
12
use Magento \Framework \Serialize \SerializerInterface ;
12
13
use Magento \Store \Model \ScopeInterface ;
@@ -35,14 +36,14 @@ class ConfigHelper
35
36
public const REPLACE_CATEGORIES = 'algoliasearch_instant/instant/replace_categories ' ;
36
37
public const INSTANT_SELECTOR = 'algoliasearch_instant/instant/instant_selector ' ;
37
38
public const NUMBER_OF_PRODUCT_RESULTS = 'algoliasearch_instant/instant/number_product_results ' ;
38
- public const FACETS = 'algoliasearch_instant/instant /facets ' ;
39
- public const MAX_VALUES_PER_FACET = 'algoliasearch_instant/instant /max_values_per_facet ' ;
40
- public const SORTING_INDICES = 'algoliasearch_instant/instant /sorts ' ;
41
- public const SHOW_SUGGESTIONS_NO_RESULTS = 'algoliasearch_instant/instant/show_suggestions_on_no_result_page ' ;
42
- public const XML_ADD_TO_CART_ENABLE = 'algoliasearch_instant/instant/add_to_cart_enable ' ;
43
- public const INFINITE_SCROLL_ENABLE = 'algoliasearch_instant/instant/infinite_scroll_enable ' ;
44
- public const SEARCHBOX_ENABLE = 'algoliasearch_instant/instant/instantsearch_searchbox ' ;
45
- public const HIDE_PAGINATION = 'algoliasearch_instant/instant /hide_pagination ' ;
39
+ public const FACETS = 'algoliasearch_instant/instant_facets /facets ' ;
40
+ public const MAX_VALUES_PER_FACET = 'algoliasearch_instant/instant_facets /max_values_per_facet ' ;
41
+ public const SORTING_INDICES = 'algoliasearch_instant/instant_sorts /sorts ' ;
42
+ public const SEARCHBOX_ENABLE = 'algoliasearch_instant/instant_options/instantsearch_searchbox ' ;
43
+ public const SHOW_SUGGESTIONS_NO_RESULTS = 'algoliasearch_instant/instant_options/show_suggestions_on_no_result_page ' ;
44
+ public const XML_ADD_TO_CART_ENABLE = 'algoliasearch_instant/instant_options/add_to_cart_enable ' ;
45
+ public const INFINITE_SCROLL_ENABLE = 'algoliasearch_instant/instant_options/infinite_scroll_enable ' ;
46
+ public const HIDE_PAGINATION = 'algoliasearch_instant/instant_options /hide_pagination ' ;
46
47
47
48
public const IS_POPUP_ENABLED = 'algoliasearch_autocomplete/autocomplete/is_popup_enabled ' ;
48
49
public const NB_OF_PRODUCTS_SUGGESTIONS = 'algoliasearch_autocomplete/autocomplete/nb_of_products_suggestions ' ;
@@ -135,7 +136,7 @@ class ConfigHelper
135
136
protected const IS_ADDTOCART_ENABLED_IN_FREQUENTLY_BOUGHT_TOGETHER = 'algoliasearch_recommend/recommend/frequently_bought_together/is_addtocart_enabled ' ;
136
137
protected const IS_ADDTOCART_ENABLED_IN_RELATED_PRODUCTS = 'algoliasearch_recommend/recommend/related_product/is_addtocart_enabled ' ;
137
138
protected const IS_ADDTOCART_ENABLED_IN_TRENDS_ITEM = 'algoliasearch_recommend/recommend/trends_item/is_addtocart_enabled ' ;
138
- protected const USE_VIRTUAL_REPLICA_ENABLED = 'algoliasearch_instant/instant/use_virtual_replica ' ;
139
+ protected const USE_VIRTUAL_REPLICA_ENABLED = 'algoliasearch_instant/instant/use_virtual_replica ' ; //legacy config
139
140
protected const AUTOCOMPLETE_KEYBORAD_NAVIAGATION = 'algoliasearch_autocomplete/autocomplete/navigator ' ;
140
141
protected const FREQUENTLY_BOUGHT_TOGETHER_TITLE = 'algoliasearch_recommend/recommend/frequently_bought_together/title ' ;
141
142
protected const RELATED_PRODUCTS_TITLE = 'algoliasearch_recommend/recommend/related_product/title ' ;
@@ -145,6 +146,10 @@ class ConfigHelper
145
146
public const ENHANCED_QUEUE_ARCHIVE = 'algoliasearch_advanced/queue/enhanced_archive ' ;
146
147
public const NUMBER_OF_ELEMENT_BY_PAGE = 'algoliasearch_advanced/queue/number_of_element_by_page ' ;
147
148
public const ARCHIVE_LOG_CLEAR_LIMIT = 'algoliasearch_advanced/queue/archive_clear_limit ' ;
149
+ // https://www.algolia.com/doc/guides/managing-results/refine-results/sorting/in-depth/replicas/#what-are-virtual-replicas
150
+ public const MAX_VIRTUAL_REPLICA_LIMIT = 20 ;
151
+
152
+ public const SORT_ATTRIBUTE_PRICE = 'price ' ;
148
153
149
154
/**
150
155
* @var Magento\Framework\App\Config\ScopeConfigInterface
@@ -206,6 +211,11 @@ class ConfigHelper
206
211
*/
207
212
protected $ cookieHelper ;
208
213
214
+ /**
215
+ * @var array<int,<array<string, mixed>>>
216
+ */
217
+ protected array $ _sortingIndices = [];
218
+
209
219
/**
210
220
* @param Magento\Framework\App\Config\ScopeConfigInterface $configInterface
211
221
* @param StoreManagerInterface $storeManager
@@ -1005,17 +1015,107 @@ public function getAutocompleteMinimumCharacterLength($storeId = null): int
1005
1015
}
1006
1016
1007
1017
/**
1008
- * @param $originalIndexName
1009
- * @param $storeId
1010
- * @param $currentCustomerGroupId
1011
- * @param $attrs
1018
+ * When group pricing is enabled a replica must be created for each possible sort
1019
+ *
1020
+ * @param string $originalIndexName
1021
+ * @param int $customerGroupId
1022
+ * @param string $currency
1023
+ * @param array $origAttr
1012
1024
* @return array
1025
+ */
1026
+ protected function getCustomerGroupSortPriceOverride (
1027
+ string $ originalIndexName ,
1028
+ int $ customerGroupId ,
1029
+ string $ currency ,
1030
+ array $ origAttr ): array
1031
+ {
1032
+ $ attrName = $ origAttr ['attribute ' ];
1033
+ $ sortDir = $ origAttr ['sort ' ];
1034
+ $ groupIndexNameSuffix = 'group_ ' . $ customerGroupId ;
1035
+ $ groupIndexName =
1036
+ $ originalIndexName . '_ ' . $ attrName . '_ ' . $ groupIndexNameSuffix . '_ ' . $ sortDir ;
1037
+ $ groupSortAttribute = $ attrName . '. ' . $ currency . '. ' . $ groupIndexNameSuffix ;
1038
+ $ newAttr = [
1039
+ 'attribute ' => $ attrName ,
1040
+ 'name ' => $ groupIndexName ,
1041
+ 'sort ' => $ sortDir ,
1042
+ 'sortLabel ' => $ origAttr ['sortLabel ' ]
1043
+ ];
1044
+
1045
+ $ newAttr ['ranking ' ] = $ this ->getSortAttributingRankingSetting ($ groupSortAttribute , $ sortDir );
1046
+ return $ this ->decorateSortAttribute ($ newAttr );
1047
+ }
1048
+
1049
+ /*
1050
+ * Add data to the sort attribute object
1051
+ */
1052
+ protected function decorateSortAttribute (array $ attr ): array {
1053
+ if (!array_key_exists ('label ' , $ attr ) && array_key_exists ('sortLabel ' , $ attr )) {
1054
+ $ attr ['label ' ] = $ attr ['sortLabel ' ];
1055
+ }
1056
+ return $ attr ;
1057
+ }
1058
+
1059
+ /**
1060
+ * Get ranking setting to be used for the standard sorting replica
1061
+ * @param string $attrName
1062
+ * @param string $sortDir
1063
+ * @return string[]
1064
+ */
1065
+ protected function getSortAttributingRankingSetting (string $ attrName , string $ sortDir ): array
1066
+ {
1067
+ return [
1068
+ $ sortDir . '( ' . $ attrName . ') ' ,
1069
+ 'typo ' ,
1070
+ 'geo ' ,
1071
+ 'words ' ,
1072
+ 'filters ' ,
1073
+ 'proximity ' ,
1074
+ 'attribute ' ,
1075
+ 'exact ' ,
1076
+ 'custom ' ,
1077
+ ];
1078
+ }
1079
+
1080
+ /**
1081
+ * @throws LocalizedException
1082
+ */
1083
+ protected function isGroupPricingExcludedFromWebsite (int $ customerGroupId , int $ websiteId ): bool
1084
+ {
1085
+ $ excludedWebsites = $ this ->groupExcludedWebsiteRepository ->getCustomerGroupExcludedWebsites ($ customerGroupId );
1086
+ return in_array ($ websiteId , $ excludedWebsites );
1087
+ }
1088
+
1089
+ /**
1090
+ * Augment sorting configuration with corresponding replica indices, ranking,
1091
+ * and (as needed) customer group pricing
1092
+ *
1093
+ * @param string $originalIndexName
1094
+ * @param ?int $storeId
1095
+ * @param ?int $currentCustomerGroupId
1096
+ * @param ?array $attrs - serialized array of sorting attributes to transform (defaults to saved sorting config)
1097
+ * @return array of transformed sorting / replica objects
1013
1098
* @throws Magento\Framework\Exception\LocalizedException
1014
1099
* @throws Magento\Framework\Exception\NoSuchEntityException
1015
1100
*/
1016
- public function getSortingIndices ($ originalIndexName , $ storeId = null , $ currentCustomerGroupId = null , $ attrs = null )
1101
+ public function getSortingIndices (
1102
+ string $ originalIndexName ,
1103
+ int $ storeId = null ,
1104
+ int $ currentCustomerGroupId = null ,
1105
+ array $ attrs = null
1106
+ ): array
1017
1107
{
1018
- if (!$ attrs ){
1108
+ // Selectively cache this result - only cache manipulation of saved settings per store
1109
+ $ useCache = is_null ($ currentCustomerGroupId ) && is_null ($ attrs );
1110
+
1111
+ if ($ useCache
1112
+ && array_key_exists ($ storeId , $ this ->_sortingIndices )
1113
+ && is_array ($ this ->_sortingIndices [$ storeId ])) {
1114
+ return $ this ->_sortingIndices [$ storeId ];
1115
+ }
1116
+
1117
+ // If no sorting configuration is supplied - obtain from the saved configuration
1118
+ if (!$ attrs ) {
1019
1119
$ attrs = $ this ->getSorting ($ storeId );
1020
1120
}
1021
1121
@@ -1024,85 +1124,54 @@ public function getSortingIndices($originalIndexName, $storeId = null, $currentC
1024
1124
foreach ($ attrs as $ key => $ attr ) {
1025
1125
$ indexName = false ;
1026
1126
$ sortAttribute = false ;
1027
- if ($ this ->isCustomerGroupsEnabled ($ storeId ) && $ attr ['attribute ' ] === 'price ' ) {
1028
- $ websiteId = (int )$ this ->storeManager ->getStore ($ storeId )->getWebsiteId ();
1127
+ // Group pricing
1128
+ if ($ this ->isCustomerGroupsEnabled ($ storeId ) && $ attr ['attribute ' ] === self ::SORT_ATTRIBUTE_PRICE ) {
1129
+ $ websiteId = (int ) $ this ->storeManager ->getStore ($ storeId )->getWebsiteId ();
1029
1130
$ groupCollection = $ this ->groupCollection ;
1030
1131
if (!is_null ($ currentCustomerGroupId )) {
1031
1132
$ groupCollection ->addFilter ('customer_group_id ' , $ currentCustomerGroupId );
1032
1133
}
1033
1134
foreach ($ groupCollection as $ group ) {
1034
- $ customerGroupId = (int )$ group ->getData ('customer_group_id ' );
1035
- $ excludedWebsites = $ this ->groupExcludedWebsiteRepository -> getCustomerGroupExcludedWebsites ($ customerGroupId);
1036
- if ( in_array ( $ websiteId , $ excludedWebsites )) {
1037
- continue ;
1135
+ $ customerGroupId = (int ) $ group ->getData ('customer_group_id ' );
1136
+ if (! $ this ->isGroupPricingExcludedFromWebsite ($ customerGroupId, $ websiteId )) {
1137
+ $ newAttr = $ this -> getCustomerGroupSortPriceOverride ( $ originalIndexName , $ customerGroupId , $ currency , $ attr );;
1138
+ $ attributesToAdd [ $ newAttr [ ' sort ' ]][] = $ this -> decorateSortAttribute ( $ newAttr ) ;
1038
1139
}
1039
- $ groupIndexNameSuffix = 'group_ ' . $ customerGroupId ;
1040
- $ groupIndexName =
1041
- $ originalIndexName . '_ ' . $ attr ['attribute ' ] . '_ ' . $ groupIndexNameSuffix . '_ ' . $ attr ['sort ' ];
1042
- $ groupSortAttribute = $ attr ['attribute ' ] . '. ' . $ currency . '. ' . $ groupIndexNameSuffix ;
1043
- $ newAttr = [];
1044
- $ newAttr ['name ' ] = $ groupIndexName ;
1045
- $ newAttr ['attribute ' ] = $ attr ['attribute ' ];
1046
- $ newAttr ['sort ' ] = $ attr ['sort ' ];
1047
- $ newAttr ['sortLabel ' ] = $ attr ['sortLabel ' ];
1048
- if (!array_key_exists ('label ' , $ newAttr ) && array_key_exists ('sortLabel ' , $ newAttr )) {
1049
- $ newAttr ['label ' ] = $ newAttr ['sortLabel ' ];
1050
- }
1051
- $ newAttr ['ranking ' ] = [
1052
- $ newAttr ['sort ' ] . '( ' . $ groupSortAttribute . ') ' ,
1053
- 'typo ' ,
1054
- 'geo ' ,
1055
- 'words ' ,
1056
- 'filters ' ,
1057
- 'proximity ' ,
1058
- 'attribute ' ,
1059
- 'exact ' ,
1060
- 'custom ' ,
1061
- ];
1062
- $ attributesToAdd [$ newAttr ['sort ' ]][] = $ newAttr ;
1063
1140
}
1064
- } elseif ($ attr ['attribute ' ] === 'price ' ) {
1141
+ // Regular pricing
1142
+ } elseif ($ attr ['attribute ' ] === self ::SORT_ATTRIBUTE_PRICE ) {
1065
1143
$ indexName = $ originalIndexName . '_ ' . $ attr ['attribute ' ] . '_ ' . 'default ' . '_ ' . $ attr ['sort ' ];
1066
1144
$ sortAttribute = $ attr ['attribute ' ] . '. ' . $ currency . '. ' . 'default ' ;
1145
+ // All other sort attributes
1067
1146
} else {
1068
1147
$ indexName = $ originalIndexName . '_ ' . $ attr ['attribute ' ] . '_ ' . $ attr ['sort ' ];
1069
1148
$ sortAttribute = $ attr ['attribute ' ];
1070
1149
}
1150
+
1151
+ // Decorate all non group pricing attributes
1071
1152
if ($ indexName && $ sortAttribute ) {
1072
1153
$ attrs [$ key ]['name ' ] = $ indexName ;
1073
- if (!array_key_exists ('label ' , $ attrs [$ key ]) && array_key_exists ('sortLabel ' , $ attrs [$ key ])) {
1074
- $ attrs [$ key ]['label ' ] = $ attrs [$ key ]['sortLabel ' ];
1075
- }
1076
- $ attrs [$ key ]['ranking ' ] = [
1077
- $ attr ['sort ' ] . '( ' . $ sortAttribute . ') ' ,
1078
- 'typo ' ,
1079
- 'geo ' ,
1080
- 'words ' ,
1081
- 'filters ' ,
1082
- 'proximity ' ,
1083
- 'attribute ' ,
1084
- 'exact ' ,
1085
- 'custom ' ,
1086
- ];
1154
+ $ attrs [$ key ]['ranking ' ] = $ this ->getSortAttributingRankingSetting ($ sortAttribute , $ attr ['sort ' ]);
1155
+ $ attrs [$ key ] = $ this ->decorateSortAttribute ($ attrs [$ key ]);
1087
1156
}
1088
1157
}
1089
1158
$ attrsToReturn = [];
1090
- if (count ($ attributesToAdd ) > 0 ) {
1091
- foreach ($ attrs as $ key => $ attr ) {
1092
- if ($ attr ['attribute ' ] == 'price ' && isset ($ attributesToAdd [$ attr ['sort ' ]])) {
1093
- $ attrsToReturn = array_merge ($ attrsToReturn , $ attributesToAdd [$ attr ['sort ' ]]);
1094
- } else {
1095
- $ attrsToReturn [] = $ attr ;
1096
- }
1159
+
1160
+ foreach ($ attrs as $ attr ) {
1161
+ if ($ attr ['attribute ' ] == self ::SORT_ATTRIBUTE_PRICE
1162
+ && count ($ attributesToAdd )
1163
+ && isset ($ attributesToAdd [$ attr ['sort ' ]])) {
1164
+ $ attrsToReturn = array_merge ($ attrsToReturn , $ attributesToAdd [$ attr ['sort ' ]]);
1165
+ } else {
1166
+ $ attrsToReturn [] = $ attr ;
1097
1167
}
1098
1168
}
1099
- if (count ($ attrsToReturn ) > 0 ) {
1100
- return $ attrsToReturn ;
1101
- }
1102
- if (is_array ($ attrs )) {
1103
- return $ attrs ;
1169
+
1170
+ if ($ useCache ) {
1171
+ $ this ->_sortingIndices [$ storeId ] = $ attrsToReturn ;
1104
1172
}
1105
- return [];
1173
+
1174
+ return $ attrsToReturn ;
1106
1175
}
1107
1176
1108
1177
/***
@@ -1791,14 +1860,17 @@ public function getCacheTime($storeId = null)
1791
1860
}
1792
1861
1793
1862
/**
1794
- * @param $storeId
1795
- * @return mixed
1863
+ * @param int|null $storeId
1864
+ * @return bool
1796
1865
*/
1797
- public function useVirtualReplica ($ storeId = null ) {
1798
- return $ this ->configInterface ->isSetFlag (self ::USE_VIRTUAL_REPLICA_ENABLED ,
1799
- ScopeInterface::SCOPE_STORE ,
1800
- $ storeId
1801
- );
1866
+ public function useVirtualReplica (?int $ storeId = null ): bool
1867
+ {
1868
+ return (bool ) count (array_filter (
1869
+ $ this ->getSorting ($ storeId ),
1870
+ function ($ sort ) {
1871
+ return $ sort ['virtualReplica ' ];
1872
+ }
1873
+ ));
1802
1874
}
1803
1875
1804
1876
/**
0 commit comments