Search by

gogospace / laravel-bulk-cache

gogoSpace

Batched cache loading with explicit scopes and guarded Redis publication for Laravel.

Package info

github.com/gogoSpace/laravel-bulk-cache

pkg:composer/gogospace/laravel-bulk-cache

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v0.1.0-beta.2 2026-09-27 15:46 UTC

This package is auto-updated.

Last update: 2026-09-29 13:03:00 UTC


README

Read a set of keys, reuse cached values, and load missing items in batches. Each item is cached separately, so requests with overlapping keys can reuse the same data.

Laravel Bulk Cache adds rememberMany and flexibleMany alongside Laravel Cache, with explicit scopes for tenant, user, or locale, per-item invalidation, and optional stale-value refresh. The default driver uses your Laravel cache store; it needs no Redis or queue worker.

Quickstart · Documentation · Changelog · MIT license

Warning

Beta software. The public API and stored cache format may change before 1.0. The package has automated test coverage but no established production track record. Read the upgrade procedure when updating an existing installation.

Requirements and installation

PHP 8.3 or later and Laravel 12 or 13. The portable driver uses your Laravel cache store; it needs no Redis or queue worker. See compatibility and guarantees for tested environments and limits.

Install the exact beta version from Packagist:

composer require gogospace/laravel-bulk-cache:0.1.0-beta.2

Laravel discovers the service provider automatically. Publishing configuration is optional:

php artisan vendor:publish --tag=bulk-cache-config
php artisan config:cache

The default uses your application's default cache store. Use a persistent store such as file or database to reuse values across requests; array lasts only within the process. Set a distinct BULK_CACHE_PREFIX for every application and environment sharing a backend.

Quickstart

Run this in a Laravel route or Artisan command. The source is synthetic, so it needs no tables or external service. The initial scope invalidation makes the example repeatable; omit that line from normal reads.

use GogoSpace\BulkCache\Facades\BulkCache;
use GogoSpace\BulkCache\Missing;

$source = ['101' => ['name' => 'Notebook'], '102' => ['name' => 'Pencil']];
$loaderCalls = 0;
$loader = function (array $keys) use (&$source, &$loaderCalls): array {
    $loaderCalls++;
    $values = [];
    foreach ($keys as $key) {
        $values[$key] = $source[$key] ?? Missing::Value;
    }

    return $values;
};

$catalog = BulkCache::scope('quickstart-catalog-v1', ['locale' => 'en']);
$catalog->invalidateScope();
$first = $catalog->rememberMany([101, 102, 999], 60, $loader);
$second = $catalog->rememberMany([101, 102, 999], 60, $loader);

$source['101'] = ['name' => 'Updated notebook'];
$catalog->invalidateMany([101]);
$updated = $catalog->rememberMany([101, 102], 60, $loader);

return [
    'same_values' => $first === $second,
    'missing' => $second[999] === Missing::Value,
    'updated_name' => $updated[101]['name'],
    'loader_calls' => $loaderCalls,
];

The result is same_values: true, missing: true, updated_name: "Updated notebook", and loader_calls: 2. The second read needs no source call; invalidating item 101 reloads only that item. The same example is available as a PHP file.

In a database loader, use one whereIn query per callback and map its rows to every requested key. Return Missing::Value for an authoritative absence. A missing map key is an error. A timeout or failed query must throw; it must not become Missing::Value.

Refreshing older values

flexibleMany can return stale values while scheduling a refresh. “Stale” means older than the fresh duration but still inside an explicitly allowed extra window.

use GogoSpace\BulkCache\Freshness;

$values = $catalog->flexibleMany(
    [101, 102],
    Freshness::seconds(freshFor: 60, staleFor: 300),
    $loader,
);

This allows at most 60 fresh seconds plus 300 stale seconds. Missing or expired items load synchronously. Automatic refresh runs after an HTTP response below status 400; CLI calls refresh inline. See HTTP and queue lifecycle before using deferred refresh or queue workers.

Choosing where to use it

Start with an ordinary batch database query. Caching is useful when repeated reads avoid significant source work. It also adds storage operations, invalidation work, and a period in which data may be old. A cheap query or mostly unique requests may be better without caching.

Complete synthetic examples show a public catalog with per-user overlays and an expensive API or read model. See how to adapt them.

Documentation