Skip to content

Commit e277804

Browse files
committed
MAGE-848 Implement migration to convert global replica setting to sorting configuration based on scope of original setting
1 parent 5a62ce1 commit e277804

File tree

1 file changed

+92
-16
lines changed

1 file changed

+92
-16
lines changed

Setup/Patch/Data/MigrateVirtualReplicaConfigPatch.php

Lines changed: 92 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,40 @@
33
namespace Algolia\AlgoliaSearch\Setup\Patch\Data;
44

55
use Algolia\AlgoliaSearch\Api\Product\ReplicaManagerInterface;
6+
use Algolia\AlgoliaSearch\Exception\ReplicaLimitExceededException;
7+
use Algolia\AlgoliaSearch\Exception\TooManyCustomerGroupsAsReplicasException;
68
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
79
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;
813
use Magento\Framework\App\Config\ConfigResource\ConfigInterface;
914
use Magento\Framework\App\Config\ScopeConfigInterface;
1015
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;
1119
use Magento\Framework\Setup\ModuleDataSetupInterface;
1220
use Magento\Framework\Setup\Patch\DataPatchInterface;
1321
use Magento\Framework\Setup\Patch\PatchInterface;
22+
use Magento\Store\Model\ScopeInterface;
23+
use Magento\Store\Model\StoreManagerInterface;
1424

1525
class MigrateVirtualReplicaConfigPatch implements DataPatchInterface
1626
{
1727
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
2440
)
2541
{}
2642

@@ -33,27 +49,87 @@ public function apply(): PatchInterface
3349

3450
$this->configChecker->checkAndApplyAllScopes(ConfigHelper::USE_VIRTUAL_REPLICA_ENABLED, [$this, 'migrateSetting']);
3551

36-
// rebuild everything after
37-
3852
$this->moduleDataSetup->getConnection()->endSetup();
3953

4054
return $this;
4155
}
4256

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+
*/
4365
public function migrateSetting(string $scope = ScopeConfigInterface::SCOPE_TYPE_DEFAULT, int $scopeId = 0): void
4466
{
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);
4870
return;
4971
}
5072

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+
}
55117

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+
);
57133
}
58134

59135
/**

0 commit comments

Comments
 (0)