Skip to content

Commit 70cbb64

Browse files
committed
B2B-2677: [MediaGallery]Implement data caching for GraphQL results on resolver level
- Ensure orphaned cache ids are removed from cache tag files
1 parent 9796ff2 commit 70cbb64

File tree

5 files changed

+135
-29
lines changed

5 files changed

+135
-29
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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\CatalogGraphQl\Model\Resolver\Cache\Product\MediaGallery;
9+
10+
use Magento\Catalog\Model\Product;
11+
use Magento\CatalogGraphQl\Model\Resolver\Product\MediaGallery\ChangeDetector;
12+
use Magento\Framework\App\Cache\Tag\StrategyInterface;
13+
14+
class TagsStrategy implements StrategyInterface
15+
{
16+
/**
17+
* @var ChangeDetector
18+
*/
19+
private $mediaGalleryChangeDetector;
20+
21+
/**
22+
* @param ChangeDetector $mediaGalleryChangeDetector
23+
*/
24+
public function __construct(ChangeDetector $mediaGalleryChangeDetector)
25+
{
26+
$this->mediaGalleryChangeDetector = $mediaGalleryChangeDetector;
27+
}
28+
29+
/**
30+
* @inheritDoc
31+
*/
32+
public function getTags($object)
33+
{
34+
if ($object instanceof Product &&
35+
!$object->isObjectNew() &&
36+
$this->mediaGalleryChangeDetector->isChanged($object)
37+
) {
38+
return [
39+
sprintf('%s_%s', ResolverCacheIdentity::CACHE_TAG, $object->getSku())
40+
];
41+
}
42+
43+
return [];
44+
}
45+
}

app/code/Magento/CatalogGraphQl/Plugin/Product/UpdateIdentities.php renamed to app/code/Magento/CatalogGraphQl/Model/Resolver/Product/MediaGallery/ChangeDetector.php

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
*/
66
declare(strict_types=1);
77

8-
namespace Magento\CatalogGraphQl\Plugin\Product;
8+
namespace Magento\CatalogGraphQl\Model\Resolver\Product\MediaGallery;
99

1010
use Magento\Catalog\Model\Product;
11-
use Magento\CatalogGraphQl\Model\Resolver\Cache\Product\MediaGallery\ResolverCacheIdentity;
1211
use Magento\Framework\Serialize\SerializerInterface;
1312

14-
/**
15-
* This is a plugin to \Magento\Catalog\Model\Product.
16-
* It is used to add media gallery identities to product identities for invalidation purposes.
17-
*/
18-
class UpdateIdentities
13+
class ChangeDetector
1914
{
2015
/**
2116
* @var SerializerInterface
@@ -31,29 +26,18 @@ public function __construct(
3126
$this->serializer = $serializer;
3227
}
3328

34-
/**
35-
* Flag product media gallery as changed after adding or updating image, or on product removal
36-
*
37-
* @param Product $subject
38-
* @param array $result
39-
* @return array
40-
*/
41-
public function afterGetIdentities(Product $subject, array $result): array
42-
{
43-
if (!$subject->isObjectNew() && ($subject->isDeleted() || $this->isMediaGalleryChanged($subject))) {
44-
$result[] = sprintf('%s_%s', ResolverCacheIdentity::CACHE_TAG, $subject->getSku());
45-
}
46-
return $result;
47-
}
48-
4929
/**
5030
* Check if the media gallery of the given product is changed
5131
*
5232
* @param Product $product
5333
* @return bool
5434
*/
55-
private function isMediaGalleryChanged(Product $product): bool
35+
public function isChanged(Product $product): bool
5636
{
37+
if ($product->isDeleted()) {
38+
return true;
39+
}
40+
5741
if (!$product->hasDataChanges()) {
5842
return false;
5943
}

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,13 @@
125125
</argument>
126126
</arguments>
127127
</type>
128-
<type name="Magento\Catalog\Model\Product">
129-
<plugin name="add_media_gallery_identities" type="Magento\CatalogGraphQl\Plugin\Product\UpdateIdentities"/>
128+
<type name="Magento\GraphQlResolverCache\App\Cache\Tag\Strategy\Locator">
129+
<arguments>
130+
<argument name="customStrategies" xsi:type="array">
131+
<item name="Magento\Catalog\Api\Data\ProductInterface" xsi:type="object">
132+
Magento\CatalogGraphQl\Model\Resolver\Cache\Product\MediaGallery\TagsStrategy
133+
</item>
134+
</argument>
135+
</arguments>
130136
</type>
131137
</config>
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
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\GraphQlResolverCache\App\Cache\Tag\Strategy;
9+
10+
use Magento\Framework\App\Cache\Tag\StrategyInterface;
11+
12+
/**
13+
* Locate GraphQL resolver cache tag strategy using configuration
14+
*/
15+
class Locator
16+
{
17+
/**
18+
* Strategies map
19+
*
20+
* @var array
21+
*/
22+
private $customStrategies = [];
23+
24+
/**
25+
* @param array $customStrategies
26+
*/
27+
public function __construct(
28+
array $customStrategies = []
29+
) {
30+
$this->customStrategies = $customStrategies;
31+
}
32+
33+
/**
34+
* Return GraphQL Resolver Cache tag strategy for specified object
35+
*
36+
* @param object $object
37+
* @throws \InvalidArgumentException
38+
* @return StrategyInterface|null
39+
*/
40+
public function getStrategy($object): ?StrategyInterface
41+
{
42+
if (!is_object($object)) {
43+
throw new \InvalidArgumentException('Provided argument is not an object');
44+
}
45+
46+
$classHierarchy = array_merge(
47+
[get_class($object) => get_class($object)],
48+
class_parents($object),
49+
class_implements($object)
50+
);
51+
52+
$result = array_intersect(array_keys($this->customStrategies), $classHierarchy);
53+
54+
return $this->customStrategies[array_shift($result)] ?? null;
55+
}
56+
}

app/code/Magento/GraphQlResolverCache/Model/Resolver/Result/TagResolver.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,16 @@
88
namespace Magento\GraphQlResolverCache\Model\Resolver\Result;
99

1010
use Magento\Framework\App\Cache\Tag\Resolver;
11-
use Magento\Framework\App\Cache\Tag\Strategy\Factory as StrategyFactory;
11+
use Magento\Framework\App\Cache\Tag\Strategy\Factory as OtherCachesStrategyFactory;
12+
use Magento\GraphQlResolverCache\App\Cache\Tag\Strategy\Locator as ResolverCacheStrategyLocator;
1213

1314
class TagResolver extends Resolver
1415
{
16+
/**
17+
* @var ResolverCacheStrategyLocator
18+
*/
19+
private $resolverCacheTagStrategyLocator;
20+
1521
/**
1622
* @var array
1723
*/
@@ -20,16 +26,19 @@ class TagResolver extends Resolver
2026
/**
2127
* GraphQL Resolver cache-specific tag resolver for the purpose of invalidation
2228
*
23-
* @param StrategyFactory $factory
29+
* @param ResolverCacheStrategyLocator $resolverCacheStrategyLocator
30+
* @param OtherCachesStrategyFactory $otherCachesStrategyFactory
2431
* @param array $invalidatableObjectTypes
2532
*/
2633
public function __construct(
27-
StrategyFactory $factory,
34+
ResolverCacheStrategyLocator $resolverCacheStrategyLocator,
35+
OtherCachesStrategyFactory $otherCachesStrategyFactory,
2836
array $invalidatableObjectTypes = []
2937
) {
38+
$this->resolverCacheTagStrategyLocator = $resolverCacheStrategyLocator;
3039
$this->invalidatableObjectTypes = $invalidatableObjectTypes;
3140

32-
parent::__construct($factory);
41+
parent::__construct($otherCachesStrategyFactory);
3342
}
3443

3544
/**
@@ -51,6 +60,12 @@ public function getTags($object)
5160
return [];
5261
}
5362

63+
$resolverCacheTagStrategy = $this->resolverCacheTagStrategyLocator->getStrategy($object);
64+
65+
if ($resolverCacheTagStrategy) {
66+
return $resolverCacheTagStrategy->getTags($object);
67+
}
68+
5469
return parent::getTags($object);
5570
}
5671
}

0 commit comments

Comments
 (0)