Skip to content

Commit 096f118

Browse files
committed
caching system
1 parent 9708b44 commit 096f118

File tree

7 files changed

+209
-16
lines changed

7 files changed

+209
-16
lines changed

config/translator.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,12 @@
5050

5151
'excluded_paths' => [],
5252

53+
'services' => [
54+
'php-parser' => [
55+
'cache_path' => base_path('.translator.cache'),
56+
],
57+
],
58+
5359
],
5460

5561
];

src/Caches/SearchCodeCache.php

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
<?php
2+
3+
namespace Elegantly\Translator\Caches;
4+
5+
use Illuminate\Contracts\Filesystem\Filesystem;
6+
use PhpParser\Node\ArrayItem;
7+
use PhpParser\Node\Expr\Array_;
8+
use PhpParser\Node\Scalar\String_;
9+
use PhpParser\Node\Stmt\Return_;
10+
11+
class SearchCodeCache
12+
{
13+
const FILENAME = 'translationsByFiles.php';
14+
15+
protected ?array $value = null;
16+
17+
public function __construct(public Filesystem $storage)
18+
{
19+
//
20+
}
21+
22+
public function getValue(): ?array
23+
{
24+
if ($this->value) {
25+
return $this->value;
26+
}
27+
28+
return $this->load();
29+
}
30+
31+
public function load(): ?array
32+
{
33+
if ($this->storage->exists(static::FILENAME)) {
34+
$this->value = include $this->storage->path(static::FILENAME);
35+
}
36+
37+
return $this->value;
38+
}
39+
40+
/**
41+
* @return null|array{ created_at: int, translations : string[] }
42+
*/
43+
public function get(string $file): ?array
44+
{
45+
if (! $this->value) {
46+
$this->load();
47+
}
48+
49+
return $this->value[$file] ?? null;
50+
}
51+
52+
/**
53+
* @param string[] $translations
54+
*/
55+
public function put(string $file, $translations): static
56+
{
57+
if (! $this->value) {
58+
$this->load();
59+
}
60+
61+
$this->value[$file] = [
62+
'created_at' => now()->getTimestamp(),
63+
'translations' => $translations,
64+
];
65+
66+
$this->store();
67+
68+
return $this;
69+
}
70+
71+
public function flush(): static
72+
{
73+
$this->value = null;
74+
75+
if ($this->storage->exists(static::FILENAME)) {
76+
$this->storage->delete(static::FILENAME);
77+
}
78+
79+
return $this;
80+
}
81+
82+
protected function store(): bool
83+
{
84+
$items = array_map(
85+
function (array $item, string $file) {
86+
return new ArrayItem(
87+
key: new String_($file),
88+
value: new Array_([
89+
new ArrayItem(
90+
key: new String_('created_at'),
91+
value: new String_($item['created_at'])
92+
),
93+
new ArrayItem(
94+
key: new String_('translations'),
95+
value: new Array_(array_map(
96+
fn (string $key) => new ArrayItem(new String_($key)),
97+
$item['translations']
98+
))
99+
),
100+
])
101+
);
102+
},
103+
$this->value,
104+
array_keys($this->value)
105+
);
106+
107+
$node = new Return_(new Array_($items));
108+
109+
$prettyPrinter = new \PhpParser\PrettyPrinter\Standard;
110+
111+
return $this->storage->put(
112+
static::FILENAME,
113+
$prettyPrinter->prettyPrintFile([$node])
114+
);
115+
}
116+
}

src/Services/SearchCode/PhpParserService.php

Lines changed: 41 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Elegantly\Translator\Services\SearchCode;
44

5+
use Closure;
6+
use Elegantly\Translator\Caches\SearchCodeCache;
7+
use Illuminate\Contracts\Filesystem\Filesystem;
58
use Illuminate\Support\Facades\Blade;
69
use PhpParser\Node;
710
use PhpParser\Node\Expr\FuncCall;
@@ -14,18 +17,22 @@
1417

1518
class PhpParserService implements SearchCodeServiceInterface
1619
{
20+
public ?SearchCodeCache $cache = null;
21+
1722
public function __construct(
1823
public array $paths,
1924
public array $excludedPaths = [],
25+
?Filesystem $cacheStorage = null,
2026
) {
21-
//
27+
if ($cacheStorage) {
28+
$this->cache = new SearchCodeCache($cacheStorage);
29+
}
2230
}
2331

2432
public function finder(): Finder
2533
{
2634
return Finder::create()
2735
->in($this->paths)
28-
// ->exclude($this->excludedPaths)
2936
->notPath($this->excludedPaths)
3037
->exclude('vendor')
3138
->exclude('node_modules')
@@ -39,7 +46,7 @@ public function finder(): Finder
3946
}
4047

4148
/**
42-
* @return string[]
49+
* @return string[] All translations keys used in the code
4350
*/
4451
public static function scanCode(string $code): array
4552
{
@@ -72,24 +79,45 @@ public static function scanCode(string $code): array
7279
->toArray();
7380
}
7481

75-
public function translationsByFiles(): array
76-
{
82+
public function translationsByFiles(
83+
?Closure $progress = null,
84+
): array {
7785
return collect($this->finder())
78-
->map(function (SplFileInfo $file) {
79-
$content = str($file->getFilename())->endsWith('.blade.php')
80-
? Blade::compileString($file->getContents())
81-
: $file->getContents();
86+
->map(function (SplFileInfo $file, string $key) use ($progress) {
87+
88+
$lastModified = $file->getMTime();
89+
$cachedResult = $this->cache?->get($key);
90+
91+
if (
92+
$lastModified && $cachedResult &&
93+
$lastModified < $cachedResult['created_at']
94+
) {
95+
$translations = $cachedResult['translations'];
96+
} else {
97+
$content = str($file->getFilename())->endsWith('.blade.php')
98+
? Blade::compileString($file->getContents())
99+
: $file->getContents();
82100

83-
return static::scanCode($content);
101+
$translations = static::scanCode($content);
102+
103+
$this->cache?->put($key, $translations);
104+
}
105+
106+
if ($progress) {
107+
$progress($file);
108+
}
109+
110+
return $translations;
84111
})
85112
->filter()
86113
->sortKeys(SORT_NATURAL)
87114
->toArray();
88115
}
89116

90-
public function filesByTranslations(): array
91-
{
92-
$translations = $this->translationsByFiles();
117+
public function filesByTranslations(
118+
?Closure $progress = null,
119+
): array {
120+
$translations = $this->translationsByFiles($progress);
93121

94122
$results = [];
95123

src/Services/SearchCode/SearchCodeServiceInterface.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,17 @@
22

33
namespace Elegantly\Translator\Services\SearchCode;
44

5+
use Closure;
6+
57
interface SearchCodeServiceInterface
68
{
79
/**
810
* @return array<string, string[]>
911
*/
10-
public function translationsByFiles(): array;
12+
public function translationsByFiles(?Closure $progress = null): array;
1113

1214
/**
1315
* @return array<string, array{ count: int, files: string[] }>
1416
*/
15-
public function filesByTranslations(): array;
17+
public function filesByTranslations(?Closure $progress = null): array;
1618
}

src/TranslatorServiceProvider.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,13 @@ public static function getSearchcodeServiceFromConfig(?string $serviceName = nul
9292
return match ($service) {
9393
'php-parser', PhpParserService::class => new PhpParserService(
9494
paths: config('translator.searchcode.paths'),
95-
excludedPaths: config('translator.searchcode.excluded_paths', [])
95+
excludedPaths: config('translator.searchcode.excluded_paths', []),
96+
cacheStorage: config('translator.searchcode.services.php-parser.cache_path')
97+
? Storage::build([
98+
'driver' => 'local',
99+
'root' => config('translator.searchcode.services.php-parser.cache_path'),
100+
])
101+
: null,
96102
),
97103
'', null => null,
98104
default => new $service,

tests/Pest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use Elegantly\Translator\Caches\SearchCodeCache;
34
use Elegantly\Translator\Tests\TestCase;
45
use Illuminate\Contracts\Filesystem\Filesystem;
56

@@ -35,4 +36,10 @@
3536
}
3637
}
3738
}
39+
40+
$cache = new SearchCodeCache(
41+
storage: Storage::fake('cache')
42+
);
43+
44+
$cache->flush();
3845
})->in('Feature');

tests/Unit/PhpParserServiceTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<?php
22

33
use Elegantly\Translator\Services\SearchCode\PhpParserService;
4+
use Illuminate\Support\Facades\Storage;
45

56
it('finds all occurences of __ in code', function (string $code) {
67
$results = PhpParserService::scanCode($code);
@@ -79,3 +80,30 @@
7980
],
8081
]);
8182
})->skipOnWindows();
83+
84+
it('caches results from files', function () {
85+
86+
$appPath = $this->getAppPath();
87+
$resourcesPath = $this->getResourcesPath();
88+
89+
$service = new PhpParserService(
90+
paths: [
91+
$appPath,
92+
$resourcesPath,
93+
],
94+
excludedPaths: $this->getExcludedPaths(),
95+
cacheStorage: Storage::fake('cache')
96+
);
97+
98+
$service->cache->put("{$appPath}/DummyClass.php", [
99+
'messages.dummy.class',
100+
]);
101+
102+
$result = $service->cache->get("{$appPath}/DummyClass.php");
103+
104+
expect($result['created_at'])->toBeInt();
105+
106+
expect($result['translations'])->toBe([
107+
'messages.dummy.class',
108+
]);
109+
})->skipOnWindows();

0 commit comments

Comments
 (0)