1: | <?php declare(strict_types = 1); |
2: | |
3: | namespace PHPStan\DependencyInjection; |
4: | |
5: | use Nette\DI\Extensions\ExtensionsExtension; |
6: | use Nette\DI\Extensions\PhpExtension; |
7: | use Phar; |
8: | use PhpParser\Parser; |
9: | use PHPStan\BetterReflection\BetterReflection; |
10: | use PHPStan\BetterReflection\Reflector\Reflector; |
11: | use PHPStan\BetterReflection\SourceLocator\SourceStubber\PhpStormStubsSourceStubber; |
12: | use PHPStan\BetterReflection\SourceLocator\Type\SourceLocator; |
13: | use PHPStan\Broker\Broker; |
14: | use PHPStan\Command\CommandHelper; |
15: | use PHPStan\File\FileHelper; |
16: | use PHPStan\Php\PhpVersion; |
17: | use PHPStan\Reflection\ReflectionProvider; |
18: | use PHPStan\Reflection\ReflectionProviderStaticAccessor; |
19: | use Symfony\Component\Finder\Finder; |
20: | use function dirname; |
21: | use function extension_loaded; |
22: | use function ini_get; |
23: | use function is_dir; |
24: | use function sys_get_temp_dir; |
25: | use function time; |
26: | use function unlink; |
27: | |
28: | |
29: | class ContainerFactory |
30: | { |
31: | |
32: | private FileHelper $fileHelper; |
33: | |
34: | private string $rootDirectory; |
35: | |
36: | private string $configDirectory; |
37: | |
38: | |
39: | public function __construct(private string $currentWorkingDirectory) |
40: | { |
41: | $this->fileHelper = new FileHelper($currentWorkingDirectory); |
42: | |
43: | $rootDir = __DIR__ . '/../..'; |
44: | $originalRootDir = $this->fileHelper->normalizePath($rootDir); |
45: | if (extension_loaded('phar')) { |
46: | $pharPath = Phar::running(false); |
47: | if ($pharPath !== '') { |
48: | $rootDir = dirname($pharPath); |
49: | } |
50: | } |
51: | $this->rootDirectory = $this->fileHelper->normalizePath($rootDir); |
52: | $this->configDirectory = $originalRootDir . '/conf'; |
53: | } |
54: | |
55: | |
56: | |
57: | |
58: | |
59: | |
60: | |
61: | public function create( |
62: | string $tempDirectory, |
63: | array $additionalConfigFiles, |
64: | array $analysedPaths, |
65: | array $composerAutoloaderProjectPaths = [], |
66: | array $analysedPathsFromConfig = [], |
67: | string $usedLevel = CommandHelper::DEFAULT_LEVEL, |
68: | ?string $generateBaselineFile = null, |
69: | ?string $cliAutoloadFile = null, |
70: | ?string $singleReflectionFile = null, |
71: | ?string $singleReflectionInsteadOfFile = null, |
72: | ): Container |
73: | { |
74: | $configurator = new Configurator(new LoaderFactory( |
75: | $this->fileHelper, |
76: | $this->rootDirectory, |
77: | $this->currentWorkingDirectory, |
78: | $generateBaselineFile, |
79: | )); |
80: | $configurator->defaultExtensions = [ |
81: | 'php' => PhpExtension::class, |
82: | 'extensions' => ExtensionsExtension::class, |
83: | ]; |
84: | $configurator->setDebugMode(true); |
85: | $configurator->setTempDirectory($tempDirectory); |
86: | $configurator->addParameters([ |
87: | 'rootDir' => $this->rootDirectory, |
88: | 'currentWorkingDirectory' => $this->currentWorkingDirectory, |
89: | 'cliArgumentsVariablesRegistered' => ini_get('register_argc_argv') === '1', |
90: | 'tmpDir' => $tempDirectory, |
91: | 'additionalConfigFiles' => $additionalConfigFiles, |
92: | 'composerAutoloaderProjectPaths' => $composerAutoloaderProjectPaths, |
93: | 'generateBaselineFile' => $generateBaselineFile, |
94: | 'usedLevel' => $usedLevel, |
95: | 'cliAutoloadFile' => $cliAutoloadFile, |
96: | 'fixerTmpDir' => sys_get_temp_dir() . '/phpstan-fixer', |
97: | ]); |
98: | $configurator->addDynamicParameters([ |
99: | 'singleReflectionFile' => $singleReflectionFile, |
100: | 'singleReflectionInsteadOfFile' => $singleReflectionInsteadOfFile, |
101: | 'analysedPaths' => $analysedPaths, |
102: | 'analysedPathsFromConfig' => $analysedPathsFromConfig, |
103: | ]); |
104: | $configurator->addConfig($this->configDirectory . '/config.neon'); |
105: | foreach ($additionalConfigFiles as $additionalConfigFile) { |
106: | $configurator->addConfig($additionalConfigFile); |
107: | } |
108: | |
109: | $container = $configurator->createContainer(); |
110: | |
111: | |
112: | $sourceLocator = $container->getService('betterReflectionSourceLocator'); |
113: | |
114: | |
115: | $reflector = $container->getService('betterReflectionReflector'); |
116: | |
117: | |
118: | $phpParser = $container->getService('phpParserDecorator'); |
119: | |
120: | BetterReflection::populate( |
121: | $container->getByType(PhpVersion::class)->getVersionId(), |
122: | $sourceLocator, |
123: | $reflector, |
124: | $phpParser, |
125: | $container->getByType(PhpStormStubsSourceStubber::class), |
126: | ); |
127: | |
128: | |
129: | $broker = $container->getByType(Broker::class); |
130: | Broker::registerInstance($broker); |
131: | ReflectionProviderStaticAccessor::registerInstance($container->getByType(ReflectionProvider::class)); |
132: | $container->getService('typeSpecifier'); |
133: | |
134: | BleedingEdgeToggle::setBleedingEdge($container->parameters['featureToggles']['bleedingEdge']); |
135: | |
136: | return $container->getByType(Container::class); |
137: | } |
138: | |
139: | public function clearOldContainers(string $tempDirectory): void |
140: | { |
141: | $configurator = new Configurator(new LoaderFactory( |
142: | $this->fileHelper, |
143: | $this->rootDirectory, |
144: | $this->currentWorkingDirectory, |
145: | null, |
146: | )); |
147: | $configurator->setDebugMode(true); |
148: | $configurator->setTempDirectory($tempDirectory); |
149: | |
150: | $containerDirectory = $configurator->getContainerCacheDirectory(); |
151: | if (!is_dir($containerDirectory)) { |
152: | return; |
153: | } |
154: | |
155: | $finder = new Finder(); |
156: | $finder->name('Container_*')->in($containerDirectory); |
157: | $twoDaysAgo = time() - 24 * 60 * 60 * 2; |
158: | |
159: | foreach ($finder as $containerFile) { |
160: | $path = $containerFile->getRealPath(); |
161: | if ($path === false) { |
162: | continue; |
163: | } |
164: | if ($containerFile->getATime() > $twoDaysAgo) { |
165: | continue; |
166: | } |
167: | if ($containerFile->getCTime() > $twoDaysAgo) { |
168: | continue; |
169: | } |
170: | |
171: | @unlink($path); |
172: | } |
173: | } |
174: | |
175: | public function getCurrentWorkingDirectory(): string |
176: | { |
177: | return $this->currentWorkingDirectory; |
178: | } |
179: | |
180: | public function getRootDirectory(): string |
181: | { |
182: | return $this->rootDirectory; |
183: | } |
184: | |
185: | public function getConfigDirectory(): string |
186: | { |
187: | return $this->configDirectory; |
188: | } |
189: | |
190: | } |
191: | |