Skip to content

Commit bbf53a8

Browse files
committed
2 parents e1cbfd0 + 22d5418 commit bbf53a8

19 files changed

Lines changed: 808 additions & 143 deletions

File tree

CatalogDataExporter/Model/Provider/Categories.php

Lines changed: 60 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Magento\CatalogDataExporter\Model\Query\CategoryMainQuery;
1616
use Magento\DataExporter\Exception\UnableRetrieveData;
1717
use Magento\DataExporter\Export\DataProcessorInterface;
18+
use Magento\DataExporter\Export\ScopeResolverInterface;
1819
use Magento\DataExporter\Model\Indexer\FeedIndexMetadata;
1920
use Magento\Framework\App\ObjectManager;
2021
use Magento\Framework\App\ResourceConnection;
@@ -63,6 +64,11 @@ class Categories implements DataProcessorInterface
6364
*/
6465
private $ancestorStatusProvider;
6566

67+
/**
68+
* @var ScopeResolverInterface
69+
*/
70+
private ScopeResolverInterface $scopeResolver;
71+
6672
/**
6773
* @param ResourceConnection $resourceConnection
6874
* @param CategoryMainQuery $categoryMainQuery
@@ -71,6 +77,7 @@ class Categories implements DataProcessorInterface
7177
* @param EntityEavAttributesResolver $entityEavAttributesResolver
7278
* @param CategoryUrlPathBuilder|null $urlPathBuilder
7379
* @param AncestorStatusProvider|null $ancestorStatusProvider
80+
* @param ScopeResolverInterface|null $scopeResolver
7481
*/
7582
public function __construct(
7683
ResourceConnection $resourceConnection,
@@ -79,7 +86,8 @@ public function __construct(
7986
LoggerInterface $logger,
8087
EntityEavAttributesResolver $entityEavAttributesResolver,
8188
?CategoryUrlPathBuilder $urlPathBuilder = null,
82-
?AncestorStatusProvider $ancestorStatusProvider = null
89+
?AncestorStatusProvider $ancestorStatusProvider = null,
90+
?ScopeResolverInterface $scopeResolver = null
8391
) {
8492
$this->resourceConnection = $resourceConnection;
8593
$this->categoryMainQuery = $categoryMainQuery;
@@ -89,6 +97,7 @@ public function __construct(
8997
$this->urlPathBuilder = $urlPathBuilder ?? ObjectManager::getInstance()->get(CategoryUrlPathBuilder::class);
9098
$this->ancestorStatusProvider = $ancestorStatusProvider
9199
?? ObjectManager::getInstance()->get(AncestorStatusProvider::class);
100+
$this->scopeResolver = $scopeResolver ?? ObjectManager::getInstance()->get(ScopeResolverInterface::class);
92101
}
93102

94103
/**
@@ -107,7 +116,7 @@ public function execute(
107116
$lastChunk = null
108117
): void {
109118
try {
110-
foreach ($this->getDataBatch($arguments, $metadata->getBatchSize()) as $dataBatch) {
119+
foreach ($this->getDataBatch($arguments, $metadata) as $dataBatch) {
111120
$output = [];
112121
[$mappedCategories, $attributesData] = $dataBatch;
113122
foreach ($mappedCategories as $storeCode => $categories) {
@@ -147,42 +156,77 @@ public function get(array $values) : array
147156
* Returns data batch.
148157
*
149158
* @param array $arguments
150-
* @param int $batchSize
159+
* @param FeedIndexMetadata $metadata
151160
* @return \Generator
152161
* @throws \Zend_Db_Statement_Exception
153162
*/
154-
private function getDataBatch(array $arguments, int $batchSize): \Generator
163+
private function getDataBatch(array $arguments, FeedIndexMetadata $metadata): \Generator
155164
{
165+
$batchSize = $metadata->getBatchSize();
156166
$itemN = 0;
157167
$queryArguments = [];
158168
$mappedCategories = [];
159169
$attributesData = [];
170+
$explicitScopes = false;
160171
foreach ($arguments as $value) {
161-
$scope = $value['scopeId'] ?? Store::DEFAULT_STORE_ID;
172+
if (isset($value['scopeId'])) {
173+
$explicitScopes = true;
174+
$scope = $value['scopeId'];
175+
} else {
176+
$scope = Store::DEFAULT_STORE_ID;
177+
}
162178
$queryArguments[$scope][$value['categoryId']] = $value['attribute_ids'] ?? [];
163179
}
164180

165181
$connection = $this->resourceConnection->getConnection();
166182
foreach ($queryArguments as $scopeId => $categoryData) {
167-
$cursor = $connection->query(
168-
$this->categoryMainQuery->getQuery(\array_keys($categoryData), $scopeId ?: null)
169-
);
183+
foreach ($this->resolveScopeBatches((int)$scopeId, $explicitScopes, $metadata) as $scopeBatch) {
184+
$cursor = $connection->query(
185+
$this->categoryMainQuery->getQuery(\array_keys($categoryData), $scopeBatch)
186+
);
170187

171-
while ($row = $cursor->fetch()) {
172-
$itemN++;
173-
$mappedCategories[$row['storeViewCode']][$row['categoryId']] = $row;
174-
$attributesData[$row['storeViewCode']][$row['categoryId']] = $categoryData[$row['categoryId']];
175-
if ($itemN % $batchSize == 0) {
176-
yield [$mappedCategories, $attributesData];
177-
$mappedCategories = [];
178-
$attributesData = [];
188+
while ($row = $cursor->fetch()) {
189+
$itemN++;
190+
$mappedCategories[$row['storeViewCode']][$row['categoryId']] = $row;
191+
$attributesData[$row['storeViewCode']][$row['categoryId']] = $categoryData[$row['categoryId']];
192+
if ($itemN % $batchSize == 0) {
193+
yield [$mappedCategories, $attributesData];
194+
$mappedCategories = [];
195+
$attributesData = [];
196+
}
179197
}
180198
}
181199
}
182200

183201
yield [$mappedCategories, $attributesData];
184202
}
185203

204+
/**
205+
* Resolve the store view id batches to extract for a given argument scope group.
206+
*
207+
* Honors an explicit non-default per-item scopeId as a single-store extraction (backward
208+
* compatibility); otherwise the scope resolver decides which store views to extract (all by
209+
* default, discoverable ones under ACO), chunked by the configured store-view batch size.
210+
*
211+
* @param int $scopeId
212+
* @param bool $explicitScopes
213+
* @param FeedIndexMetadata $metadata
214+
* @return array
215+
*/
216+
private function resolveScopeBatches(int $scopeId, bool $explicitScopes, FeedIndexMetadata $metadata): array
217+
{
218+
if ($explicitScopes && $scopeId !== Store::DEFAULT_STORE_ID) {
219+
return [[$scopeId]];
220+
}
221+
222+
$scopeIds = $this->scopeResolver->getScopes($metadata);
223+
if (empty($scopeIds)) {
224+
return [];
225+
}
226+
227+
return \array_chunk($scopeIds, $metadata->getStoreViewBatchSize());
228+
}
229+
186230
/**
187231
* Computes urlPath from url_key EAV values and injects it into each category row.
188232
*

CatalogDataExporter/Model/Provider/Product/CustomOptions.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ private function addValues(array $productOptions, ?string $storeViewCode): array
9898
foreach ($productOptions as $option) {
9999
$optionIds[] = $option['option_id'];
100100
}
101+
if (empty($optionIds)) {
102+
return $productOptions;
103+
}
101104
$optionValues = $this->customOptionValues->query(
102105
[
103106
'option_ids' => $optionIds,

CatalogDataExporter/Model/Provider/ProductMetadata.php

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
use Magento\CatalogDataExporter\Model\Query\ProductMetadataQuery;
1212
use Magento\DataExporter\Exception\UnableRetrieveData;
1313
use Magento\DataExporter\Export\DataProcessorInterface;
14+
use Magento\DataExporter\Export\ScopeResolverInterface;
1415
use Magento\DataExporter\Model\Indexer\FeedIndexMetadata;
16+
use Magento\Framework\App\ObjectManager;
1517
use Magento\Framework\App\ResourceConnection;
1618
use Magento\DataExporter\Model\Logging\CommerceDataExportLoggerInterface as LoggerInterface;
1719

@@ -55,22 +57,30 @@ class ProductMetadata implements DataProcessorInterface
5557
*/
5658
private $logger;
5759

60+
/**
61+
* @var ScopeResolverInterface
62+
*/
63+
private ScopeResolverInterface $scopeResolver;
64+
5865
/**
5966
* @param ResourceConnection $resourceConnection
6067
* @param ProductMetadataQuery $productMetadataQuery
6168
* @param FormatterInterface $formatter
6269
* @param LoggerInterface $logger
70+
* @param ScopeResolverInterface|null $scopeResolver
6371
*/
6472
public function __construct(
6573
ResourceConnection $resourceConnection,
6674
ProductMetadataQuery $productMetadataQuery,
6775
FormatterInterface $formatter,
68-
LoggerInterface $logger
76+
LoggerInterface $logger,
77+
?ScopeResolverInterface $scopeResolver = null
6978
) {
7079
$this->resourceConnection = $resourceConnection;
7180
$this->productMetadataQuery = $productMetadataQuery;
7281
$this->formatter = $formatter;
7382
$this->logger = $logger;
83+
$this->scopeResolver = $scopeResolver ?? ObjectManager::getInstance()->get(ScopeResolverInterface::class);
7484
}
7585

7686
/**
@@ -109,17 +119,36 @@ public function execute(
109119
$node = null,
110120
$info = null
111121
): void {
112-
$output = [];
113122
$queryArguments = [];
114123
try {
115124
foreach ($arguments as $value) {
116125
$queryArguments['id'][$value['id']] = $value['id'];
117126
}
127+
if (empty($queryArguments)) {
128+
$dataProcessorCallback($this->get([]));
129+
return;
130+
}
131+
118132
$connection = $this->resourceConnection->getConnection();
119-
$select = $this->productMetadataQuery->getQuery($queryArguments);
120-
$cursor = $connection->query($select);
121-
while ($row = $cursor->fetch()) {
122-
$output[] = $this->format($row);
133+
$scopeIds = $this->scopeResolver->getScopes($metadata);
134+
$scopeBatches = empty($scopeIds)
135+
? []
136+
: \array_chunk($scopeIds, $metadata->getStoreViewBatchSize());
137+
138+
// no store views to extract (e.g. all non-discoverable) - stream empty so downstream can delete
139+
if (empty($scopeBatches)) {
140+
$dataProcessorCallback($this->get([]));
141+
return;
142+
}
143+
144+
foreach ($scopeBatches as $scopeBatch) {
145+
$output = [];
146+
$select = $this->productMetadataQuery->getQuery($queryArguments, $scopeBatch);
147+
$cursor = $connection->query($select);
148+
while ($row = $cursor->fetch()) {
149+
$output[] = $this->format($row);
150+
}
151+
$dataProcessorCallback($this->get($output));
123152
}
124153
} catch (\Throwable $exception) {
125154
throw new UnableRetrieveData(
@@ -128,8 +157,6 @@ public function execute(
128157
$exception
129158
);
130159
}
131-
132-
$dataProcessorCallback($this->get($output));
133160
}
134161

135162
/**

0 commit comments

Comments
 (0)