22
33namespace PHPStan \DependencyInjection ;
44
5+ use DirectoryIterator ;
56use Nette \DI \Config \Loader ;
67use Nette \DI \Container as OriginalNetteContainer ;
78use Nette \DI \ContainerLoader ;
89use PHPStan \File \CouldNotReadFileException ;
10+ use PHPStan \File \CouldNotWriteFileException ;
11+ use PHPStan \File \FileReader ;
12+ use PHPStan \File \FileWriter ;
913use function array_keys ;
14+ use function count ;
1015use function error_reporting ;
16+ use function explode ;
17+ use function implode ;
18+ use function in_array ;
19+ use function is_dir ;
20+ use function is_file ;
1121use function restore_error_handler ;
1222use function set_error_handler ;
1323use function sha1_file ;
24+ use function sprintf ;
25+ use function str_ends_with ;
26+ use function substr ;
27+ use function time ;
28+ use function trim ;
29+ use function unlink ;
1430use const E_USER_DEPRECATED ;
1531use const PHP_RELEASE_VERSION ;
1632use const PHP_VERSION_ID ;
@@ -21,7 +37,7 @@ final class Configurator extends \Nette\Bootstrap\Configurator
2137 /** @var string[] */
2238 private array $ allConfigFiles = [];
2339
24- public function __construct (private LoaderFactory $ loaderFactory )
40+ public function __construct (private LoaderFactory $ loaderFactory, private bool $ journalContainer )
2541 {
2642 parent ::__construct ();
2743 }
@@ -59,10 +75,104 @@ public function loadContainer(): string
5975 $ this ->staticParameters ['debugMode ' ],
6076 );
6177
62- return $ loader ->load (
78+ $ className = $ loader ->load (
6379 [$ this , 'generateContainer ' ],
6480 [$ this ->staticParameters , array_keys ($ this ->dynamicParameters ), $ this ->configs , PHP_VERSION_ID - PHP_RELEASE_VERSION , NeonAdapter::CACHE_KEY , $ this ->getAllConfigFilesHashes ()],
6581 );
82+
83+ if ($ this ->journalContainer ) {
84+ $ this ->journal ($ className );
85+ }
86+
87+ return $ className ;
88+ }
89+
90+ private function journal (string $ currentContainerClassName ): void
91+ {
92+ $ directory = $ this ->getContainerCacheDirectory ();
93+ if (!is_dir ($ directory )) {
94+ return ;
95+ }
96+
97+ $ journalFile = $ directory . '/container.journal ' ;
98+ if (!is_file ($ journalFile )) {
99+ try {
100+ FileWriter::write ($ journalFile , sprintf ("%s:%d \n" , $ currentContainerClassName , time ()));
101+ } catch (CouldNotWriteFileException ) {
102+ // pass
103+ }
104+
105+ return ;
106+ }
107+
108+ try {
109+ $ journalContents = FileReader::read ($ journalFile );
110+ } catch (CouldNotReadFileException ) {
111+ return ;
112+ }
113+
114+ $ journalLines = explode ("\n" , trim ($ journalContents ));
115+ $ linesToWrite = [];
116+ $ usedInTheLastWeek = [];
117+ $ now = time ();
118+ $ currentAlreadyInTheJournal = false ;
119+ foreach ($ journalLines as $ journalLine ) {
120+ if ($ journalLine === '' ) {
121+ continue ;
122+ }
123+ $ journalLineParts = explode (': ' , $ journalLine );
124+ if (count ($ journalLineParts ) !== 2 ) {
125+ return ;
126+ }
127+ $ className = $ journalLineParts [0 ];
128+ $ containerLastUsedTime = (int ) $ journalLineParts [1 ];
129+
130+ $ week = 3600 * 24 * 7 ;
131+
132+ if ($ containerLastUsedTime + $ week >= $ now ) {
133+ $ usedInTheLastWeek [] = $ className ;
134+ }
135+
136+ if ($ currentContainerClassName !== $ className ) {
137+ $ linesToWrite [] = sprintf ('%s:%d ' , $ className , $ containerLastUsedTime );
138+ continue ;
139+ }
140+
141+ $ linesToWrite [] = sprintf ('%s:%d ' , $ currentContainerClassName , $ now );
142+ $ currentAlreadyInTheJournal = true ;
143+ }
144+
145+ if (!$ currentAlreadyInTheJournal ) {
146+ $ linesToWrite [] = sprintf ('%s:%d ' , $ currentContainerClassName , $ now );
147+ $ usedInTheLastWeek [] = $ currentContainerClassName ;
148+ }
149+
150+ try {
151+ FileWriter::write ($ journalFile , implode ("\n" , $ linesToWrite ) . "\n" );
152+ } catch (CouldNotWriteFileException ) {
153+ return ;
154+ }
155+
156+ foreach (new DirectoryIterator ($ directory ) as $ fileInfo ) {
157+ if ($ fileInfo ->isDot ()) {
158+ continue ;
159+ }
160+ $ fileName = $ fileInfo ->getFilename ();
161+ if ($ fileName === 'container.journal ' ) {
162+ continue ;
163+ }
164+ if (!str_ends_with ($ fileName , '.php ' )) {
165+ continue ;
166+ }
167+ $ fileClassName = substr ($ fileName , 0 , -4 );
168+ if (in_array ($ fileClassName , $ usedInTheLastWeek , true )) {
169+ continue ;
170+ }
171+ $ basePathname = $ fileInfo ->getPathname ();
172+ @unlink ($ basePathname );
173+ @unlink ($ basePathname . '.lock ' );
174+ @unlink ($ basePathname . '.meta ' );
175+ }
66176 }
67177
68178 public function createContainer (bool $ initialize = true ): OriginalNetteContainer
0 commit comments