Skip to content

Commit 14e3685

Browse files
Caching WiP
1 parent 5305850 commit 14e3685

25 files changed

+291
-161
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
### Added
55
- Check if value outputted in template (or escaped for output) can be converted to string
66
- Support for PHP 8.4
7+
- Caching of collected Latte context (variables, components, templates, ...) to improve performance
78
### Fixed
89
- Fixed unwanted narrowing of template variable types
910

extension.neon

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ services:
103103
- Efabrica\PHPStanLatte\Analyser\AnalysedTemplatesRegistry(@fileExcluderAnalyse, %analysedPaths%, %latte.reportUnanalysedTemplates%)
104104

105105
-
106-
factory: Efabrica\PHPStanLatte\Compiler\CompiledTemplateDirResolver
106+
factory: Efabrica\PHPStanLatte\Temp\TempDirResolver
107107
arguments:
108108
tmpDir: %latte.tmpDir%
109109

@@ -124,7 +124,7 @@ services:
124124
factory: Efabrica\PHPStanLatte\Analyser\LatteContextAnalyser
125125
arguments:
126126
parser: @latteCurrentPhpVersionRichParser
127-
tmpDir: %latte.tmpDir%
127+
debugMode: %debugMode%
128128

129129
# Latte template resolvers
130130
- Efabrica\PHPStanLatte\LatteTemplateResolver\Nette\NetteApplicationUIPresenter

src/Analyser/LatteContextAnalyser.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use Composer\InstalledVersions;
88
use Efabrica\PHPStanLatte\LatteContext\Collector\AbstractLatteContextCollector;
9+
use Efabrica\PHPStanLatte\Temp\TempDirResolver;
910
use Exception;
1011
use InvalidArgumentException;
1112
use Nette\Utils\FileSystem;
@@ -50,8 +51,9 @@ public function __construct(
5051
FileHelper $fileHelper,
5152
Parser $parser,
5253
TypeStringResolver $typeStringResolver,
54+
TempDirResolver $tempDirResolver,
5355
array $collectors,
54-
string $tmpDir
56+
bool $debugMode = false
5557
) {
5658
$this->scopeFactory = $scopeFactory;
5759
$this->nodeScopeResolver = clone $nodeScopeResolver;
@@ -61,8 +63,10 @@ public function __construct(
6163
$this->parser = $parser;
6264
$this->typeStringResolver = $typeStringResolver;
6365
$this->collectorRegistry = new LatteContextCollectorRegistry($collectors);
64-
$baseTmpDir = $tmpDir ? rtrim($tmpDir, '/') : sys_get_temp_dir() . '/phpstan-latte/';
65-
$this->tmpDir = $baseTmpDir . '/latte-context-cache/';
66+
$this->tmpDir = $tempDirResolver->resolveCollectorDir();
67+
if (file_exists($this->tmpDir) && $debugMode) {
68+
FileSystem::delete($this->tmpDir);
69+
}
6670
}
6771

6872
/**
@@ -91,6 +95,7 @@ public function analyseFiles(array $files): LatteContextData
9195
} else {
9296
$errors = array_merge($errors, $fileResult->getErrors());
9397
}
98+
} else {
9499
}
95100
if ($fileResult->getAllCollectedData() !== []) {
96101
$collectedData = array_merge($collectedData, $fileResult->getAllCollectedData());
@@ -194,7 +199,7 @@ private function cacheFilename(string $file): string
194199
PHP_VERSION_ID .
195200
(class_exists(InstalledVersions::class) ? json_encode(InstalledVersions::getAllRawData()) : '')
196201
);
197-
return $this->tmpDir . '/' . basename($file) . '.' . $cacheKey . '.json';
202+
return $this->tmpDir . basename($file) . '.' . $cacheKey . '.json';
198203
}
199204

200205
private function saveLatteContextDataToCache(string $file, LatteContextData $fileResult)

src/Compiler/CompiledTemplateDirResolver.php

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/Compiler/LatteToPhpCompiler.php

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use Composer\InstalledVersions;
88
use Efabrica\PHPStanLatte\Compiler\Compiler\CompilerInterface;
99
use Efabrica\PHPStanLatte\Exception\ParseException;
10+
use Efabrica\PHPStanLatte\Temp\TempDirResolver;
1011
use Efabrica\PHPStanLatte\Template\Template;
1112
use InvalidArgumentException;
1213
use Latte\CompileException;
@@ -15,7 +16,9 @@
1516

1617
final class LatteToPhpCompiler
1718
{
18-
private string $tmpDir;
19+
private string $compileDir;
20+
21+
private string $analyseDir;
1922

2023
private string $cacheKey;
2124

@@ -27,14 +30,18 @@ final class LatteToPhpCompiler
2730

2831
public function __construct(
2932
string $cacheKey,
30-
CompiledTemplateDirResolver $compiledTemplateDirResolver,
33+
TempDirResolver $tempDirResolver,
3134
CompilerInterface $compiler,
3235
Postprocessor $postprocessor,
3336
bool $debugMode = false
3437
) {
35-
$this->tmpDir = $compiledTemplateDirResolver->resolve();
36-
if (file_exists($this->tmpDir) && $debugMode) {
37-
FileSystem::delete($this->tmpDir);
38+
$this->compileDir = $tempDirResolver->resolveCompileDir();
39+
$this->analyseDir = $tempDirResolver->resolveAnalyseDir();
40+
if (file_exists($this->compileDir) && $debugMode) {
41+
FileSystem::delete($this->compileDir);
42+
}
43+
if (file_exists($this->analyseDir)) {
44+
FileSystem::delete($this->analyseDir);
3845
}
3946
$this->cacheKey = $cacheKey . md5(
4047
Engine::VERSION_ID .
@@ -73,11 +80,13 @@ public function compileFile(Template $template, string $context = ''): string
7380
$templateDir = substr($templateDir, strlen($replacedPath));
7481
}
7582

76-
$compileDir = $this->normalizeCompileDir($this->tmpDir . '/' . $templateDir);
83+
$compileDir = $this->normalizeCompileDir($this->compileDir . DIRECTORY_SEPARATOR . $templateDir);
7784
if (!file_exists($compileDir)) {
7885
mkdir($compileDir, 0777, true);
7986
}
80-
$compileFilePath = $compileDir . '/' . $templateFileName . '.' . $contextHash . '.php';
87+
88+
$fileName = $templateFileName . '.' . $contextHash . '.php';
89+
$compileFilePath = $compileDir . DIRECTORY_SEPARATOR . $fileName;
8190

8291
if (!$this->debugMode && file_exists($compileFilePath)) {
8392
require($compileFilePath); // load type definitions from compiled template
@@ -91,7 +100,7 @@ public function compileFile(Template $template, string $context = ''): string
91100

92101
private function normalizeCompileDir(string $compileDir): string
93102
{
94-
$compileDirParts = array_filter(explode('/', $compileDir));
103+
$compileDirParts = array_filter(explode(DIRECTORY_SEPARATOR, $compileDir));
95104
$newCompileDirParts = [];
96105
foreach ($compileDirParts as $compileDirPart) {
97106
if ($compileDirPart === '..') {
@@ -100,6 +109,6 @@ private function normalizeCompileDir(string $compileDir): string
100109
}
101110
$newCompileDirParts[] = $compileDirPart;
102111
}
103-
return '/' . implode('/', $newCompileDirParts);
112+
return DIRECTORY_SEPARATOR . implode(DIRECTORY_SEPARATOR, $newCompileDirParts);
104113
}
105114
}

src/LatteContext/Collector/ComponentCollector.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,6 @@ private function findAssignToThis(Assign $node, Scope $scope, ClassReflection $c
168168
*/
169169
private function buildComponents(Node $node, Scope $scope, ClassReflection $classReflection, Expr $componentNameArg, Expr $componentArg): ?array
170170
{
171-
print_r(['buildcomp']);
172171
$lattePhpDoc = $this->lattePhpDocResolver->resolveForNode($node, $scope);
173172
if ($lattePhpDoc->isIgnored()) {
174173
return null;
@@ -220,11 +219,8 @@ private function buildComponents(Node $node, Scope $scope, ClassReflection $clas
220219
*/
221220
public function addSubcomponents(array $components): array
222221
{
223-
print_r(['subscomponents', count($components)]);
224222
foreach ($components as $component) {
225-
print_r(['class', \get_class($component->getComponentType()), $component->getComponentType() instanceof ObjectType ? $component->getComponentType()->getClassName() : '---']);
226223
if ($component->getComponentType() instanceof ObjectType && (new ObjectType('Nette\Application\UI\Multiplier'))->isSuperTypeOf($component->getComponentType())->yes()) {
227-
print_r(['multiplier']);
228224
$multiplierType = $component->getComponentType()->getAncestorWithClassName('Nette\Application\UI\Multiplier');
229225
if ($multiplierType instanceof GenericObjectType) {
230226
$subComponentType = $multiplierType->getTypes()[0] ?? null;

src/LatteContext/Finder/ComponentFinder.php

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ final class ComponentFinder
2424

2525
private MethodCallFinder $methodCallFinder;
2626

27+
private $findCache = [];
28+
2729
public function __construct(LatteContextData $latteContext, ReflectionProvider $reflectionProvider, MethodCallFinder $methodCallFinder)
2830
{
2931
$this->reflectionProvider = $reflectionProvider;
@@ -83,14 +85,18 @@ public function __construct(LatteContextData $latteContext, ReflectionProvider $
8385
*/
8486
public function find(string $className, string ...$methodNames): array
8587
{
86-
$foundComponents = [
87-
$this->findInClasses($className),
88-
$this->findInMethodCalls($className, '__construct'),
89-
];
90-
foreach ($methodNames as $methodName) {
91-
$foundComponents[] = $this->findInMethodCalls($className, $methodName);
88+
$cacheKey = $className . ' ' . implode(' ', $methodNames);
89+
if (!isset($this->findCache[$cacheKey])) {
90+
$foundComponents = [
91+
$this->findInClasses($className),
92+
$this->findInMethodCalls($className, '__construct'),
93+
];
94+
foreach ($methodNames as $methodName) {
95+
$foundComponents[] = $this->findInMethodCalls($className, $methodName);
96+
}
97+
$this->findCache[$cacheKey] = ItemCombinator::merge(...$foundComponents);
9298
}
93-
return ItemCombinator::merge(...$foundComponents);
99+
return $this->findCache[$cacheKey];
94100
}
95101

96102
/**

src/LatteContext/Finder/FilterFinder.php

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ final class FilterFinder
1919

2020
private MethodCallFinder $methodCallFinder;
2121

22+
/** @var array<string, Filter[]> */
23+
private array $findCache = [];
24+
2225
public function __construct(LatteContextData $latteContext, ReflectionProvider $reflectionProvider, MethodCallFinder $methodCallFinder)
2326
{
2427
$this->reflectionProvider = $reflectionProvider;
@@ -41,16 +44,19 @@ public function __construct(LatteContextData $latteContext, ReflectionProvider $
4144
*/
4245
public function find(string $className, string ...$methodNames): array
4346
{
44-
$foundFilters = [
45-
$this->collectedFilters[$className][''] ?? [],
46-
$this->findInParents($className),
47-
$this->findInMethodCalls($className, '__construct'),
48-
];
49-
foreach ($methodNames as $methodName) {
50-
$foundFilters[] = $this->findInMethodCalls($className, $methodName);
47+
$cacheKey = $className . ' ' . implode(' ', $methodNames);
48+
if (!isset($this->findCache[$cacheKey])) {
49+
$foundFilters = [
50+
$this->collectedFilters[$className][''] ?? [],
51+
$this->findInParents($className),
52+
$this->findInMethodCalls($className, '__construct'),
53+
];
54+
foreach ($methodNames as $methodName) {
55+
$foundFilters[] = $this->findInMethodCalls($className, $methodName);
56+
}
57+
$this->findCache[$cacheKey] = array_merge(...$foundFilters);
5158
}
52-
53-
return array_merge(...$foundFilters);
59+
return $this->findCache[$cacheKey];
5460
}
5561

5662
/**

src/LatteContext/Finder/FormControlFinder.php

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ final class FormControlFinder
1919

2020
private MethodCallFinder $methodCallFinder;
2121

22+
/** @var array<string, ControlInterface[]> */
23+
private array $findCache = [];
24+
2225
public function __construct(LatteContextData $latteContext, ReflectionProvider $reflectionProvider, MethodCallFinder $methodCallFinder)
2326
{
2427
$this->reflectionProvider = $reflectionProvider;
@@ -43,14 +46,18 @@ public function __construct(LatteContextData $latteContext, ReflectionProvider $
4346
*/
4447
public function find(string $className, string ...$methodNames): array
4548
{
46-
$foundFormControls = [
47-
$this->findInClasses($className),
48-
$this->findInMethodCalls($className, '__construct'),
49-
];
50-
foreach ($methodNames as $methodName) {
51-
$foundFormControls[] = $this->findInMethodCalls($className, $methodName);
49+
$cacheKey = $className . ' ' . implode(' ', $methodNames);
50+
if (!isset($this->findCache[$cacheKey])) {
51+
$foundFormControls = [
52+
$this->findInClasses($className),
53+
$this->findInMethodCalls($className, '__construct'),
54+
];
55+
foreach ($methodNames as $methodName) {
56+
$foundFormControls[] = $this->findInMethodCalls($className, $methodName);
57+
}
58+
$this->findCache[$cacheKey] = ItemCombinator::merge(...$foundFormControls);
5259
}
53-
return ItemCombinator::merge(...$foundFormControls);
60+
return $this->findCache[$cacheKey];
5461
}
5562

5663
/**

src/LatteContext/Finder/FormFinder.php

Lines changed: 34 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ final class FormFinder
2323

2424
private FormGroupFinder $formGroupFinder;
2525

26+
/** @var array<string, Form[]> */
27+
private array $findCache = [];
28+
2629
public function __construct(
2730
LatteContextData $latteContext,
2831
ReflectionProvider $reflectionProvider,
@@ -52,35 +55,39 @@ public function __construct(
5255
*/
5356
public function find(string $className, string ...$methodNames): array
5457
{
55-
$foundForms = [
56-
$this->findInClasses($className),
57-
$this->findInMethodCalls($className, '__construct'),
58-
];
59-
foreach ($methodNames as $methodName) {
60-
$foundForms[] = $this->findInMethodCalls($className, $methodName);
61-
}
62-
/** @var CollectedForm[] $collectedForms */
63-
$collectedForms = array_merge(...$foundForms);
64-
65-
$forms = [];
66-
foreach ($collectedForms as $collectedForm) {
67-
$createdClassName = $collectedForm->getCreatedClassName();
68-
$parentClassNames = $this->reflectionProvider->getClass($className)->getParentClassesNames();
69-
if (in_array($createdClassName, $parentClassNames, true)) {
70-
$createdClassName = $className;
58+
$cacheKey = $className . ' ' . implode(' ', $methodNames);
59+
if (!isset($this->findCache[$cacheKey])) {
60+
$foundForms = [
61+
$this->findInClasses($className),
62+
$this->findInMethodCalls($className, '__construct'),
63+
];
64+
foreach ($methodNames as $methodName) {
65+
$foundForms[] = $this->findInMethodCalls($className, $methodName);
66+
}
67+
/** @var CollectedForm[] $collectedForms */
68+
$collectedForms = array_merge(...$foundForms);
69+
70+
$forms = [];
71+
foreach ($collectedForms as $collectedForm) {
72+
$createdClassName = $collectedForm->getCreatedClassName();
73+
$parentClassNames = $this->reflectionProvider->getClass($className)->getParentClassesNames();
74+
if (in_array($createdClassName, $parentClassNames, true)) {
75+
$createdClassName = $className;
76+
}
77+
$formControls = $this->formControlFinder->find(
78+
$createdClassName,
79+
$collectedForm->getCreatedMethodName()
80+
);
81+
$formGroups = $this->formGroupFinder->find(
82+
$createdClassName,
83+
$collectedForm->getCreatedMethodName()
84+
);
85+
$forms[$collectedForm->getForm()->getName()] = $collectedForm->getForm()->withControls($formControls)->withGroups($formGroups);
7186
}
72-
$formControls = $this->formControlFinder->find(
73-
$createdClassName,
74-
$collectedForm->getCreatedMethodName()
75-
);
76-
$formGroups = $this->formGroupFinder->find(
77-
$createdClassName,
78-
$collectedForm->getCreatedMethodName()
79-
);
80-
$forms[$collectedForm->getForm()->getName()] = $collectedForm->getForm()->withControls($formControls)->withGroups($formGroups);
81-
}
8287

83-
return $forms;
88+
$this->findCache[$cacheKey] = $forms;
89+
}
90+
return $this->findCache[$cacheKey];
8491
}
8592

8693
/**

0 commit comments

Comments
 (0)