Skip to content

Commit 8040f3d

Browse files
committed
[Caching] Add CacheMetaExtensionInterface for custom cache invalidation
Same mechanism as PHPStan's ResultCacheMetaExtension — extensions implement getKey() and getHash() to provide additional metadata that is folded into the file cache key. When any extension's hash changes, all cached files are reprocessed.
1 parent 3a3942b commit 8040f3d

5 files changed

Lines changed: 85 additions & 1 deletion

File tree

src/Caching/Config/FileHashComputer.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
namespace Rector\Caching\Config;
66

77
use Rector\Application\VersionResolver;
8+
use Rector\Caching\Contract\CacheMetaExtensionInterface;
89
use Rector\Configuration\Parameter\SimpleParameterProvider;
910
use Rector\Exception\ShouldNotHappenException;
1011

@@ -13,12 +14,31 @@
1314
*/
1415
final class FileHashComputer
1516
{
17+
/**
18+
* @param CacheMetaExtensionInterface[] $cacheMetaExtensions
19+
*/
20+
public function __construct(
21+
private readonly array $cacheMetaExtensions = []
22+
) {
23+
}
24+
1625
public function compute(string $filePath): string
1726
{
1827
$this->ensureIsPhp($filePath);
1928

2029
$parametersHash = SimpleParameterProvider::hash();
21-
return sha1($filePath . $parametersHash . VersionResolver::PACKAGE_VERSION);
30+
$extensionHash = $this->computeExtensionHash();
31+
return sha1($filePath . $parametersHash . $extensionHash . VersionResolver::PACKAGE_VERSION);
32+
}
33+
34+
private function computeExtensionHash(): string
35+
{
36+
$extensionHash = '';
37+
foreach ($this->cacheMetaExtensions as $cacheMetaExtension) {
38+
$extensionHash .= $cacheMetaExtension->getKey() . ':' . $cacheMetaExtension->getHash();
39+
}
40+
41+
return $extensionHash;
2242
}
2343

2444
private function ensureIsPhp(string $filePath): void
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Rector\Caching\Contract;
6+
7+
/**
8+
* Allows extensions to provide additional metadata for cache invalidation.
9+
* When any extension's hash changes, all cached files are reprocessed.
10+
*
11+
* @api
12+
*/
13+
interface CacheMetaExtensionInterface
14+
{
15+
/**
16+
* Returns unique key for this cache meta entry.
17+
* This describes the source of the metadata.
18+
*/
19+
public function getKey(): string;
20+
21+
/**
22+
* Returns hash of the cache meta entry.
23+
* This represents the current state of the additional meta source.
24+
*/
25+
public function getHash(): string;
26+
}

src/Config/RectorConfig.php

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

77
use Illuminate\Container\Container;
88
use Override;
9+
use Rector\Caching\Contract\CacheMetaExtensionInterface;
910
use Rector\Caching\Contract\ValueObject\Storage\CacheStorageInterface;
1011
use Rector\Configuration\Option;
1112
use Rector\Configuration\Parameter\SimpleParameterProvider;
@@ -360,6 +361,17 @@ public function cacheClass(string $cacheClass): void
360361
SimpleParameterProvider::setParameter(Option::CACHE_CLASS, $cacheClass);
361362
}
362363

364+
/**
365+
* @param class-string<CacheMetaExtensionInterface> $cacheMetaExtensionClass
366+
*/
367+
public function cacheMetaExtension(string $cacheMetaExtensionClass): void
368+
{
369+
Assert::isAOf($cacheMetaExtensionClass, CacheMetaExtensionInterface::class);
370+
371+
$this->singleton($cacheMetaExtensionClass);
372+
$this->tag($cacheMetaExtensionClass, CacheMetaExtensionInterface::class);
373+
}
374+
363375
/**
364376
* @see https://github.com/nikic/PHP-Parser/issues/723#issuecomment-712401963
365377
*/

src/Configuration/RectorConfigBuilder.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use PhpParser\NodeVisitor;
88
use Rector\Bridge\SetProviderCollector;
99
use Rector\Bridge\SetRectorsResolver;
10+
use Rector\Caching\Contract\CacheMetaExtensionInterface;
1011
use Rector\Caching\Contract\ValueObject\Storage\CacheStorageInterface;
1112
use Rector\Composer\InstalledPackageResolver;
1213
use Rector\Config\Level\CodeQualityLevel;
@@ -91,6 +92,11 @@ final class RectorConfigBuilder
9192

9293
private ?string $containerCacheDirectory = null;
9394

95+
/**
96+
* @var array<class-string<CacheMetaExtensionInterface>>
97+
*/
98+
private array $cacheMetaExtensions = [];
99+
94100
private ?bool $parallel = null;
95101

96102
private int $parallelTimeoutSeconds = 120;
@@ -316,6 +322,10 @@ public function __invoke(RectorConfig $rectorConfig): void
316322
$rectorConfig->containerCacheDirectory($this->containerCacheDirectory);
317323
}
318324

325+
foreach ($this->cacheMetaExtensions as $cacheMetaExtensionClass) {
326+
$rectorConfig->cacheMetaExtension($cacheMetaExtensionClass);
327+
}
328+
319329
if ($this->importNames || $this->importDocBlockNames) {
320330
$rectorConfig->importNames($this->importNames, $this->importDocBlockNames);
321331
$rectorConfig->importShortClasses($this->importShortClasses);
@@ -880,6 +890,16 @@ public function withCache(
880890
return $this;
881891
}
882892

893+
/**
894+
* @param class-string<CacheMetaExtensionInterface> $cacheMetaExtensionClass
895+
*/
896+
public function withCacheMetaExtension(string $cacheMetaExtensionClass): self
897+
{
898+
$this->cacheMetaExtensions[] = $cacheMetaExtensionClass;
899+
900+
return $this;
901+
}
902+
883903
/**
884904
* @param class-string<ConfigurableRectorInterface> $rectorClass
885905
* @param mixed[] $configuration

src/DependencyInjection/LazyContainerFactory.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@
3636
use Rector\BetterPhpDocParser\PhpDocParser\StaticDoctrineAnnotationParser\PlainValueParser;
3737
use Rector\Caching\Cache;
3838
use Rector\Caching\CacheFactory;
39+
use Rector\Caching\Config\FileHashComputer;
40+
use Rector\Caching\Contract\CacheMetaExtensionInterface;
3941
use Rector\ChangesReporting\Contract\Output\OutputFormatterInterface;
4042
use Rector\ChangesReporting\Output\ConsoleOutputFormatter;
4143
use Rector\ChangesReporting\Output\GitHubOutputFormatter;
@@ -482,6 +484,10 @@ static function (Container $container): DynamicSourceLocatorProvider {
482484
return $cacheFactory->create();
483485
});
484486

487+
$rectorConfig->when(FileHashComputer::class)
488+
->needs('$cacheMetaExtensions')
489+
->giveTagged(CacheMetaExtensionInterface::class);
490+
485491
// tagged services
486492
$rectorConfig->when(BetterPhpDocParser::class)
487493
->needs('$phpDocNodeDecorators')

0 commit comments

Comments
 (0)