Cache

The Cache class is Slenix's file-based caching system. It stores data as JSON files inside the storage/cache/ directory and supports TTL (Time To Live), permanent storage, lazy population, atomic counters, and manual cleanup — with zero external dependencies.


How It Works

Each cached value is written as a .json file named after an MD5 hash of the key (plus optional prefix). The file contains the value and an expiry timestamp. On read, expired entries are detected and deleted automatically.


Configuration

These methods are typically called once during application bootstrap.

Setting the cache directory

php
Cache::setPath('/custom/path/to/cache');

If not set, the default directory is storage/cache/ relative to the project root (or the STORAGE_PATH constant if defined).

Setting a global key prefix

Prefixes prevent key collisions when multiple applications share the same cache directory.

php
Cache::setPrefix('myapp_');

Storing Values

Cache::put(string $key, mixed $value, int $ttl = 3600): void

Stores any serializable value with a TTL in seconds. Defaults to 3600 seconds (1 hour).

php
Cache::put('homepage_posts', $posts, 600);       // expires in 10 minutes
Cache::put('exchange_rate', 1.23, 60);           // expires in 1 minute
Cache::put('settings', $configArray, 86400);     // expires in 24 hours

Pass 0 as TTL to store without expiry:

php
Cache::put('feature_flags', $flags, 0);          // never expires

Cache::forever(string $key, mixed $value): void

Convenience wrapper for put() with ttl = 0. Stores the value permanently until manually removed.

php
Cache::forever('countries', $countriesList);

Retrieving Values

Cache::get(string $key, mixed $default = null): mixed

Returns the cached value, or $default if the key does not exist or has expired. Expired entries are deleted from disk on read.

php
$posts = Cache::get('homepage_posts');

// With a default fallback
$rate = Cache::get('exchange_rate', 1.00);

Cache::remember(string $key, int $ttl, callable $callback): mixed

Returns the cached value if it exists. Otherwise, executes the callback, stores its return value, and returns it. This is the most common pattern for caching expensive operations.

php
$users = Cache::remember('all_users', 300, function () {
    return User::all();
});
php
$stats = Cache::remember('dashboard_stats', 3600, function () {
    return [
        'total_orders'   => Order::count(),
        'total_revenue'  => Order::sum('total'),
        'new_users_today' => User::today()->count(),
    ];
});

Checking Existence

Cache::has(string $key): bool

Returns true if the key exists and has not expired.

php
if (!Cache::has('exchange_rate')) {
    // fetch and cache a fresh rate
}

Removing Values

Cache::forget(string $key): bool

Deletes a specific cache entry. Returns true on success.

php
Cache::forget('homepage_posts');

Cache::flush(): int

Deletes all cache files in the cache directory. Returns the number of files removed.

php
$removed = Cache::flush();
echo "Cleared {$removed} cache entries.";

Cache::purgeExpired(): int

Scans the cache directory and removes only entries that have expired. Useful as a scheduled maintenance task. Returns the number of files removed.

php
$purged = Cache::purgeExpired();
echo "Removed {$purged} stale cache files.";

Counters

Cache keys holding integer values can be incremented and decremented atomically. The original TTL of the key is preserved across updates.

Cache::increment(string $key, int $by = 1): int

Increments the stored integer value and returns the new value. If the key does not exist, it starts from 0.

php
Cache::increment('page_views');          // 1
Cache::increment('page_views');          // 2
Cache::increment('page_views', 10);      // 12

Cache::decrement(string $key, int $by = 1): int

Decrements the stored integer value and returns the new value.

php
Cache::decrement('available_seats');     // -1 from current
Cache::decrement('available_seats', 5);  // -5 from current

TTL Reference

TTL valueBehaviour
0Stored forever — never auto-expires
60Expires in 1 minute
3600Expires in 1 hour (default)
86400Expires in 24 hours

Method Reference

MethodReturnsDescription
Cache::put($key, $value, $ttl)voidStores a value with a TTL
Cache::forever($key, $value)voidStores a value with no expiry
Cache::get($key, $default)mixedRetrieves a value or returns default
Cache::remember($key, $ttl, $fn)mixedGets cached value or runs callback
Cache::has($key)boolChecks if a key exists and is valid
Cache::forget($key)boolDeletes a specific cache entry
Cache::flush()intDeletes all cache files
Cache::purgeExpired()intDeletes only expired cache files
Cache::increment($key, $by)intIncrements an integer value
Cache::decrement($key, $by)intDecrements an integer value
Cache::setPath($path)voidSets a custom cache directory
Cache::setPrefix($prefix)voidSets a global key prefix

Complete Example

php
use Slenix\Supports\Cache\Cache;

// Bootstrap (e.g. in config/app.php)
Cache::setPrefix('myapp_');

// -------------------------------------------------------
// Controller — caching a database query
// -------------------------------------------------------

public function index(Request $request, Response $response): void
{
    $products = Cache::remember('products_list', 300, function () {
        return Product::active()->orderBy('name')->get();
    });

    return $response->json($products);
}

// -------------------------------------------------------
// After an update, invalidate the relevant cache entry
// -------------------------------------------------------

public function update(Request $request, Response $response, int $id): void
{
    Product::find($id)->update($request->only('name', 'price'));

    Cache::forget('products_list');

    return $response->json(['message' => 'Product updated.']);
}

// -------------------------------------------------------
// Rate-limiting with counters
// -------------------------------------------------------

public function contact(Request $request, Response $response): void
{
    $ip  = $request->ip();
    $key = "contact_attempts_{$ip}";

    if (Cache::get($key, 0) >= 5) {
        return $response->status(429)->json([
            'error' => 'Too many requests. Please wait before trying again.',
        ]);
    }

    Cache::increment($key);

    if (!Cache::has("{$key}_ttl_set")) {
        Cache::put($key, Cache::get($key, 1), 3600); // reset window after 1 hour
        Cache::forever("{$key}_ttl_set", true);
    }

    // process contact form ...

    return $response->json(['message' => 'Message sent.']);
}

// -------------------------------------------------------
// Scheduled cleanup (e.g. via a daily job)
// -------------------------------------------------------

public function handle(): void
{
    $removed = Cache::purgeExpired();
    echo "Purged {$removed} expired cache entries." . PHP_EOL;
}