Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions extension.neon
Original file line number Diff line number Diff line change
Expand Up @@ -310,5 +310,8 @@ services:

-
class: PHPStan\Symfony\SymfonyContainerResultCacheMetaExtension
arguments:
tmpDir: %tmpDir%
containerXmlPath: %symfony.containerXmlPath%
tags:
- phpstan.resultCacheMetaExtension
35 changes: 34 additions & 1 deletion src/Symfony/SymfonyContainerResultCacheMetaExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,13 @@

use PHPStan\Analyser\ResultCache\ResultCacheMetaExtension;
use function array_map;
use function file_get_contents;
use function file_put_contents;
use function hash;
use function hash_file;
use function ksort;
use function sort;
use function sprintf;
use function var_export;

final class SymfonyContainerResultCacheMetaExtension implements ResultCacheMetaExtension
Expand All @@ -16,10 +20,16 @@ final class SymfonyContainerResultCacheMetaExtension implements ResultCacheMetaE

private ServiceMap $serviceMap;

public function __construct(ParameterMap $parameterMap, ServiceMap $serviceMap)
private string $tmpDir;

private ?string $containerXmlPath;

public function __construct(ParameterMap $parameterMap, ServiceMap $serviceMap, string $tmpDir, ?string $containerXmlPath)
{
$this->parameterMap = $parameterMap;
$this->serviceMap = $serviceMap;
$this->tmpDir = $tmpDir;
$this->containerXmlPath = $containerXmlPath;
}

public function getKey(): string
Expand All @@ -28,6 +38,29 @@ public function getKey(): string
}

public function getHash(): string
{
if ($this->containerXmlPath !== null) {
$xmlHash = hash_file('sha256', $this->containerXmlPath);
if ($xmlHash === false) {
throw new XmlContainerNotExistsException(sprintf('Container %s does not exist', $this->containerXmlPath));
}
$hashFile = sprintf('%s/%s-%s.hash', $this->tmpDir, $this->getKey(), $xmlHash);
$hash = @file_get_contents($hashFile);
if ($hash !== false) {
return $hash;
}
}

$hash = $this->calculateHash();

if ($this->containerXmlPath !== null) {
file_put_contents($hashFile, $hash);
}

return $hash;
}

public function calculateHash(): string
{
$services = $parameters = [];

Expand Down
68 changes: 68 additions & 0 deletions tests/Symfony/SymfonyContainerResultCacheMetaExtensionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,77 @@

use PHPStan\Testing\PHPStanTestCase;
use function count;
use function file_get_contents;
use function file_put_contents;
use function glob;
use function mkdir;
use function rmdir;
use function sprintf;
use function sys_get_temp_dir;
use function uniqid;
use function unlink;

/**
* @phpstan-type ContainerContents array{parameters?: ParameterMap, services?: ServiceMap}
*/
final class SymfonyContainerResultCacheMetaExtensionTest extends PHPStanTestCase
{

private string $tmpDir;

protected function setUp(): void
{
parent::setUp();
$this->tmpDir = sys_get_temp_dir() . '/phpstan-symfony-test-' . uniqid('', true);
mkdir($this->tmpDir, 0777, true);
}

protected function tearDown(): void
{
$cacheFiles = glob($this->tmpDir . '/*.hash');
if ($cacheFiles !== false) {
foreach ($cacheFiles as $file) {
unlink($file);
}
}
rmdir($this->tmpDir);
parent::tearDown();
}

public function testHashIsCalculatedAndWrittenToCacheFileOnCacheMiss(): void
{
$containerXmlPath = __DIR__ . '/container.xml';

$extension = new SymfonyContainerResultCacheMetaExtension(
new DefaultParameterMap([]),
new DefaultServiceMap([]),
$this->tmpDir,
$containerXmlPath,
);

$hash = $extension->getHash();

$cacheFile = sprintf('%s/symfonyDiContainer-c55d6ac45b535d6ecc9402cbb93825c38ec7b11b03f66577d0d3549b3d9ef75f.hash', $this->tmpDir);
self::assertFileExists($cacheFile);
self::assertSame($hash, file_get_contents($cacheFile));
}

public function testCachedHashIsReturnedOnCacheHit(): void
{
$containerXmlPath = __DIR__ . '/container.xml';
$cacheFile = sprintf('%s/symfonyDiContainer-c55d6ac45b535d6ecc9402cbb93825c38ec7b11b03f66577d0d3549b3d9ef75f.hash', $this->tmpDir);
file_put_contents($cacheFile, 'pre-computed-hash');

$extension = new SymfonyContainerResultCacheMetaExtension(
new DefaultParameterMap([]),
new DefaultServiceMap([]),
$this->tmpDir,
$containerXmlPath,
);

self::assertSame('pre-computed-hash', $extension->getHash());
}

/**
* @param list<ContainerContents> $sameHashContents
* @param ContainerContents $invalidatingContent
Expand All @@ -30,6 +94,8 @@ public function testContainerHashIsCalculatedCorrectly(
$currentHash = (new SymfonyContainerResultCacheMetaExtension(
$content['parameters'] ?? new DefaultParameterMap([]),
$content['services'] ?? new DefaultServiceMap([]),
__DIR__ . '/../../tmp',
null,
))->getHash();

if ($hash === null) {
Expand All @@ -44,6 +110,8 @@ public function testContainerHashIsCalculatedCorrectly(
(new SymfonyContainerResultCacheMetaExtension(
$invalidatingContent['parameters'] ?? new DefaultParameterMap([]),
$invalidatingContent['services'] ?? new DefaultServiceMap([]),
__DIR__ . '/../../tmp',
null,
))->getHash(),
);
}
Expand Down
Loading