Skip to content

Commit 4f42e76

Browse files
committed
fix: stop FileLocatorCached from restoring a deleted cache on shutdown
1 parent 01fd6ee commit 4f42e76

7 files changed

Lines changed: 147 additions & 2 deletions

File tree

‎system/Autoloader/FileLocatorCached.php‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ private function saveCache(): void
8484
*/
8585
public function deleteCache(): void
8686
{
87+
$this->cache = [];
8788
$this->cacheUpdated = false;
8889
$this->cacheHandler->delete($this->cacheKey);
8990
}

‎system/Commands/Cache/ClearCache.php‎

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

1414
namespace CodeIgniter\Commands\Cache;
1515

16+
use CodeIgniter\Autoloader\FileLocatorCached;
1617
use CodeIgniter\CLI\BaseCommand;
1718
use CodeIgniter\CLI\CLI;
1819
use Config\Cache;
@@ -81,6 +82,12 @@ public function run(array $params)
8182
return EXIT_ERROR;
8283
}
8384

85+
$locator = service('locator');
86+
87+
if ($handler === 'file' && $locator instanceof FileLocatorCached) {
88+
$locator->deleteCache();
89+
}
90+
8491
CLI::write(CLI::color('Cache cleared.', 'green'));
8592

8693
return EXIT_SUCCESS;

‎system/Commands/Utilities/Optimize.php‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,12 @@ public function run(array $params)
7474

7575
private function clearCache(): void
7676
{
77-
$locator = new FileLocatorCached(new FileLocator(service('autoloader')));
77+
$locator = service('locator');
78+
79+
if (! $locator instanceof FileLocatorCached) {
80+
$locator = new FileLocatorCached(new FileLocator(service('autoloader')));
81+
}
82+
7883
$locator->deleteCache();
7984
CLI::write('Removed FileLocatorCache.', 'green');
8085

‎tests/system/Autoloader/FileLocatorCachedTest.php‎

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,10 +75,27 @@ protected function tearDown(): void
7575

7676
public function testDeleteCache(): void
7777
{
78-
$this->assertNotSame([], $this->handler->get('FileLocatorCache'));
78+
$this->locator->search('Config/App');
79+
$this->locator->__destruct();
80+
$this->assertIsArray($this->handler->get('FileLocatorCache'));
7981

8082
$this->locator->deleteCache();
8183

8284
$this->assertFalse($this->handler->get('FileLocatorCache'));
8385
}
86+
87+
public function testDeleteCacheDiscardsDataHeldInMemory(): void
88+
{
89+
$this->locator->getClassname(SYSTEMPATH . 'CodeIgniter.php');
90+
91+
$this->locator->deleteCache();
92+
93+
$this->locator->search('Config/App');
94+
$this->locator->__destruct();
95+
96+
$cached = $this->handler->get('FileLocatorCache');
97+
98+
$this->assertArrayHasKey('search', $cached);
99+
$this->assertArrayNotHasKey('getClassname', $cached);
100+
}
84101
}

‎tests/system/Commands/Cache/ClearCacheTest.php‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@
1313

1414
namespace CodeIgniter\Commands\Cache;
1515

16+
use CodeIgniter\Autoloader\FileLocator;
17+
use CodeIgniter\Autoloader\FileLocatorCached;
1618
use CodeIgniter\Cache\CacheFactory;
19+
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
1720
use CodeIgniter\Cache\Handlers\FileHandler;
1821
use CodeIgniter\CLI\CLI;
1922
use CodeIgniter\Config\Factories;
@@ -93,6 +96,29 @@ public function testClearCacheWorks(): void
9396
$this->assertStringContainsString('Cache cleared.', $this->getStreamFilterBuffer());
9497
}
9598

99+
public function testClearCacheDiscardsSharedLocatorCache(): void
100+
{
101+
$handler = new FileVarExportHandler();
102+
$handler->delete('FileLocatorCache');
103+
104+
$locator = new FileLocatorCached(new FileLocator(service('autoloader')), $handler);
105+
$locator->search('Config/App');
106+
Services::injectMock('locator', $locator);
107+
108+
command('cache:clear');
109+
110+
$locator->search('Config/Cache');
111+
$locator->__destruct();
112+
Services::resetSingle('locator');
113+
114+
$cached = $handler->get('FileLocatorCache');
115+
116+
$this->assertArrayNotHasKey('Config/App', $cached['search']);
117+
$this->assertArrayHasKey('Config/Cache', $cached['search']);
118+
119+
$handler->delete('FileLocatorCache');
120+
}
121+
96122
public function testClearCacheFails(): void
97123
{
98124
$cache = $this->getMockBuilder(FileHandler::class)
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <admin@codeigniter.com>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace CodeIgniter\Commands\Utilities;
15+
16+
use Closure;
17+
use CodeIgniter\Autoloader\FileLocator;
18+
use CodeIgniter\Autoloader\FileLocatorCached;
19+
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
20+
use CodeIgniter\Test\CIUnitTestCase;
21+
use CodeIgniter\Test\ReflectionHelper;
22+
use CodeIgniter\Test\StreamFilterTrait;
23+
use Config\Services;
24+
use PHPUnit\Framework\Attributes\Group;
25+
26+
/**
27+
* @internal
28+
*/
29+
#[Group('Others')]
30+
final class OptimizeTest extends CIUnitTestCase
31+
{
32+
use ReflectionHelper;
33+
use StreamFilterTrait;
34+
35+
private FileVarExportHandler $handler;
36+
37+
protected function setUp(): void
38+
{
39+
parent::setUp();
40+
41+
$this->handler = new FileVarExportHandler();
42+
$this->handler->delete('FileLocatorCache');
43+
}
44+
45+
protected function tearDown(): void
46+
{
47+
parent::tearDown();
48+
49+
$this->handler->delete('FileLocatorCache');
50+
Services::resetSingle('locator');
51+
}
52+
53+
/**
54+
* @return Closure(): void
55+
*/
56+
private function getClearCache(): Closure
57+
{
58+
return self::getPrivateMethodInvoker(new Optimize(service('logger'), service('commands')), 'clearCache');
59+
}
60+
61+
public function testClearCacheDiscardsSharedLocatorCache(): void
62+
{
63+
$locator = new FileLocatorCached(new FileLocator(service('autoloader')), $this->handler);
64+
$locator->search('Config/App');
65+
Services::injectMock('locator', $locator);
66+
67+
($this->getClearCache())();
68+
69+
$locator->search('Config/Cache');
70+
$locator->__destruct();
71+
72+
$cached = $this->handler->get('FileLocatorCache');
73+
74+
$this->assertArrayNotHasKey('Config/App', $cached['search']);
75+
$this->assertArrayHasKey('Config/Cache', $cached['search']);
76+
$this->assertStringContainsString('Removed FileLocatorCache.', $this->getStreamFilterBuffer());
77+
}
78+
79+
public function testClearCacheDeletesTheFileWithoutSharedLocatorCache(): void
80+
{
81+
$this->handler->save('FileLocatorCache', ['search' => []]);
82+
83+
($this->getClearCache())();
84+
85+
$this->assertFalse($this->handler->get('FileLocatorCache'));
86+
$this->assertStringContainsString('Removed FileLocatorCache.', $this->getStreamFilterBuffer());
87+
}
88+
}

‎user_guide_src/source/changelogs/v4.7.5.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ Deprecations
3838
Bugs Fixed
3939
**********
4040

41+
- **Autoloader:** Fixed a bug where ``FileLocatorCached::deleteCache()`` left the deleted data in memory, so it could be written back to the cache file on shutdown. ``spark optimize`` and ``spark cache:clear`` now clear the shared locator's cache instead of a separate instance.
4142
- **CLI:** Fixed a bug where pressing backspace in a ``CLI::prompt()`` erased the prompt text when the ``readline`` extension is enabled. The prompt is now passed to ``readline()`` so line redraws repaint it.
4243
ANSI color codes in the prompt (e.g., option defaults) are wrapped in readline's non-printing markers under GNU readline so cursor positioning stays accurate.
4344
On Windows, where the ``readline`` extension is built on WinEditLine, the prompt is written to STDOUT first because WinEditLine reports no library version and prints ANSI sequences literally.

0 commit comments

Comments
 (0)