Skip to content

Commit a4bc7c0

Browse files
authored
Merge pull request #8017 from kenjis/feat-FileLocator-Caching
feat: FileLocator caching
2 parents d5ad48e + dc87b0d commit a4bc7c0

File tree

15 files changed

+455
-24
lines changed

15 files changed

+455
-24
lines changed

system/Autoloader/FileLocator.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
*
1818
* @see \CodeIgniter\Autoloader\FileLocatorTest
1919
*/
20-
class FileLocator
20+
class FileLocator implements FileLocatorInterface
2121
{
2222
/**
2323
* The Autoloader to use.
Lines changed: 172 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
<?php
2+
3+
/**
4+
* This file is part of CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Autoloader;
13+
14+
use CodeIgniter\Cache\CacheInterface;
15+
use CodeIgniter\Cache\FactoriesCache\FileVarExportHandler;
16+
17+
/**
18+
* FileLocator with Cache
19+
*
20+
* @see \CodeIgniter\Autoloader\FileLocatorCachedTest
21+
*/
22+
final class FileLocatorCached implements FileLocatorInterface
23+
{
24+
private FileLocator $locator;
25+
26+
/**
27+
* @var CacheInterface|FileVarExportHandler
28+
*/
29+
private $cacheHandler;
30+
31+
/**
32+
* Cache data
33+
*
34+
* [method => data]
35+
* E.g.,
36+
* [
37+
* 'search' => [$path => $foundPaths],
38+
* ]
39+
*/
40+
private array $cache = [];
41+
42+
/**
43+
* Is the cache updated?
44+
*/
45+
private bool $cacheUpdated = false;
46+
47+
private string $cacheKey = 'FileLocatorCache';
48+
49+
/**
50+
* @param CacheInterface|FileVarExportHandler|null $cache
51+
*/
52+
public function __construct(FileLocator $locator, $cache = null)
53+
{
54+
$this->cacheHandler = $cache ?? new FileVarExportHandler();
55+
$this->locator = $locator;
56+
57+
$this->loadCache();
58+
}
59+
60+
private function loadCache(): void
61+
{
62+
$data = $this->cacheHandler->get($this->cacheKey);
63+
64+
if (is_array($data)) {
65+
$this->cache = $data;
66+
}
67+
}
68+
69+
public function __destruct()
70+
{
71+
$this->saveCache();
72+
}
73+
74+
private function saveCache(): void
75+
{
76+
if ($this->cacheUpdated) {
77+
$this->cacheHandler->save($this->cacheKey, $this->cache, 3600 * 24);
78+
}
79+
}
80+
81+
/**
82+
* Delete cache data
83+
*/
84+
public function deleteCache(): void
85+
{
86+
$this->cacheHandler->delete($this->cacheKey);
87+
}
88+
89+
public function findQualifiedNameFromPath(string $path): false|string
90+
{
91+
if (isset($this->cache['findQualifiedNameFromPath'][$path])) {
92+
return $this->cache['findQualifiedNameFromPath'][$path];
93+
}
94+
95+
$classname = $this->locator->findQualifiedNameFromPath($path);
96+
97+
$this->cache['findQualifiedNameFromPath'][$path] = $classname;
98+
$this->cacheUpdated = true;
99+
100+
return $classname;
101+
}
102+
103+
public function getClassname(string $file): string
104+
{
105+
if (isset($this->cache['getClassname'][$file])) {
106+
return $this->cache['getClassname'][$file];
107+
}
108+
109+
$classname = $this->locator->getClassname($file);
110+
111+
$this->cache['getClassname'][$file] = $classname;
112+
$this->cacheUpdated = true;
113+
114+
return $classname;
115+
}
116+
117+
public function search(string $path, string $ext = 'php', bool $prioritizeApp = true): array
118+
{
119+
if (isset($this->cache['search'][$path][$ext][$prioritizeApp])) {
120+
return $this->cache['search'][$path][$ext][$prioritizeApp];
121+
}
122+
123+
$foundPaths = $this->locator->search($path, $ext, $prioritizeApp);
124+
125+
$this->cache['search'][$path][$ext][$prioritizeApp] = $foundPaths;
126+
$this->cacheUpdated = true;
127+
128+
return $foundPaths;
129+
}
130+
131+
public function listFiles(string $path): array
132+
{
133+
if (isset($this->cache['listFiles'][$path])) {
134+
return $this->cache['listFiles'][$path];
135+
}
136+
137+
$files = $this->locator->listFiles($path);
138+
139+
$this->cache['listFiles'][$path] = $files;
140+
$this->cacheUpdated = true;
141+
142+
return $files;
143+
}
144+
145+
public function listNamespaceFiles(string $prefix, string $path): array
146+
{
147+
if (isset($this->cache['listNamespaceFiles'][$prefix][$path])) {
148+
return $this->cache['listNamespaceFiles'][$prefix][$path];
149+
}
150+
151+
$files = $this->locator->listNamespaceFiles($prefix, $path);
152+
153+
$this->cache['listNamespaceFiles'][$prefix][$path] = $files;
154+
$this->cacheUpdated = true;
155+
156+
return $files;
157+
}
158+
159+
public function locateFile(string $file, ?string $folder = null, string $ext = 'php'): false|string
160+
{
161+
if (isset($this->cache['locateFile'][$file][$folder][$ext])) {
162+
return $this->cache['locateFile'][$file][$folder][$ext];
163+
}
164+
165+
$files = $this->locator->locateFile($file, $folder, $ext);
166+
167+
$this->cache['locateFile'][$file][$folder][$ext] = $files;
168+
$this->cacheUpdated = true;
169+
170+
return $files;
171+
}
172+
}
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 CodeIgniter 4 framework.
5+
*
6+
* (c) CodeIgniter Foundation <[email protected]>
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace CodeIgniter\Autoloader;
13+
14+
/**
15+
* Allows loading non-class files in a namespaced manner.
16+
* Works with Helpers, Views, etc.
17+
*/
18+
interface FileLocatorInterface
19+
{
20+
/**
21+
* Attempts to locate a file by examining the name for a namespace
22+
* and looking through the PSR-4 namespaced files that we know about.
23+
*
24+
* @param string $file The relative file path or namespaced file to
25+
* locate. If not namespaced, search in the app
26+
* folder.
27+
* @param string|null $folder The folder within the namespace that we should
28+
* look for the file. If $file does not contain
29+
* this value, it will be appended to the namespace
30+
* folder.
31+
* @param string $ext The file extension the file should have.
32+
*
33+
* @return false|string The path to the file, or false if not found.
34+
*/
35+
public function locateFile(string $file, ?string $folder = null, string $ext = 'php');
36+
37+
/**
38+
* Examines a file and returns the fully qualified class name.
39+
*/
40+
public function getClassname(string $file): string;
41+
42+
/**
43+
* Searches through all of the defined namespaces looking for a file.
44+
* Returns an array of all found locations for the defined file.
45+
*
46+
* Example:
47+
*
48+
* $locator->search('Config/Routes.php');
49+
* // Assuming PSR4 namespaces include foo and bar, might return:
50+
* [
51+
* 'app/Modules/foo/Config/Routes.php',
52+
* 'app/Modules/bar/Config/Routes.php',
53+
* ]
54+
*/
55+
public function search(string $path, string $ext = 'php', bool $prioritizeApp = true): array;
56+
57+
/**
58+
* Find the qualified name of a file according to
59+
* the namespace of the first matched namespace path.
60+
*
61+
* @return false|string The qualified name or false if the path is not found
62+
*/
63+
public function findQualifiedNameFromPath(string $path);
64+
65+
/**
66+
* Scans the defined namespaces, returning a list of all files
67+
* that are contained within the subpath specified by $path.
68+
*
69+
* @return string[] List of file paths
70+
*/
71+
public function listFiles(string $path): array;
72+
73+
/**
74+
* Scans the provided namespace, returning a list of all files
75+
* that are contained within the sub path specified by $path.
76+
*
77+
* @return string[] List of file paths
78+
*/
79+
public function listNamespaceFiles(string $prefix, string $path): array;
80+
}

system/CLI/Commands.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace CodeIgniter\CLI;
1313

14-
use CodeIgniter\Autoloader\FileLocator;
14+
use CodeIgniter\Autoloader\FileLocatorInterface;
1515
use CodeIgniter\Log\Logger;
1616
use ReflectionClass;
1717
use ReflectionException;
@@ -87,7 +87,7 @@ public function discoverCommands()
8787
return;
8888
}
8989

90-
/** @var FileLocator $locator */
90+
/** @var FileLocatorInterface $locator */
9191
$locator = service('locator');
9292
$files = $locator->listFiles('Commands/');
9393

system/Commands/Utilities/Routes/ControllerFinder.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace CodeIgniter\Commands\Utilities\Routes;
1313

14-
use CodeIgniter\Autoloader\FileLocator;
14+
use CodeIgniter\Autoloader\FileLocatorInterface;
1515
use CodeIgniter\Config\Services;
1616

1717
/**
@@ -26,7 +26,7 @@ final class ControllerFinder
2626
*/
2727
private string $namespace;
2828

29-
private FileLocator $locator;
29+
private FileLocatorInterface $locator;
3030

3131
/**
3232
* @param string $namespace namespace to search

system/Config/BaseService.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use CodeIgniter\Autoloader\Autoloader;
1515
use CodeIgniter\Autoloader\FileLocator;
16+
use CodeIgniter\Autoloader\FileLocatorInterface;
1617
use CodeIgniter\Cache\CacheInterface;
1718
use CodeIgniter\Cache\ResponseCache;
1819
use CodeIgniter\CLI\Commands;
@@ -226,7 +227,7 @@ public static function autoloader(bool $getShared = true)
226227
* within namespaced folders, as well as convenience methods for
227228
* loading 'helpers', and 'libraries'.
228229
*
229-
* @return FileLocator
230+
* @return FileLocatorInterface
230231
*/
231232
public static function locator(bool $getShared = true)
232233
{

system/Publisher/Publisher.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace CodeIgniter\Publisher;
1313

14-
use CodeIgniter\Autoloader\FileLocator;
14+
use CodeIgniter\Autoloader\FileLocatorInterface;
1515
use CodeIgniter\Files\FileCollection;
1616
use CodeIgniter\HTTP\URI;
1717
use CodeIgniter\Publisher\Exceptions\PublisherException;
@@ -105,7 +105,7 @@ final public static function discover(string $directory = 'Publishers'): array
105105

106106
self::$discovered[$directory] = [];
107107

108-
/** @var FileLocator $locator */
108+
/** @var FileLocatorInterface $locator */
109109
$locator = service('locator');
110110

111111
if ([] === $files = $locator->listFiles($directory)) {

system/Router/RouteCollection.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace CodeIgniter\Router;
1313

1414
use Closure;
15-
use CodeIgniter\Autoloader\FileLocator;
15+
use CodeIgniter\Autoloader\FileLocatorInterface;
1616
use CodeIgniter\Router\Exceptions\RouterException;
1717
use Config\App;
1818
use Config\Modules;
@@ -245,7 +245,7 @@ class RouteCollection implements RouteCollectionInterface
245245
/**
246246
* Handle to the file locator to use.
247247
*
248-
* @var FileLocator
248+
* @var FileLocatorInterface
249249
*/
250250
protected $fileLocator;
251251

@@ -283,7 +283,7 @@ class RouteCollection implements RouteCollectionInterface
283283
/**
284284
* Constructor
285285
*/
286-
public function __construct(FileLocator $locator, Modules $moduleConfig, Routing $routing)
286+
public function __construct(FileLocatorInterface $locator, Modules $moduleConfig, Routing $routing)
287287
{
288288
$this->fileLocator = $locator;
289289
$this->moduleConfig = $moduleConfig;

system/View/Parser.php

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
namespace CodeIgniter\View;
1313

14-
use CodeIgniter\Autoloader\FileLocator;
14+
use CodeIgniter\Autoloader\FileLocatorInterface;
1515
use CodeIgniter\View\Exceptions\ViewException;
1616
use Config\View as ViewConfig;
1717
use ParseError;
@@ -79,10 +79,15 @@ class Parser extends View
7979
/**
8080
* Constructor
8181
*
82-
* @param FileLocator|null $loader
82+
* @param FileLocatorInterface|null $loader
8383
*/
84-
public function __construct(ViewConfig $config, ?string $viewPath = null, $loader = null, ?bool $debug = null, ?LoggerInterface $logger = null)
85-
{
84+
public function __construct(
85+
ViewConfig $config,
86+
?string $viewPath = null,
87+
$loader = null,
88+
?bool $debug = null,
89+
?LoggerInterface $logger = null
90+
) {
8691
// Ensure user plugins override core plugins.
8792
$this->plugins = $config->plugins;
8893

0 commit comments

Comments
 (0)