Skip to content

Commit a3fbbfa

Browse files
committed
B2B-2258: Add caching capability to the storeConfig GraphQl query
1 parent 9d9bcd6 commit a3fbbfa

File tree

4 files changed

+213
-17
lines changed

4 files changed

+213
-17
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<?php
2+
/**
3+
* Copyright © Magento, Inc. All rights reserved.
4+
* See COPYING.txt for license details.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\StoreGraphQl\Plugin;
9+
10+
use Magento\StoreGraphQl\Model\Resolver\Store\ConfigIdentity;
11+
12+
/**
13+
* Store group plugin
14+
*/
15+
class Group
16+
{
17+
/**
18+
* Add graphql store config tag to the store group cache identities.
19+
*
20+
* @param \Magento\Store\Model\Group $subject
21+
* @param array $result
22+
* @return array
23+
*/
24+
public function afterGetIdentities(\Magento\Store\Model\Group $subject, array $result): array
25+
{
26+
$storeIds = $subject->getStoreIds();
27+
foreach ($storeIds as $storeId) {
28+
$result[] = sprintf('%s_%s', ConfigIdentity::CACHE_TAG, $storeId);
29+
}
30+
return $result;
31+
}
32+
}

app/code/Magento/StoreGraphQl/etc/di.xml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@
1414
</arguments>
1515
</type>
1616
<type name="Magento\Store\Model\Store">
17-
<plugin name="getIdentities" type="Magento\StoreGraphQl\Plugin\Store" />
17+
<plugin name="getStoreIdentities" type="Magento\StoreGraphQl\Plugin\Store" />
1818
</type>
1919
<type name="Magento\Store\Model\Website">
20-
<plugin name="getIdentities" type="Magento\StoreGraphQl\Plugin\Website" />
20+
<plugin name="getWebsiteIdentities" type="Magento\StoreGraphQl\Plugin\Website" />
21+
</type>
22+
<type name="Magento\Store\Model\Group">
23+
<plugin name="getGroupIdentities" type="Magento\StoreGraphQl\Plugin\Group" />
2124
</type>
2225
</config>

dev/tests/api-functional/testsuite/Magento/GraphQl/Store/StoreConfigCacheTest.php

Lines changed: 162 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Magento\Store\Api\StoreConfigManagerInterface;
1515
use Magento\Store\Api\StoreRepositoryInterface;
1616
use Magento\Store\Api\StoreResolverInterface;
17+
use Magento\Store\Model\Group;
1718
use Magento\Store\Model\ScopeInterface;
1819
use Magento\Store\Model\Store;
1920
use Magento\TestFramework\App\ApiMutableScopeConfig;
@@ -152,7 +153,7 @@ public function testGetStoreConfig(): void
152153
* Store scoped config change triggers purging only the cache of the changed store.
153154
*
154155
* @magentoConfigFixture default/system/full_page_cache/caching_application 2
155-
* @magentoApiDataFixture Magento/Store/_files/multiple_websites_with_store_groups_stores.php
156+
* @magentoApiDataFixture Magento/Store/_files/store.php
156157
* @throws NoSuchEntityException
157158
*/
158159
public function testCachePurgedWithStoreScopeConfigChange(): void
@@ -177,11 +178,11 @@ public function testCachePurgedWithStoreScopeConfigChange(): void
177178
$this->assertEquals($defaultStoreCode, $defaultStoreResponseResult['code']);
178179
$this->assertEquals($defaultLocale, $defaultStoreResponseResult['locale']);
179180

180-
// Query test store config
181-
$secondStoreCode = 'second_store_view';
182-
$responseTestStore = $this->graphQlQueryWithResponseHeaders($query, [], '', ['Store' => $secondStoreCode]);
183-
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseTestStore['headers']);
184-
$secondStoreCacheId = $responseTestStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
181+
// Query second store config
182+
$secondStoreCode = 'test';
183+
$responseSecondStore = $this->graphQlQueryWithResponseHeaders($query, [], '', ['Store' => $secondStoreCode]);
184+
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseSecondStore['headers']);
185+
$secondStoreCacheId = $responseSecondStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
185186
$this->assertNotEquals($secondStoreCacheId, $defaultStoreCacheId);
186187
// Verify we obtain a cache MISS at the 1st time
187188
$secondStoreResponse = $this->assertCacheMissAndReturnResponse(
@@ -244,7 +245,7 @@ public function testCachePurgedWithStoreScopeConfigChange(): void
244245
* Store change triggers purging only the cache of the changed store.
245246
*
246247
* @magentoConfigFixture default/system/full_page_cache/caching_application 2
247-
* @magentoApiDataFixture Magento/Store/_files/multiple_websites_with_store_groups_stores.php
248+
* @magentoApiDataFixture Magento/Store/_files/store.php
248249
* @throws NoSuchEntityException
249250
*/
250251
public function testCachePurgedWithStoreChange(): void
@@ -270,10 +271,10 @@ public function testCachePurgedWithStoreChange(): void
270271
$this->assertEquals($defaultLocale, $defaultStoreResponseResult['locale']);
271272

272273
// Query second store config
273-
$secondStoreCode = 'second_store_view';
274-
$responseTestStore = $this->graphQlQueryWithResponseHeaders($query, [], '', ['Store' => $secondStoreCode]);
275-
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseTestStore['headers']);
276-
$secondStoreCacheId = $responseTestStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
274+
$secondStoreCode = 'test';
275+
$responseSecondStore = $this->graphQlQueryWithResponseHeaders($query, [], '', ['Store' => $secondStoreCode]);
276+
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseSecondStore['headers']);
277+
$secondStoreCacheId = $responseSecondStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
277278
$this->assertNotEquals($secondStoreCacheId, $defaultStoreCacheId);
278279
// Verify we obtain a cache MISS at the 1st time
279280
$secondStoreResponse = $this->assertCacheMissAndReturnResponse(
@@ -286,18 +287,18 @@ public function testCachePurgedWithStoreChange(): void
286287
$this->assertArrayHasKey('storeConfig', $secondStoreResponse['body']);
287288
$secondStoreResponseResult = $secondStoreResponse['body']['storeConfig'];
288289
$this->assertEquals($secondStoreCode, $secondStoreResponseResult['code']);
289-
$secondStoreName = 'Second Store View';
290+
$secondStoreName = 'Test Store';
290291
$this->assertEquals($secondStoreName, $secondStoreResponseResult['store_name']);
291292

292-
// Change store name
293+
// Change second store name
293294
/** @var Store $store */
294295
$store = $this->objectManager->create(Store::class);
295296
$store->load($secondStoreCode, 'code');
296297
$secondStoreNewName = $secondStoreName . ' 2';
297298
$store->setName($secondStoreNewName);
298299
$store->save();
299300

300-
// Query default store config after test store config change
301+
// Query default store config after second store is changed
301302
// Verify we obtain a cache HIT at the 2nd time, the cache is not purged
302303
$defaultStoreResponseHit = $this->assertCacheHitAndReturnResponse(
303304
$query,
@@ -310,7 +311,7 @@ public function testCachePurgedWithStoreChange(): void
310311
$this->assertEquals($defaultLocale, $defaultStoreResponseHitResult['locale']);
311312
$this->assertEquals($defaultStoreResponseResult['store_name'], $defaultStoreResponseHitResult['store_name']);
312313

313-
// Query second store config after second store config is changed
314+
// Query second store config after second store is changed
314315
// Verify we obtain a cache MISS at the 2nd time, the cache is purged
315316
$secondStoreResponseMiss = $this->assertCacheMissAndReturnResponse(
316317
$query,
@@ -337,6 +338,152 @@ public function testCachePurgedWithStoreChange(): void
337338
$this->assertEquals($secondStoreNewName, $secondStoreResponseHitResult['store_name']);
338339
}
339340

341+
/**
342+
* Store group change triggers purging only the cache of the stores associated with the changed store group.
343+
*
344+
* @magentoConfigFixture default/system/full_page_cache/caching_application 2
345+
* @magentoApiDataFixture Magento/Store/_files/multiple_websites_with_store_groups_stores.php
346+
* @throws NoSuchEntityException
347+
*/
348+
public function testCachePurgedWithStoreGroupChange(): void
349+
{
350+
$this->changeToOneWebsiteTwoStoreGroupsThreeStores();
351+
$query = $this->getQuery();
352+
353+
// Query default store config
354+
$responseDefaultStore = $this->graphQlQueryWithResponseHeaders($query);
355+
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseDefaultStore['headers']);
356+
$defaultStoreCacheId = $responseDefaultStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
357+
// Verify we obtain a cache MISS at the 1st time
358+
$this->assertCacheMissAndReturnResponse(
359+
$query,
360+
[CacheIdCalculator::CACHE_ID_HEADER => $defaultStoreCacheId]
361+
);
362+
363+
// Query second store config
364+
$secondStoreCode = 'second_store_view';
365+
$responseThirdStore = $this->graphQlQueryWithResponseHeaders(
366+
$query,
367+
[],
368+
'',
369+
['Store' => $secondStoreCode]
370+
);
371+
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseThirdStore['headers']);
372+
$secondStoreCacheId = $responseThirdStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
373+
$this->assertNotEquals($secondStoreCacheId, $defaultStoreCacheId);
374+
// Verify we obtain a cache MISS at the 1st time
375+
$secondStoreResponse = $this->assertCacheMissAndReturnResponse(
376+
$query,
377+
[
378+
CacheIdCalculator::CACHE_ID_HEADER => $secondStoreCacheId,
379+
'Store' => $secondStoreCode
380+
]
381+
);
382+
$this->assertArrayHasKey('storeConfig', $secondStoreResponse['body']);
383+
$secondStoreResponseResult = $secondStoreResponse['body']['storeConfig'];
384+
$secondStoreGroupName = 'Second store group';
385+
$this->assertEquals($secondStoreGroupName, $secondStoreResponseResult['store_group_name']);
386+
387+
// Query third store config
388+
$thirdStoreCode = 'third_store_view';
389+
$responseThirdStore = $this->graphQlQueryWithResponseHeaders(
390+
$query,
391+
[],
392+
'',
393+
['Store' => $thirdStoreCode]
394+
);
395+
$this->assertArrayHasKey(CacheIdCalculator::CACHE_ID_HEADER, $responseThirdStore['headers']);
396+
$thirdStoreCacheId = $responseThirdStore['headers'][CacheIdCalculator::CACHE_ID_HEADER];
397+
// Verify we obtain a cache MISS at the 1st time
398+
$thirdStoreResponse = $this->assertCacheMissAndReturnResponse(
399+
$query,
400+
[
401+
CacheIdCalculator::CACHE_ID_HEADER => $thirdStoreCacheId,
402+
'Store' => $thirdStoreCode
403+
]
404+
);
405+
$this->assertArrayHasKey('storeConfig', $thirdStoreResponse['body']);
406+
$thirdStoreResponseResult = $thirdStoreResponse['body']['storeConfig'];
407+
$this->assertEquals($secondStoreGroupName, $thirdStoreResponseResult['store_group_name']);
408+
409+
// Change store group name
410+
/** @var Group $storeGroup */
411+
$storeGroup = $this->objectManager->create(Group::class);
412+
$storeGroup->load('second_store', 'code');
413+
$secondStoreGroupNewName = $secondStoreGroupName . ' 2';
414+
$storeGroup->setName($secondStoreGroupNewName);
415+
$storeGroup->save();
416+
417+
// Query default store config after second store group is changed
418+
// Verify we obtain a cache HIT at the 2nd time, the cache is not purged
419+
$this->assertCacheHitAndReturnResponse(
420+
$query,
421+
[CacheIdCalculator::CACHE_ID_HEADER => $defaultStoreCacheId]
422+
);
423+
424+
// Query second store config after its associated second store group is changed
425+
// Verify we obtain a cache MISS at the 2nd time, the cache is purged
426+
$secondStoreResponseMiss = $this->assertCacheMissAndReturnResponse(
427+
$query,
428+
[
429+
CacheIdCalculator::CACHE_ID_HEADER => $secondStoreCacheId,
430+
'Store' => $secondStoreCode
431+
]
432+
);
433+
$this->assertArrayHasKey('storeConfig', $secondStoreResponseMiss['body']);
434+
$secondStoreResponseMissResult = $secondStoreResponseMiss['body']['storeConfig'];
435+
$this->assertEquals($secondStoreGroupNewName, $secondStoreResponseMissResult['store_group_name']);
436+
// Verify we obtain a cache HIT at the 3rd time
437+
$this->assertCacheHitAndReturnResponse(
438+
$query,
439+
[
440+
CacheIdCalculator::CACHE_ID_HEADER => $secondStoreCacheId,
441+
'Store' => $secondStoreCode
442+
]
443+
);
444+
445+
// Query third store config after its associated second store group is changed
446+
// Verify we obtain a cache MISS at the 2nd time, the cache is purged
447+
$thirdStoreResponseMiss = $this->assertCacheMissAndReturnResponse(
448+
$query,
449+
[
450+
CacheIdCalculator::CACHE_ID_HEADER => $thirdStoreCacheId,
451+
'Store' => $thirdStoreCode
452+
]
453+
);
454+
$this->assertArrayHasKey('storeConfig', $thirdStoreResponseMiss['body']);
455+
$thirdStoreResponseMissResult = $thirdStoreResponseMiss['body']['storeConfig'];
456+
$this->assertEquals($secondStoreGroupNewName, $thirdStoreResponseMissResult['store_group_name']);
457+
// Verify we obtain a cache HIT at the 3rd time
458+
$this->assertCacheHitAndReturnResponse(
459+
$query,
460+
[
461+
CacheIdCalculator::CACHE_ID_HEADER => $thirdStoreCacheId,
462+
'Store' => $thirdStoreCode
463+
]
464+
);
465+
}
466+
467+
private function changeToOneWebsiteTwoStoreGroupsThreeStores()
468+
{
469+
// Change second store to the same website of the default store
470+
/** @var Store $store2 */
471+
$store2 = $this->objectManager->create(Store::class);
472+
$store2->load('second_store_view', 'code');
473+
$store2GroupId = $store2->getStoreGroupId();
474+
/** @var Group $store2Group */
475+
$store2Group = $this->objectManager->create(Group::class);
476+
$store2Group->load($store2GroupId);
477+
$store2Group->setWebsiteId(1)->save();
478+
$store2->setWebsiteId(1)->save();
479+
480+
// Change third store to the same store group and website of second store
481+
/** @var Store $store3 */
482+
$store3 = $this->objectManager->create(Store::class);
483+
$store3->load('third_store_view', 'code');
484+
$store3->setGroupId($store2GroupId)->setWebsiteId(1)->save();
485+
}
486+
340487
/**
341488
* Get query
342489
*

dev/tests/integration/testsuite/Magento/Store/_files/multiple_websites_with_store_groups_stores_rollback.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,20 @@
2323
$website2->delete();
2424
}
2525

26+
/** Delete the second store groups **/
27+
$group = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Group::class);
28+
/** @var $group \Magento\Store\Model\Group */
29+
$groupId = $group->load('second_store', 'code')->getId();
30+
if ($groupId) {
31+
$group->delete();
32+
}
33+
$group2 = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Group::class);
34+
/** @var $group2 \Magento\Store\Model\Group */
35+
$groupId2 = $group2->load('third_store', 'code')->getId();
36+
if ($groupId2) {
37+
$group2->delete();
38+
}
39+
2640
$store = \Magento\TestFramework\Helper\Bootstrap::getObjectManager()->create(\Magento\Store\Model\Store::class);
2741
if ($store->load('second_store_view', 'code')->getId()) {
2842
$store->delete();

0 commit comments

Comments
 (0)