Skip to content

Commit b625777

Browse files
authored
Merge pull request #1542 from algolia/feature/MAGE-839
Feature/mage 839 Store scoped replica state management
2 parents 471d76b + 30740ac commit b625777

File tree

9 files changed

+231
-150
lines changed

9 files changed

+231
-150
lines changed

Helper/ConfigHelper.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace Algolia\AlgoliaSearch\Helper;
44

5+
use Algolia\AlgoliaSearch\Model\Product\ReplicaManager;
56
use Magento;
67
use Magento\Customer\Model\ResourceModel\Group\Collection as GroupCollection;
78
use Magento\Directory\Model\Currency as DirCurrency;
@@ -1166,7 +1167,7 @@ public function getSortingIndices(
11661167
$attrsToReturn[] = $attr;
11671168
}
11681169
}
1169-
1170+
11701171
if ($useCache) {
11711172
$this->_sortingIndices[$storeId] = $attrsToReturn;
11721173
}
@@ -1868,7 +1869,7 @@ public function useVirtualReplica(?int $storeId = null): bool
18681869
return (bool) count(array_filter(
18691870
$this->getSorting($storeId),
18701871
function ($sort) {
1871-
return $sort['virtualReplica'];
1872+
return $sort[ReplicaManager::SORT_KEY_VIRTUAL_REPLICA];
18721873
}
18731874
));
18741875
}

Helper/Configuration/ConfigChecker.php

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,48 @@
22

33
namespace Algolia\AlgoliaSearch\Helper\Configuration;
44

5-
use Algolia\AlgoliaSearch\Helper\ConfigHelper;
65
use Magento\Framework\App\Config\ScopeConfigInterface;
6+
use Magento\Framework\Exception\NoSuchEntityException;
7+
use Magento\Store\Api\WebsiteRepositoryInterface;
78
use Magento\Store\Model\ScopeInterface;
89
use Magento\Store\Model\StoreManagerInterface;
910

1011
class ConfigChecker
1112
{
1213
public function __construct(
13-
protected ScopeConfigInterface $scopeConfig,
14-
protected StoreManagerInterface $storeManager
14+
protected ScopeConfigInterface $scopeConfig,
15+
protected StoreManagerInterface $storeManager,
16+
protected WebsiteRepositoryInterface $websiteRepository
1517
) {}
1618

17-
public function isSettingAppliedForScopeAndCode(string $path, string $scope, string $code): bool
19+
/**
20+
* Is a scoped value different from the default?
21+
* @param string $path
22+
* @param string $scope
23+
* @param mixed $code
24+
* @return bool
25+
*/
26+
public function isSettingAppliedForScopeAndCode(string $path, string $scope, mixed $code): bool
1827
{
1928
$value = $this->scopeConfig->getValue($path, $scope, $code);
2029
$defaultValue = $this->scopeConfig->getValue($path);
2130
return ($value !== $defaultValue);
2231
}
2332

33+
/**
34+
* Does a store config override the website config?
35+
* @param string $path
36+
* @param mixed $websiteId
37+
* @param int $storeId
38+
* @return bool
39+
*/
40+
protected function isStoreSettingOverridingWebsite(string $path, mixed $websiteId, int $storeId): bool
41+
{
42+
$storeValue = $this->scopeConfig->getValue($path, ScopeInterface::SCOPE_STORES, $storeId);
43+
$websiteValue = $this->scopeConfig->getValue($path, ScopeInterface::SCOPE_WEBSITES, $websiteId);
44+
return ($storeValue !== $websiteValue);
45+
}
46+
2447
/**
2548
* For a given path, check if that path has a non-default value
2649
* and if so perform corresponding logic (specified via callback)
@@ -32,23 +55,22 @@ public function isSettingAppliedForScopeAndCode(string $path, string $scope, str
3255
*
3356
* @return void
3457
*/
35-
public function checkAndApplyAllScopes(string $path, callable $callback, bool $includeDefault = true) {
58+
public function checkAndApplyAllScopes(string $path, callable $callback, bool $includeDefault = true): void
59+
{
3660
// First update all the possible scoped configurations
37-
/** @var \Magento\Store\Api\Data\WebsiteInterface $website */
3861
foreach ($this->storeManager->getWebsites() as $website) {
3962
if ($this->isSettingAppliedForScopeAndCode(
40-
ConfigHelper::CC_CONVERSION_ANALYTICS_MODE,
63+
$path,
4164
ScopeInterface::SCOPE_WEBSITES,
4265
$website->getId()
4366
)) {
4467
$callback(ScopeInterface::SCOPE_WEBSITES, $website->getId());
4568
}
4669
}
4770

48-
/** @var \Magento\Store\Api\Data\StoreInterface $store */
4971
foreach ($this->storeManager->getStores() as $store) {
5072
if ($this->isSettingAppliedForScopeAndCode(
51-
ConfigHelper::CC_CONVERSION_ANALYTICS_MODE,
73+
$path,
5274
ScopeInterface::SCOPE_STORES,
5375
$store->getId()
5476
)) {
@@ -61,4 +83,52 @@ public function checkAndApplyAllScopes(string $path, callable $callback, bool $i
6183
$callback(ScopeConfigInterface::SCOPE_TYPE_DEFAULT);
6284
}
6385
}
86+
87+
88+
/**
89+
* For a given path and scope determine which stores are affected
90+
* @param string $path The configuration path
91+
* @param string $scope The scope: `default`, `websites` or `stores`
92+
* @param int $scopeId The entity referenced by the corresponding scope
93+
* @return int[]
94+
* @throws NoSuchEntityException
95+
*/
96+
public function getAffectedStoreIds(string $path, string $scope, int $scopeId): array
97+
{
98+
$storeIds = [];
99+
100+
switch ($scope) {
101+
// check and find all stores that are not overridden
102+
case ScopeConfigInterface::SCOPE_TYPE_DEFAULT:
103+
foreach ($this->storeManager->getStores() as $store) {
104+
if (!$this->isSettingAppliedForScopeAndCode(
105+
$path,
106+
ScopeInterface::SCOPE_STORES,
107+
$store->getId()
108+
)) {
109+
$storeIds[] = $store->getId();
110+
}
111+
}
112+
break;
113+
114+
// website config applied - check and find all stores under that website that are not overridden
115+
case ScopeInterface::SCOPE_WEBSITES:
116+
$website = $this->websiteRepository->getById($scopeId);
117+
foreach ($website->getStores() as $store) {
118+
if (!$this->isStoreSettingOverridingWebsite(
119+
$path,
120+
$website->getId(),
121+
$store->getId()
122+
)) {
123+
$storeIds[] = $store->getId();
124+
}
125+
}
126+
break;
127+
128+
// simple store specific config
129+
case ScopeInterface::SCOPE_STORES:
130+
$storeIds[] = $scopeId;
131+
}
132+
return $storeIds;
133+
}
64134
}

Helper/Entity/ProductHelper.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Algolia\AlgoliaSearch\Helper\Entity\Product\PriceManager;
1616
use Algolia\AlgoliaSearch\Helper\Image as ImageHelper;
1717
use Algolia\AlgoliaSearch\Helper\Logger;
18+
use Algolia\AlgoliaSearch\Model\Product\ReplicaManager;
1819
use Magento\Bundle\Model\Product\Type as BundleProductType;
1920
use Magento\Catalog\Model\Product;
2021
use Magento\Catalog\Model\Product\Attribute\Source\Status;
@@ -1425,7 +1426,7 @@ protected function decorateReplicasSetting(array $sortingIndices): array {
14251426
return array_map(
14261427
function($sort) {
14271428
$replica = $sort['name'];
1428-
return !! $sort['virtualReplica']
1429+
return !! $sort[ReplicaManager::SORT_KEY_VIRTUAL_REPLICA]
14291430
? "virtual($replica)"
14301431
: $replica;
14311432
},

Model/Backend/EnableCustomerGroups.php

Lines changed: 24 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22

33
namespace Algolia\AlgoliaSearch\Model\Backend;
44

5-
use Algolia\AlgoliaSearch\Exceptions\AlgoliaException;
6-
use Algolia\AlgoliaSearch\Helper\Data;
7-
use Algolia\AlgoliaSearch\Helper\Entity\ProductHelper;
5+
use Algolia\AlgoliaSearch\Helper\Configuration\ConfigChecker;
6+
use Algolia\AlgoliaSearch\Registry\ReplicaState;
87
use Magento\Framework\App\Cache\TypeListInterface;
98
use Magento\Framework\App\Config\ScopeConfigInterface;
109
use Magento\Framework\App\Config\Value;
@@ -13,61 +12,43 @@
1312
use Magento\Framework\Model\Context;
1413
use Magento\Framework\Model\ResourceModel\AbstractResource;
1514
use Magento\Framework\Registry;
16-
use Magento\Store\Model\StoreManagerInterface;
1715

1816
class EnableCustomerGroups extends Value
1917
{
20-
/**
21-
* @param Context $context
22-
* @param Registry $registry
23-
* @param ScopeConfigInterface $config
24-
* @param TypeListInterface $cacheTypeList
25-
* @param StoreManagerInterface $storeManager
26-
* @param Data $helper
27-
* @param ProductHelper $productHelper
28-
* @param AbstractResource|null $resource
29-
* @param AbstractDb|null $resourceCollection
30-
* @param array $data
31-
*/
3218
public function __construct(
33-
Context $context,
34-
Registry $registry,
35-
ScopeConfigInterface $config,
36-
TypeListInterface $cacheTypeList,
37-
protected StoreManagerInterface $storeManager,
38-
protected Data $helper,
39-
protected ProductHelper $productHelper,
40-
AbstractResource $resource = null,
41-
AbstractDb $resourceCollection = null,
42-
array $data = []
19+
Context $context,
20+
Registry $registry,
21+
ScopeConfigInterface $config,
22+
TypeListInterface $cacheTypeList,
23+
protected ReplicaState $replicaState,
24+
protected ConfigChecker $configChecker,
25+
AbstractResource $resource = null,
26+
AbstractDb $resourceCollection = null,
27+
array $data = []
4328
)
4429
{
4530
parent::__construct($context, $registry, $config, $cacheTypeList, $resource, $resourceCollection, $data);
4631
}
4732

4833
/**
4934
* @return $this
50-
* @throws AlgoliaException
5135
* @throws NoSuchEntityException
5236
*/
53-
public function afterSave(): \Magento\Framework\App\Config\Value
37+
public function afterSave(): Value
5438
{
55-
// TODO: Determine if this action should be performed in the event of customer group pricing enablement
56-
/*
57-
if ($this->isValueChanged()) {
58-
try {
59-
$storeIds = array_keys($this->storeManager->getStores());
60-
foreach ($storeIds as $storeId) {
61-
$indexName = $this->helper->getIndexName($this->productHelper->getIndexNameSuffix(), $storeId);
62-
$this->productHelper->handlingReplica($indexName, $storeId);
63-
}
64-
} catch (AlgoliaException $e) {
65-
if ($e->getCode() !== 404) {
66-
throw $e;
67-
}
68-
}
39+
$storeIds = $this->configChecker->getAffectedStoreIds(
40+
$this->getPath(),
41+
$this->getScope(),
42+
$this->getScopeId()
43+
);
44+
45+
foreach ($storeIds as $storeId) {
46+
$this->replicaState->setChangeState(
47+
$this->isValueChanged()
48+
? ReplicaState::REPLICA_STATE_CHANGED
49+
: ReplicaState::REPLICA_STATE_UNCHANGED,
50+
$storeId);
6951
}
70-
*/
7152

7253
return parent::afterSave();
7354
}

Model/Backend/Sorts.php

Lines changed: 26 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,51 +2,32 @@
22

33
namespace Algolia\AlgoliaSearch\Model\Backend;
44

5-
use Algolia\AlgoliaSearch\Exceptions\AlgoliaException;
6-
use Algolia\AlgoliaSearch\Helper\Data;
7-
use Algolia\AlgoliaSearch\Helper\Entity\ProductHelper;
5+
use Algolia\AlgoliaSearch\Helper\Configuration\ConfigChecker;
86
use Algolia\AlgoliaSearch\Registry\ReplicaState;
97
use Magento\Config\Model\Config\Backend\Serialized\ArraySerialized;
108
use Magento\Framework\App\Cache\TypeListInterface;
119
use Magento\Framework\App\Config\ScopeConfigInterface;
1210
use Magento\Framework\App\ObjectManager;
1311
use Magento\Framework\Data\Collection\AbstractDb;
14-
use Magento\Framework\Exception\LocalizedException;
1512
use Magento\Framework\Exception\NoSuchEntityException;
1613
use Magento\Framework\Model\Context;
1714
use Magento\Framework\Model\ResourceModel\AbstractResource;
1815
use Magento\Framework\Registry;
1916
use Magento\Framework\Serialize\Serializer\Json;
20-
use Magento\Store\Model\StoreManagerInterface;
2117

2218
class Sorts extends ArraySerialized
2319
{
24-
/**
25-
* @param Context $context
26-
* @param Registry $registry
27-
* @param ScopeConfigInterface $config
28-
* @param TypeListInterface $cacheTypeList
29-
* @param AbstractResource|null $resource
30-
* @param AbstractDb|null $resourceCollection
31-
* @param array $data
32-
* @param Json|null $serializer
33-
* @param StoreManagerInterface $storeManager
34-
* @param Data $helper
35-
* @param ProductHelper $productHelper
36-
*/
3720
public function __construct(
38-
Context $context,
39-
Registry $registry,
40-
ScopeConfigInterface $config,
41-
TypeListInterface $cacheTypeList,
42-
protected StoreManagerInterface $storeManager,
43-
protected Data $helper,
44-
protected ProductHelper $productHelper,
45-
protected ReplicaState $replicaState,
46-
AbstractResource $resource = null,
47-
AbstractDb $resourceCollection = null,
48-
array $data = [],
49-
Json $serializer = null
21+
Context $context,
22+
Registry $registry,
23+
ScopeConfigInterface $config,
24+
TypeListInterface $cacheTypeList,
25+
protected ReplicaState $replicaState,
26+
protected ConfigChecker $configChecker,
27+
AbstractResource $resource = null,
28+
AbstractDb $resourceCollection = null,
29+
array $data = [],
30+
Json $serializer = null
5031
)
5132
{
5233
$this->serializer = $serializer ?: ObjectManager::getInstance()->get(Json::class);
@@ -63,14 +44,24 @@ public function __construct(
6344

6445
/**
6546
* @return $this
66-
* @throws AlgoliaException
67-
* @throws NoSuchEntityException|LocalizedException
47+
* @throws NoSuchEntityException
6848
*/
6949
public function afterSave(): \Magento\Framework\App\Config\Value
7050
{
71-
if ($this->isValueChanged()) {
72-
$this->replicaState->setOriginalSortConfiguration($this->serializer->unserialize($this->getOldValue()));
73-
$this->replicaState->setUpdatedSortConfiguration($this->serializer->unserialize($this->getValue()));
51+
$storeIds = $this->configChecker->getAffectedStoreIds(
52+
$this->getPath(),
53+
$this->getScope(),
54+
$this->getScopeId()
55+
);
56+
57+
foreach ($storeIds as $storeId) {
58+
if ($this->isValueChanged()) {
59+
$this->replicaState->setChangeState(ReplicaState::REPLICA_STATE_CHANGED, $storeId);
60+
$this->replicaState->setOriginalSortConfiguration($this->serializer->unserialize($this->getOldValue()), $storeId);
61+
$this->replicaState->setUpdatedSortConfiguration($this->serializer->unserialize($this->getValue()), $storeId);
62+
} else {
63+
$this->replicaState->setChangeState(ReplicaState::REPLICA_STATE_UNCHANGED, $storeId);
64+
}
7465
}
7566

7667
return parent::afterSave();

0 commit comments

Comments
 (0)