Skip to content

Commit 7e823bf

Browse files
devanychsamdark
andauthored
Add description to readme and checks to FileCache (#30)
* Add description to readme * Add additional checks to FileCache * Add tests for coverage * Fix return false on throw exception in set method * Use longer variable name Co-authored-by: Alexander Makarov <sam@rmcreative.ru>
1 parent 3b9e3a9 commit 7e823bf

3 files changed

Lines changed: 148 additions & 20 deletions

File tree

README.md

Lines changed: 100 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,6 @@
66
<br>
77
</p>
88

9-
The package implements file-based PSR-16 cache,
10-
119
[![Latest Stable Version](https://poser.pugx.org/yiisoft/cache-file/v/stable.png)](https://packagist.org/packages/yiisoft/cache-file)
1210
[![Total Downloads](https://poser.pugx.org/yiisoft/cache-file/downloads.png)](https://packagist.org/packages/yiisoft/cache-file)
1311
[![Build status](https://github.com/yiisoft/cache-file/workflows/build/badge.svg)](https://github.com/yiisoft/cache-file/actions?query=workflow%3Abuild)
@@ -17,9 +15,108 @@ The package implements file-based PSR-16 cache,
1715
[![static analysis](https://github.com/yiisoft/cache-file/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/cache-file/actions?query=workflow%3A%22static+analysis%22)
1816
[![type-coverage](https://shepherd.dev/github/yiisoft/cache-file/coverage.svg)](https://shepherd.dev/github/yiisoft/cache-file)
1917

18+
This package implements file-based [PSR-16](https://www.php-fig.org/psr/psr-16/) cache.
19+
20+
## Installation
21+
22+
The package could be installed with composer:
23+
24+
```
25+
composer install yiisoft/cache-file
26+
```
27+
28+
## Configuration
29+
30+
When creating an instance of `\Yiisoft\Cache\File\FileCache`, you must specify
31+
the path to the base directory in which the cache files will be stored:
32+
33+
```php
34+
$cache = new \Yiisoft\Cache\File\FileCache('/path/to/directory');
35+
```
36+
37+
Change the suffix of the cache files:
38+
39+
```php
40+
$cache = $cache->withFileSuffix('.txt'); // default is '.bin'
41+
```
42+
43+
Change the permission to be set for newly created cache files:
44+
45+
```php
46+
$cache = $cache->withFileMode(0644); // default is null
47+
```
48+
49+
This value will be used by PHP `chmod()` function. No umask will be applied.
50+
If not set, the permission will be determined by the current environment.
51+
52+
Change the permission to be set for newly created directories:
53+
54+
```php
55+
$cache = $cache->withDirectoryMode(0777); // default is 0775
56+
```
57+
58+
This value will be used by PHP `chmod()` function. No umask will be applied. Defaults to 0775,
59+
meaning the directory is read-writable by an owner and group, but read-only for other users.
60+
61+
Change the level of sub-directories to store cache files:
62+
63+
```php
64+
$cache = $cache->withDirectoryLevel(3); // default is 1
65+
```
66+
67+
If the system has huge number of cache files (e.g. one million), you may use a bigger
68+
value (usually no bigger than 3). Using sub-directories is mainly to ensure the file
69+
system is not over burdened with a single directory having too many files.
70+
71+
Change the probability of performing garbage collection when storing a piece of data in the cache:
72+
73+
```php
74+
$cache = $cache->withGcProbability(1000); // default is 10
75+
```
76+
77+
The probability (parts per million) that garbage collection (GC) should be performed when
78+
storing a piece of data in the cache. Defaults to 10, meaning 0.001% chance. This number
79+
should be between 0 and 1000000. A value 0 means no GC will be performed at all.
80+
2081
## General usage
2182

22-
## Testing
83+
The package does not contain any additional functionality for interacting with the cache,
84+
except those defined in the [PSR-16](https://www.php-fig.org/psr/psr-16/) interface.
85+
86+
```php
87+
$cache = new \Yiisoft\Cache\File\FileCache('/path/to/directory');
88+
$parameters = ['user_id' => 42];
89+
$key = 'demo';
90+
91+
// try retrieving $data from cache
92+
$data = $cache->get($key);
93+
94+
if ($data === null) {
95+
// $data is not found in cache, calculate it from scratch
96+
$data = calculateData($parameters);
97+
98+
// store $data in cache for an hour so that it can be retrieved next time
99+
$cache->set($key, $data, 3600);
100+
}
101+
102+
// $data is available here
103+
```
104+
105+
In order to delete value you can use:
106+
107+
```php
108+
$cache->delete($key);
109+
// Or all cache
110+
$cache->clear();
111+
```
112+
113+
To work with values in a more efficient manner, batch operations should be used:
114+
115+
- `getMultiple()`
116+
- `setMultiple()`
117+
- `deleteMultiple()`
118+
119+
This package can be used as a cache handler for the [Yii Caching Library](https://github.com/yiisoft/cache).
23120

24121
### Unit testing
25122

src/FileCache.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
use function error_get_last;
1818
use function filemtime;
1919
use function fileowner;
20-
use function file_exists;
2120
use function fopen;
2221
use function function_exists;
2322
use function gettype;
@@ -140,9 +139,10 @@ public function set($key, $value, $ttl = null): bool
140139
}
141140

142141
$file = $this->getCacheFile($key);
142+
$cacheDirectory = dirname($file);
143143

144-
if ($this->directoryLevel > 0 && !$this->createDirectoryIfNotExists(dirname($file))) {
145-
return false;
144+
if (!is_dir($this->cachePath) || ($this->directoryLevel > 0 && !$this->createDirectoryIfNotExists($cacheDirectory))) {
145+
throw new CacheException("Failed to create cache directory \"{$cacheDirectory}\".");
146146
}
147147

148148
// If ownership differs the touch call will fail, so we try to
@@ -168,7 +168,7 @@ public function delete($key): bool
168168
$this->validateKey($key);
169169
$file = $this->getCacheFile($key);
170170

171-
if (!file_exists($file)) {
171+
if (!is_file($file)) {
172172
return true;
173173
}
174174

@@ -344,7 +344,7 @@ private function normalizeTtl($ttl): ?int
344344
*/
345345
private function createDirectoryIfNotExists(string $path): bool
346346
{
347-
return is_dir($path) || (mkdir($path, $this->directoryMode, true) && is_dir($path));
347+
return is_dir($path) || (!is_file($path) && mkdir($path, $this->directoryMode, true) && is_dir($path));
348348
}
349349

350350
/**
@@ -446,7 +446,7 @@ private function validateKeys(array $keys): void
446446
*/
447447
private function existsAndNotExpired(string $file): bool
448448
{
449-
return file_exists($file) && @filemtime($file) > time();
449+
return is_file($file) && @filemtime($file) > time();
450450
}
451451

452452
/**

tests/FileCacheTest.php

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@
1414
use Psr\SimpleCache\InvalidArgumentException;
1515
use ReflectionException;
1616
use stdClass;
17+
use Yiisoft\Cache\File\CacheException;
1718
use Yiisoft\Cache\File\FileCache;
1819
use Yiisoft\Cache\File\MockHelper;
1920

2021
use function array_keys;
2122
use function array_map;
2223
use function dirname;
2324
use function fileperms;
25+
use function file_put_contents;
2426
use function function_exists;
2527
use function glob;
2628
use function is_dir;
@@ -39,20 +41,22 @@ final class FileCacheTest extends TestCase
3941
{
4042
use PHPMock;
4143

44+
private const RUNTIME_DIRECTORY = __DIR__ . '/runtime';
45+
4246
private FileCache $cache;
4347
private string $tmpDir;
4448

4549
public function setUp(): void
4650
{
47-
$this->cache = new FileCache(__DIR__ . '/runtime/cache');
51+
$this->cache = new FileCache(self::RUNTIME_DIRECTORY . '/cache');
4852
$this->tmpDir = sys_get_temp_dir() . '/yiisoft-test-file-cache';
4953
}
5054

5155
public function tearDown(): void
5256
{
5357
MockHelper::$time = null;
5458
$this->removeDirectory($this->tmpDir);
55-
$this->removeDirectory(__DIR__ . '/runtime');
59+
$this->removeDirectory(self::RUNTIME_DIRECTORY);
5660
}
5761

5862
/**
@@ -483,6 +487,33 @@ public function testGcProbability(): void
483487
$this->assertFileDoesNotExist($cacheFile);
484488
}
485489

490+
public function testDeleteForCacheItemNotExist(): void
491+
{
492+
$this->assertNull($this->cache->get('key'));
493+
$this->assertTrue($this->cache->delete('key'));
494+
$this->assertNull($this->cache->get('key'));
495+
}
496+
497+
public function testSetThrowExceptionForInvalidCacheDirectory(): void
498+
{
499+
$directory = self::RUNTIME_DIRECTORY . '/cache/fail';
500+
$cache = new FileCache($directory);
501+
502+
$this->removeDirectory($directory);
503+
file_put_contents($directory, 'fail');
504+
505+
$this->expectException(CacheException::class);
506+
$cache->set('key', 'value');
507+
}
508+
509+
public function testConstructorThrowExceptionForInvalidCacheDirectory(): void
510+
{
511+
$file = self::RUNTIME_DIRECTORY . '/fail';
512+
file_put_contents($file, 'fail');
513+
$this->expectException(CacheException::class);
514+
new FileCache($file);
515+
}
516+
486517
public function invalidKeyProvider(): array
487518
{
488519
return [
@@ -502,7 +533,7 @@ public function invalidKeyProvider(): array
502533
*
503534
* @param mixed $key
504535
*/
505-
public function testGetInvalidKey($key): void
536+
public function testGetThrowExceptionForInvalidKey($key): void
506537
{
507538
$this->expectException(InvalidArgumentException::class);
508539
$this->cache->get($key);
@@ -513,7 +544,7 @@ public function testGetInvalidKey($key): void
513544
*
514545
* @param mixed $key
515546
*/
516-
public function testSetInvalidKey($key): void
547+
public function testSetThrowExceptionForInvalidKey($key): void
517548
{
518549
$this->expectException(InvalidArgumentException::class);
519550
$this->cache->set($key, 'value');
@@ -524,7 +555,7 @@ public function testSetInvalidKey($key): void
524555
*
525556
* @param mixed $key
526557
*/
527-
public function testDeleteInvalidKey($key): void
558+
public function testDeleteThrowExceptionForInvalidKey($key): void
528559
{
529560
$this->expectException(InvalidArgumentException::class);
530561
$this->cache->delete($key);
@@ -535,7 +566,7 @@ public function testDeleteInvalidKey($key): void
535566
*
536567
* @param mixed $key
537568
*/
538-
public function testGetMultipleInvalidKeys($key): void
569+
public function testGetMultipleThrowExceptionForInvalidKeys($key): void
539570
{
540571
$this->expectException(InvalidArgumentException::class);
541572
$this->cache->getMultiple([$key]);
@@ -546,7 +577,7 @@ public function testGetMultipleInvalidKeys($key): void
546577
*
547578
* @param mixed $key
548579
*/
549-
public function testGetMultipleInvalidKeysNotIterable($key): void
580+
public function testGetMultipleThrowExceptionForInvalidKeysNotIterable($key): void
550581
{
551582
$this->expectException(InvalidArgumentException::class);
552583
$this->cache->getMultiple($key);
@@ -557,7 +588,7 @@ public function testGetMultipleInvalidKeysNotIterable($key): void
557588
*
558589
* @param mixed $key
559590
*/
560-
public function testSetMultipleInvalidKeysNotIterable($key): void
591+
public function testSetMultipleThrowExceptionForInvalidKeysNotIterable($key): void
561592
{
562593
$this->expectException(InvalidArgumentException::class);
563594
$this->cache->setMultiple($key);
@@ -568,7 +599,7 @@ public function testSetMultipleInvalidKeysNotIterable($key): void
568599
*
569600
* @param mixed $key
570601
*/
571-
public function testDeleteMultipleInvalidKeys($key): void
602+
public function testDeleteMultipleThrowExceptionForInvalidKeys($key): void
572603
{
573604
$this->expectException(InvalidArgumentException::class);
574605
$this->cache->deleteMultiple([$key]);
@@ -579,7 +610,7 @@ public function testDeleteMultipleInvalidKeys($key): void
579610
*
580611
* @param mixed $key
581612
*/
582-
public function testDeleteMultipleInvalidKeysNotIterable($key): void
613+
public function testDeleteMultipleThrowExceptionForInvalidKeysNotIterable($key): void
583614
{
584615
$this->expectException(InvalidArgumentException::class);
585616
$this->cache->deleteMultiple($key);
@@ -590,7 +621,7 @@ public function testDeleteMultipleInvalidKeysNotIterable($key): void
590621
*
591622
* @param mixed $key
592623
*/
593-
public function testHasInvalidKey($key): void
624+
public function testHasThrowExceptionForInvalidKey($key): void
594625
{
595626
$this->expectException(InvalidArgumentException::class);
596627
$this->cache->has($key);

0 commit comments

Comments
 (0)