Skip to content

Commit 3ed5b58

Browse files
committed
Refactor ProxyAutoloader to use PHPStan Cache
1 parent 6e2f5c2 commit 3ed5b58

File tree

3 files changed

+136
-7
lines changed

3 files changed

+136
-7
lines changed

src/bitExpert/PHPStan/Magento/Autoload/ProxyAutoloader.php

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,49 @@
1212

1313
namespace bitExpert\PHPStan\Magento\Autoload;
1414

15+
use PHPStan\Cache\Cache;
16+
1517
class ProxyAutoloader
1618
{
19+
/**
20+
* @var Cache
21+
*/
22+
private $cache;
23+
24+
/**
25+
* ProxyAutoloader constructor.
26+
*
27+
* @param Cache $cache
28+
*/
29+
public function __construct(Cache $cache)
30+
{
31+
$this->cache = $cache;
32+
}
33+
1734
public function autoload(string $class): void
1835
{
1936
if (!preg_match('#\\\Proxy#', $class)) {
2037
return;
2138
}
2239

40+
$cacheFilename = $this->cache->load($class, '');
41+
if ($cacheFilename === null) {
42+
$this->cache->save($class, '', $this->getFileContents($class));
43+
$cacheFilename = $this->cache->load($class, '');
44+
}
45+
46+
require_once($cacheFilename);
47+
}
48+
49+
/**
50+
* Generate the proxy file content as Magento would.
51+
*
52+
* @param string $class
53+
* @return string
54+
* @throws \ReflectionException
55+
*/
56+
protected function getFileContents(string $class): string
57+
{
2358
$namespace = explode('\\', ltrim($class, '\\'));
2459
$proxyClassname = array_pop($namespace);
2560
$proxyBaseClass = '';
@@ -95,7 +130,7 @@ public function autoload(string $class): void
95130
$template .= "{METHODS}";
96131
$template .= "}\n";
97132

98-
$template = str_replace(
133+
return str_replace(
99134
[
100135
'{NAMESPACE}',
101136
'{CLASSNAME}',
@@ -114,11 +149,5 @@ public function autoload(string $class): void
114149
],
115150
$template
116151
);
117-
118-
// we need to store the generated file on disk as PHPStan will try to access the file in several ways. Just
119-
// eval'ing the php code to make the class available won't work!
120-
$tmpFilename = tempnam(sys_get_temp_dir(), 'PSMP');
121-
file_put_contents($tmpFilename, $template, LOCK_EX);
122-
include($tmpFilename);
123152
}
124153
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the phpstan-magento package.
5+
*
6+
* (c) bitExpert AG
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
declare(strict_types=1);
12+
13+
namespace bitExpert\PHPStan\Magento\Autoload;
14+
15+
/**
16+
* Dummy class that can be loaded via the Autoloader in the test cases.
17+
*/
18+
class HelperProxy
19+
{
20+
}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the phpstan-magento package.
5+
*
6+
* (c) bitExpert AG
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
declare(strict_types=1);
12+
13+
namespace bitExpert\PHPStan\Magento\Autoload;
14+
15+
use PHPStan\Cache\Cache;
16+
use PHPStan\Cache\CacheStorage;
17+
use PHPUnit\Framework\TestCase;
18+
19+
class ProxyAutoloaderUnitTest extends TestCase
20+
{
21+
/**
22+
* @var CacheStorage|\PHPUnit\Framework\MockObject\MockObject
23+
*/
24+
private $storage;
25+
/**
26+
* @var ProxyAutoloader
27+
*/
28+
private $autoloader;
29+
30+
public function setUp(): void
31+
{
32+
$this->storage = $this->createMock(CacheStorage::class);
33+
$this->autoloader = new ProxyAutoloader(new Cache($this->storage));
34+
}
35+
36+
/**
37+
* @test
38+
*/
39+
public function autoloaderIgnoresClassesWithoutProxyPostfix()
40+
{
41+
$this->storage->expects($this->never())
42+
->method('load');
43+
44+
$this->autoloader->autoload('SomeClass');
45+
}
46+
47+
/**
48+
* @test
49+
*/
50+
public function autoloaderUsesCachedFileWhenFound()
51+
{
52+
$this->storage->expects($this->once())
53+
->method('load')
54+
->willReturn(__DIR__ . '/HelperProxy.php');
55+
56+
$this->autoloader->autoload('\bitExpert\PHPStan\Magento\Autoload\Helper\Proxy');
57+
58+
self::assertTrue(class_exists(HelperProxy::class, false));
59+
}
60+
61+
/**
62+
* @test
63+
*/
64+
public function autoloaderGeneratesCacheFileWhenNotFoundInCache()
65+
{
66+
// little hack: the proxy autoloader will use Reflection to look for a class without the \Proxy prefix,
67+
// to avoid having another stub class file, we define an class alias here
68+
class_alias('\bitExpert\PHPStan\Magento\Autoload\HelperProxy', '\bitExpert\PHPStan\Magento\Autoload\Helper');
69+
70+
$this->storage->expects($this->atMost(2))
71+
->method('load')
72+
->willReturnOnConsecutiveCalls(null, __DIR__ . '/HelperProxy.php');
73+
$this->storage->expects($this->once())
74+
->method('save');
75+
76+
$this->autoloader->autoload('\bitExpert\PHPStan\Magento\Autoload\Helper\Proxy');
77+
78+
self::assertTrue(class_exists(HelperProxy::class, false));
79+
}
80+
}

0 commit comments

Comments
 (0)