Skip to content

Commit b6db71c

Browse files
committed
OXDEV-9930 Cache chain
1 parent 896f110 commit b6db71c

5 files changed

Lines changed: 90 additions & 9 deletions

File tree

CHANGELOG-2.x.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
### Added
66
- Template Filter to sanitize HTML content
77
- PHP v8.5 support
8+
- Cache template chains to improve rendering performance
89

910
### Changed
1011
- Extension include_content uses HTML sanitizer

src/Resolver/TemplateChain/TemplateChainResolver.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
class TemplateChainResolver implements TemplateChainResolverInterface
1515
{
1616
private array $lastChildCache = [];
17+
private array $parentCache = [];
1718

1819
public function __construct(
1920
private TemplateChainBuilderInterface $templateChainBuilder,
@@ -23,11 +24,15 @@ public function __construct(
2324

2425
public function getParent(string $templateName): string
2526
{
26-
$templateType = $this->templateTypeFactory->createFromTemplateName($templateName);
27-
return $this->templateChainBuilder
28-
->getChain($templateType)
29-
->getParent($templateType)
30-
->getFullyQualifiedName();
27+
if (!isset($this->parentCache[$templateName])) {
28+
$templateType = $this->templateTypeFactory->createFromTemplateName($templateName);
29+
$this->parentCache[$templateName] = $this->templateChainBuilder
30+
->getChain($templateType)
31+
->getParent($templateType)
32+
->getFullyQualifiedName();
33+
}
34+
35+
return $this->parentCache[$templateName];
3136
}
3237

3338
public function getLastChild(string $templateName): string

src/Resolver/TemplateChain/TemplateChainSorter.php

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
class TemplateChainSorter implements TemplateChainSorterInterface
2020
{
21+
private array $chainCache = [];
22+
2123
public function __construct(
2224
private SortingConfigurationValidatorInterface $sortingConfigurationValidator,
2325
private ShopConfigurationDaoInterface $shopConfigurationDao,
@@ -28,11 +30,15 @@ public function __construct(
2830

2931
public function sort(TemplateChain $unsortedChain, TemplateTypeInterface $extendedTemplate): TemplateChain
3032
{
31-
$sortingConfiguration = $this->shopConfigurationDao
32-
->get($this->context->getCurrentShopId())
33-
->getModuleTemplateExtensionChain();
33+
$shopId = $this->context->getCurrentShopId();
34+
35+
if (!isset($this->chainCache[$shopId])) {
36+
$this->chainCache[$shopId] = $this->shopConfigurationDao
37+
->get($shopId)
38+
->getModuleTemplateExtensionChain();
39+
}
3440

35-
return $this->getSortedChain($unsortedChain, $sortingConfiguration, $extendedTemplate);
41+
return $this->getSortedChain($unsortedChain, $this->chainCache[$shopId], $extendedTemplate);
3642
}
3743

3844
private function getSortedChain(

tests/Unit/Resolver/TemplateChain/TemplateChainResolverTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,39 @@
1818

1919
final class TemplateChainResolverTest extends TestCase
2020
{
21+
public function testGetParentWithMultipleCallsWillUseCachedResult(): void
22+
{
23+
$templateName = 'widget/header.html.twig';
24+
25+
$templateTypeMock = $this->createMock(TemplateTypeInterface::class);
26+
$parentMock = $this->createConfiguredMock(TemplateTypeInterface::class, [
27+
'getFullyQualifiedName' => '@my_module/widget/header.html.twig'
28+
]);
29+
$templateChainMock = $this->createConfiguredMock(TemplateChain::class, [
30+
'getParent' => $parentMock
31+
]);
32+
33+
$templateTypeFactoryMock = $this->createMock(TemplateTypeFactoryInterface::class);
34+
$templateTypeFactoryMock
35+
->expects($this->once())
36+
->method('createFromTemplateName')
37+
->with($templateName)
38+
->willReturn($templateTypeMock);
39+
40+
$templateChainBuilderMock = $this->createMock(TemplateChainBuilderInterface::class);
41+
$templateChainBuilderMock
42+
->expects($this->once())
43+
->method('getChain')
44+
->with($templateTypeMock)
45+
->willReturn($templateChainMock);
46+
47+
$templateChainResolver = new TemplateChainResolver($templateChainBuilderMock, $templateTypeFactoryMock);
48+
49+
$templateChainResolver->getParent($templateName);
50+
$templateChainResolver->getParent($templateName);
51+
$templateChainResolver->getParent($templateName);
52+
}
53+
2154
public function testGetLastChildWithMultipleCallsWillUseCachedResult(): void
2255
{
2356
$templateName = 'widget/header.html.twig';

tests/Unit/Resolver/TemplateChain/TemplateChainSorterTest.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,42 @@ public function testSortWithADuplicatedModuleIdInConfigurationWillCallLogger():
162162
$this->logger->error(Argument::type('string'))->shouldHaveBeenCalled();
163163
}
164164

165+
public function testSortWithMultipleCallsWillUseCachedShopConfiguration(): void
166+
{
167+
$shopId = 1;
168+
$templateModule1 = new ModuleTemplateType('template1', 'module1');
169+
$chain = new TemplateChain();
170+
$chain->append($templateModule1);
171+
172+
$moduleTemplateExtensionsChain = new ModuleTemplateExtensionChain([]);
173+
$shopConfiguration = $this->prophesize(ShopConfiguration::class);
174+
$shopConfiguration->getModuleTemplateExtensionChain()->willReturn($moduleTemplateExtensionsChain);
175+
176+
$shopConfigurationDao = $this->prophesize(ShopConfigurationDaoInterface::class);
177+
$shopConfigurationDao->get($shopId)->willReturn($shopConfiguration)->shouldBeCalledOnce();
178+
179+
$context = $this->prophesize(ContextInterface::class);
180+
$context->getCurrentShopId()->willReturn($shopId);
181+
182+
$this->sortingConfigurationValidator = $this->prophesize(SortingConfigurationValidatorInterface::class);
183+
$this->logger = $this->prophesize(LoggerInterface::class);
184+
185+
$this->chainSorter = new TemplateChainSorter(
186+
$this->sortingConfigurationValidator->reveal(),
187+
$shopConfigurationDao->reveal(),
188+
$context->reveal(),
189+
$this->logger->reveal(),
190+
);
191+
192+
$chain1 = new TemplateChain();
193+
$chain1->append($templateModule1);
194+
$this->chainSorter->sort($chain1, $templateModule1);
195+
196+
$chain2 = new TemplateChain();
197+
$chain2->append($templateModule1);
198+
$this->chainSorter->sort($chain2, $templateModule1);
199+
}
200+
165201
private function prepareChainSortersConfiguration(string $templateName, array $loadOrder): void
166202
{
167203
$shopId = 1;

0 commit comments

Comments
 (0)