3
3
namespace Algolia \AlgoliaSearch \Setup \Patch \Data ;
4
4
5
5
use Algolia \AlgoliaSearch \Api \Product \ReplicaManagerInterface ;
6
+ use Algolia \AlgoliaSearch \Exception \ReplicaLimitExceededException ;
7
+ use Algolia \AlgoliaSearch \Exception \TooManyCustomerGroupsAsReplicasException ;
6
8
use Algolia \AlgoliaSearch \Helper \ConfigHelper ;
7
9
use Algolia \AlgoliaSearch \Helper \Configuration \ConfigChecker ;
10
+ use Algolia \AlgoliaSearch \Service \Product \SortingTransformer ;
11
+ use Algolia \AlgoliaSearch \Service \StoreNameFetcher ;
12
+ use Algolia \AlgoliaSearch \Validator \VirtualReplicaValidatorFactory ;
8
13
use Magento \Framework \App \Config \ConfigResource \ConfigInterface ;
9
14
use Magento \Framework \App \Config \ScopeConfigInterface ;
10
15
use Magento \Framework \App \Config \Storage \WriterInterface ;
16
+ use Magento \Framework \Exception \LocalizedException ;
17
+ use Magento \Framework \Exception \NoSuchEntityException ;
18
+ use Magento \Framework \Serialize \SerializerInterface ;
11
19
use Magento \Framework \Setup \ModuleDataSetupInterface ;
12
20
use Magento \Framework \Setup \Patch \DataPatchInterface ;
13
21
use Magento \Framework \Setup \Patch \PatchInterface ;
22
+ use Magento \Store \Model \ScopeInterface ;
23
+ use Magento \Store \Model \StoreManagerInterface ;
14
24
15
25
class MigrateVirtualReplicaConfigPatch implements DataPatchInterface
16
26
{
17
27
public function __construct (
18
- protected ModuleDataSetupInterface $ moduleDataSetup ,
19
- protected WriterInterface $ configWriter ,
20
- protected ConfigInterface $ config ,
21
- protected ScopeConfigInterface $ scopeConfig ,
22
- protected ConfigChecker $ configChecker ,
23
- protected ReplicaManagerInterface $ replicaManager
28
+ protected ModuleDataSetupInterface $ moduleDataSetup ,
29
+ protected WriterInterface $ configWriter ,
30
+ protected ConfigInterface $ config ,
31
+ protected ScopeConfigInterface $ scopeConfig ,
32
+ protected ConfigHelper $ configHelper ,
33
+ protected ConfigChecker $ configChecker ,
34
+ protected ReplicaManagerInterface $ replicaManager ,
35
+ protected SortingTransformer $ sortingTransformer ,
36
+ protected VirtualReplicaValidatorFactory $ validatorFactory ,
37
+ protected StoreManagerInterface $ storeManager ,
38
+ protected StoreNameFetcher $ storeNameFetcher ,
39
+ protected SerializerInterface $ serializer
24
40
)
25
41
{}
26
42
@@ -33,27 +49,87 @@ public function apply(): PatchInterface
33
49
34
50
$ this ->configChecker ->checkAndApplyAllScopes (ConfigHelper::USE_VIRTUAL_REPLICA_ENABLED , [$ this , 'migrateSetting ' ]);
35
51
36
- // rebuild everything after
37
-
38
52
$ this ->moduleDataSetup ->getConnection ()->endSetup ();
39
53
40
54
return $ this ;
41
55
}
42
56
57
+ /**
58
+ * Seek each scoped global replica config and attempt to apply to the sorting config
59
+ * Note that a scoping mismatch could occur so this patch will create a matching scoped sort
60
+ * based on the scope of the original legacy virtual replica config
61
+ *
62
+ * @throws NoSuchEntityException
63
+ * @throws LocalizedException
64
+ */
43
65
public function migrateSetting (string $ scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT , int $ scopeId = 0 ): void
44
66
{
45
- $ value = ( bool ) $ this -> scopeConfig -> getValue (ConfigHelper:: USE_VIRTUAL_REPLICA_ENABLED , $ scope , $ scopeId );
46
- // not enabled moving on...
47
- if (! $ value ) {
67
+ // If not enabled - delete this old setting and move on...
68
+ if (! $ this -> scopeConfig -> isSetFlag (ConfigHelper:: USE_VIRTUAL_REPLICA_ENABLED , $ scope , $ scopeId )) {
69
+ $ this -> deleteLegacyConfig ( $ scope , $ scopeId );
48
70
return ;
49
71
}
50
72
51
- // TODO...
52
- // retrieve the sorting config
53
- // turn on virtual replicas for all attributes
54
- // run the validator, throw ReplicaExceedsException if needed
73
+ // Replicate the global settings by turning on virtual replicas for all attributes
74
+ $ virtualizedSorts = $ this ->simulateFullVirtualReplicas ($ scope , $ scopeId );
75
+
76
+ // Get all stores affected by this configuration
77
+ $ storeIds = $ this ->configChecker ->getAffectedStoreIds (
78
+ ConfigHelper::USE_VIRTUAL_REPLICA_ENABLED ,
79
+ $ scope ,
80
+ $ scopeId
81
+ );
82
+
83
+ // Retrieve the sorting config
84
+ foreach ($ storeIds as $ storeId ) {
85
+ $ sortingIndices = $ this ->sortingTransformer ->getSortingIndices ($ storeId , null , $ virtualizedSorts );
86
+
87
+ $ validator = $ this ->validatorFactory ->create ();
88
+ if (!$ validator ->isReplicaConfigurationValid ($ sortingIndices )) {
89
+ $ storeName = $ this ->storeNameFetcher ->getStoreName ($ storeId ) . " (Store ID= $ storeId) " ;
90
+ $ prefix = "Error encountered while attempting to migrate your virtual replica configuration. \n" ;
91
+ $ postfix = "\nPlease note that there can be no more than " . $ this ->replicaManager ->getMaxVirtualReplicasPerIndex () . " virtual replicas per index. " ;
92
+ $ postfix .= "\nYou can now configure virtual replicas by attribute under: Stores > Configuration > Algolia Search > InstantSearch Results Page > Sorting " ;
93
+ $ postfix .= "\nRun the \"bin/magento algolia:replicas:disable-virtual-replicas \" before running \"setup:upgrade \" and configure your virtual replicas in the Magento admin. " ;
94
+ if ($ validator ->isTooManyCustomerGroups ()) {
95
+ throw (new TooManyCustomerGroupsAsReplicasException (__ ("{$ prefix }You have too many customer groups to enable virtual replicas on the pricing sort for $ storeName. $ postfix " )))
96
+ ->withReplicaCount ($ validator ->getReplicaCount ())
97
+ ->withPriceSortReplicaCount ($ validator ->getPriceSortReplicaCount ());
98
+ }
99
+ else {
100
+ throw (new ReplicaLimitExceededException (__ ("{$ prefix }Replica limit exceeded for $ storeName. $ postfix " )))
101
+ ->withReplicaCount ($ validator ->getReplicaCount ());
102
+ }
103
+ }
104
+
105
+ // If all is copacetic then save the new sorting config
106
+ // Save to store scope if we are not already there or if a store scope override exists
107
+ if ($ scope != ScopeInterface::SCOPE_STORES
108
+ && $ this ->configChecker ->isSettingAppliedForScopeAndCode (ConfigHelper::SORTING_INDICES , ScopeInterface::SCOPE_STORES , $ storeId )) {
109
+ $ this ->configHelper ->setSorting ($ virtualizedSorts , ScopeInterface::SCOPE_STORES , $ storeId );
110
+ }
111
+ }
112
+
113
+ // Save in the matching scope to the original legacy global config
114
+ $ this ->configHelper ->setSorting ($ virtualizedSorts , $ scope , $ scopeId );
115
+ $ this ->deleteLegacyConfig ($ scope , $ scopeId );
116
+ }
55
117
56
- //if all is copacetic then save the new sorting config
118
+ protected function deleteLegacyConfig ($ scope , $ scopeId ): void
119
+ {
120
+ $ this ->configWriter ->delete (ConfigHelper::USE_VIRTUAL_REPLICA_ENABLED , $ scope , $ scopeId );
121
+ }
122
+
123
+ protected function simulateFullVirtualReplicas (string $ scope , int $ scopeId ): array
124
+ {
125
+ $ raw = $ this ->scopeConfig ->getValue (ConfigHelper::SORTING_INDICES , $ scope , $ scopeId );
126
+ return array_map (
127
+ function ($ sort ) {
128
+ $ sort [ReplicaManagerInterface::SORT_KEY_VIRTUAL_REPLICA ] = 1 ;
129
+ return $ sort ;
130
+ },
131
+ $ this ->serializer ->unserialize ($ raw )
132
+ );
57
133
}
58
134
59
135
/**
0 commit comments