1515use Magento \CatalogDataExporter \Model \Query \CategoryMainQuery ;
1616use Magento \DataExporter \Exception \UnableRetrieveData ;
1717use Magento \DataExporter \Export \DataProcessorInterface ;
18+ use Magento \DataExporter \Export \ScopeResolverInterface ;
1819use Magento \DataExporter \Model \Indexer \FeedIndexMetadata ;
1920use Magento \Framework \App \ObjectManager ;
2021use 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 *
0 commit comments