Skip to content

Commit e20d7ed

Browse files
committed
feat(cache): add device-detector cache option to improve performance
1 parent 1068b06 commit e20d7ed

5 files changed

Lines changed: 40 additions & 8 deletions

File tree

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,12 @@ $browser = new Parser(null, null, [
166166

167167
Available options:
168168

169-
| Key | Default | Description |
170-
| :--------------------------- | :-----: | :------------------------------------- |
171-
| `cache.interval` | `10080` | Cache TTL in seconds |
172-
| `cache.prefix` | `bd4_` | Cache key prefix |
173-
| `security.max-header-length` | `2048` | Max user agent length (DoS protection) |
169+
| Key | Default | Description |
170+
| :--------------------------- | :-------: | :----------------------------------------------------- |
171+
| `cache.interval` | `10080` | Cache TTL in seconds |
172+
| `cache.prefix` | `bd4_` | Cache key prefix |
173+
| `cache.device-detector` | `false` | Enable matomo/device-detector's internal Laravel cache |
174+
| `security.max-header-length` | `2048` | Max user agent length (DoS protection) |
174175

175176
## Quality
176177

config/browser-detect.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,13 @@
1010
* Cache prefix, the user agent string will be hashed and appended at the end.
1111
*/
1212
'prefix' => 'bd4_',
13+
/**
14+
* Enable the device-detector engine's own internal cache via Laravel's cache store.
15+
* When enabled, parsed YAML device definition data is cached by the underlying
16+
* matomo/device-detector library, reducing file reads on repeated parses.
17+
* Requires a Laravel application context — do not enable in standalone mode.
18+
*/
19+
'device-detector' => false,
1320
],
1421
'security' => [
1522
/**

src/Parser.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public function __construct(?CacheManager $cache = null, ?Request $request = nul
8181

8282
$this->pipeline = [
8383
new Stages\CrawlerDetect,
84-
new Stages\DeviceDetector,
84+
new Stages\DeviceDetector($this->cacheConfig()['device-detector']),
8585
new Stages\BrowserDetect,
8686
];
8787
}
@@ -202,11 +202,11 @@ protected function makeHashKey(string $agent): string
202202
}
203203

204204
/**
205-
* @return array{interval: int, prefix: string}
205+
* @return array{interval: int, prefix: string, device-detector: bool}
206206
*/
207207
private function cacheConfig(): array
208208
{
209-
/** @var array{interval: int, prefix: string} */
209+
/** @var array{interval: int, prefix: string, device-detector: bool} */
210210
return $this->config['cache'];
211211
}
212212

src/Stages/DeviceDetector.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,17 @@ class DeviceDetector implements StageInterface
1313
{
1414
protected ?\DeviceDetector\DeviceDetector $detector = null;
1515

16+
public function __construct(protected bool $useDeviceDetectorCache = false) {}
17+
1618
public function __invoke(PayloadInterface $payload): PayloadInterface
1719
{
1820
if ($this->detector === null) {
1921
$this->detector = new \DeviceDetector\DeviceDetector;
2022
// Skip bot detection — CrawlerDetect handles that upstream.
2123
$this->detector->skipBotDetection(true);
24+
if ($this->useDeviceDetectorCache) {
25+
$this->detector->setCache(new \DeviceDetector\Cache\LaravelCache());
26+
}
2227
}
2328
$this->detector->setUserAgent($payload->getAgent());
2429
$this->detector->parse();

tests/Stages/DeviceDetectorTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use hisorange\BrowserDetect\Payload;
66
use hisorange\BrowserDetect\Stages\DeviceDetector;
77
use hisorange\BrowserDetect\Test\TestCase;
8+
use Illuminate\Support\Facades\Cache;
89
use PHPUnit\Framework\Attributes\DataProvider;
910

1011
/**
@@ -77,6 +78,24 @@ public static function provideAgents()
7778
];
7879
}
7980

81+
/**
82+
* @covers ::__construct()
83+
* @covers ::__invoke()
84+
*/
85+
public function test_invoke_with_device_detector_cache_enabled()
86+
{
87+
// Must be called before the stage runs to intercept cache writes.
88+
Cache::spy();
89+
90+
$stage = new DeviceDetector(useDeviceDetectorCache: true);
91+
$payload = new Payload('Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36');
92+
$stage($payload);
93+
94+
$this->assertSame('Blink', $payload->getValue('browserEngine'));
95+
$this->assertSame('Chrome', $payload->getValue('browserFamily'));
96+
Cache::shouldHaveReceived('put');
97+
}
98+
8099
/**
81100
* @covers ::__invoke()
82101
*/

0 commit comments

Comments
 (0)