PHPackages                             henzeb/warmable - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Caching](/categories/caching)
4. /
5. henzeb/warmable

ActiveLibrary[Caching](/categories/caching)

henzeb/warmable
===============

A framework agnostic cache warmer

v1.1.0(2y ago)0181AGPL-3.0-onlyPHPPHP ^8.1

Since Feb 18Pushed 2y ago1 watchersCompare

[ Source](https://github.com/henzeb/warmable)[ Packagist](https://packagist.org/packages/henzeb/warmable)[ Docs](https://github.com/henzeb/warmable)[ RSS](/packages/henzeb-warmable/feed)WikiDiscussions master Synced 2d ago

READMEChangelog (2)Dependencies (5)Versions (3)Used By (1)

Warmable
========

[](#warmable)

[![Latest Version on Packagist](https://camo.githubusercontent.com/e3628eb7570dba55d48e94577beb4220e55cd6e6dbd9be9e250ebeb149e6d5b6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f68656e7a65622f7761726d61626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/henzeb/warmable)[![Total Downloads](https://camo.githubusercontent.com/aa731c2dd4399e900abc5816452773767865a269760994d28445a14a29845057/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f68656e7a65622f7761726d61626c652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/henzeb/warmable)

This package was inspired by a talk by [@timacdonald](https://github.com/timacdonald) where he showed a technique to warm up a cache entry scheduled by using a simple invokable class.

When you cache the result of a heavy operation, once in a while, some user will have to wait for the operation to be cached again. If the request rate is high enough, multiple people may have to do so at the same time.

This package provides the framework in which you can take all that away. It is implementing the [PSR16](https://www.php-fig.org/psr/psr-16/) interface for caching, so it pretty much supports every caching mechanism you can think of, and if not, one can implement a wrapper, and it still supports every caching mechanism you can think of.

Laravel-developers can use this package as well, but in order to harvest the full power of Laravel, it's better to install and use [Warmable for Laravel](https://packagist.org/packages/henzeb/warmable-laravel)

Installation
------------

[](#installation)

Just install with the following command.

```
composer require henzeb/warmable
```

Terminology
-----------

[](#terminology)

#### Warm up / warming up

[](#warm-up--warming-up)

The term `warm up` or `warming up` refers to caching during a cron job or in a queue job.

#### preheating

[](#preheating)

Preheating is the term used when the cache is populated during execution, which is the default operation when the cache does not exist. This may also be dispatched to a background operation like a Queueing System.

Usage
-----

[](#usage)

### Creating a Warmable

[](#creating-a-warmable)

Creating a `Warmable` is pretty easy.

```
use Henzeb\Warmable\Warmable;
use Psr\SimpleCache\CacheInterface;
use DateTimeInterface;
use DateInterval;

class HeavyOperation extends Warmable
{
    protected function key() : string
    {
        // ... return your key
    }

    protected function ttl() : DateTimeInterface|DateInterval|int|null
    {
        // ... return your desired ttl
    }

    protected function gracePeriod() : DateTimeInterface|DateInterval|int|null
    {
        // ... return your desired grace period
    }

    protected function cache(): CacheInterface
    {
         // ... your cache implementation
    }

    protected function warmable(): mixed
    {
         // ... your heavy operation
    }
}
```

Note: The `key` and the `ttl` can be omitted. When omitting the `key`, a key is generated based on the FQCN of your object. When `ttl` is omitted, the `Warmable` result will be stored in cache forever.

chaining methods.
-----------------

[](#chaining-methods)

`Warmable` allows chaining methods. You can start with any method you wish.

```
HeavyOperation::withKey('yourKey')->get();

HeavyOperation::withTtl(300)->withKey('yourKey')->get();

HeavyOperation::withKey('yourKey')->withTtl(300)->get();
```

### make

[](#make)

With `make` you can easily get an instance of your `Warmable`. You can add arguments that will be passed on to your constructor.

```
// equivalent to new HeavyOperation();
HeavyOperation::make();

// equivalent to new HeavyOperation(new YourService());
HeavyOperation::make(new YourService());
```

### get

[](#get)

With this method you can easily access the cached data.

```
HeavyOperation::get();
HeavyOperation::make()->get();
```

By default,`Warmable` preheats the data for the first time if it does not exist yet. If you don't want that to happen before response, you can set a default. In that case it will postpone that action until after the response is sent to the browser.

```
HeavyOperation::get([]);

HeavyOperation::get(true);

HeavyOperation::get(fn()=>false);
```

Note: this doesn't work with `null`. Use [withoutPreheating](#withoutPreheating) instead.

### with

[](#with)

The warmable method supports a rudimentary version of dependency injection. Using this method, you can make your cache unique per user or item. You don´t have to do anything else besides passing it into the constructor.

```
use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    // ...

    public function warmable(int $id): mixed {
        // ...
        return 'this is '.$id;
    }
}

HeavyOperation::with(12)->get(); // returns 'this is 12'
HeavyOperation::with(14)->get(); // returns 'this is 14'
HeavyOperation::with(12)->get(); // returns 'this is 12' from cache
HeavyOperation::with(14)->get(); // returns 'this is 14' from cache
```

### key

[](#key)

By default, `Warmable` will generate a unique key for you. You don't need to do anything. Even if you want to reuse the `Warmable` for different items, `Warmable` got your back. But if you do want to customize the key, there are 2 ways to do it.

The first is by setting the `key` method on your `Warmable` class.

```
use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable {
    protected function key() : string{
        return 'your-key';
    }
}

HeavyOperation::get(); // retrieves from 'your-key'
HeavyOperation::with(12)->get(); // retrieves from 'your-key.'
```

The second option is inline:

```
HeavyOperation::withKey('other-key')->get(); // retrieves from 'other-key'
HeavyOperation::withKey('other-key')
->with(12)
->get(); // retrieves from 'other-key.'
```

### Cache

[](#cache)

The cache is, obviously, a required element. It's set through the mandatory `cache` method. There is also a `withCache` method that can be used inline.

```
use Psr\SimpleCache\CacheInterface;
HeavyOperation::withCache();
HeavyOperation::make()->withCache();
```

Note: `Warmable` accepts any Cache implementation that implements the PSR-16 `CacheInterface`. If the cache system you are using does not implement it, you can easily create a wrapper that does implement it.

### Time To Live (Ttl)

[](#time-to-live-ttl)

Allows you to use a different TTL than the one defined inside your class.

Note Ttl is `null`, and thus `forever`, by default.

```
use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    protected function ttl(): DateTimeInterface|DateInterval|int|null {
         return DateInterval::createFromDateString('300 seconds');
    }
}
```

Or you can set things inline inline:

```
use Henzeb\Warmable\Warmable;

// expires on given date
HeavyOperation::withTtl(new DateTime('2024-02-31 23:00'));

// expires in 300 seconds
HeavyOperation::withTtl(
DateInterval::createFromDateString('300 seconds')
);

// expires in 300 seconds
HeavyOperation::withTtl(300);
```

### Grace periods

[](#grace-periods)

In combination with a Ttl, a grace period allows you to give the user the old data while updating the cache. This updating happens after returning the response to the browser.

The example below will create a cache item that lives for 600 seconds. 300+ seconds in, the next call will return the value in the cache, and registers a shutdown function that updates the cache item, which will live for 600 seconds, and so on.

```
use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    protected function ttl(): DateTimeInterface|DateInterval|int|null {
         return 300
    }

    protected function gracePeriod(): DateTimeInterface|DateInterval|int|null {
         return 300
    }
}
```

### getKey

[](#getkey)

There may be occasions where you need to see the key used by your `Warmable`.

```
// returns warmable.HeavyOperation
HeavyOperation::getKey();

// returns test
HeavyOperation::withKey('test')->getKey();

// returns test.
HeavyOperation::withKey('test')->with(id)->getKey();
```

### missing

[](#missing)

```
// returns true
HeavyOperation::missing();
// returns false
HeavyOperation::get(); // will preheat the cache
HeavyOperation::make()->missing();
HeavyOperation::missing();
```

### isPreheated

[](#ispreheated)

This method tells you if the cache was preheated.

```
$operation = HeavyOperation::make();
$operation->isPreheated(); // returns false
$operation->get(); // will preheat the cache
$operation->isPreheated(); // returns true
```

### withoutPreheating

[](#withoutpreheating)

This method allows you to explicitly disable preheating.

```
HeavyOperation::withoutPreheating()->get(); // returns null when not warmed up

// and when called again:
HeavyOperation::withoutPreheating()->get(); // returns null when not warmed up
```

### withPreheating

[](#withpreheating)

Works exactly like [withoutPreheating](#without), except it switches the preheating on.

```
// would preheat the warmable data.
HeavyOperation::withPreheating()->get();

// would preheat the data after shutdown, and return default instead.
HeavyOperation::withPreheating()->get([]);
```

### shouldPreheat

[](#shouldpreheat)

A method that tells you if preheat flag is turned on

```
HeavyOperation::shouldPreheat(); // returns true (default)
HeavyOperation::withPreheating()->shouldPreheat(); // returns true
HeavyOperation::withoutPreheating()->shouldPreheat(); // returns false
```

### cooldown

[](#cooldown)

If for some reason you need to delete the cache, you can call `cooldown`.

```
HeavyOperation::cooldown();
HeavyOperation::make()->cooldown();
```

### Custom warmup strategy

[](#custom-warmup-strategy)

If your application has access to a queue, it is easy to change the preheat strategy. By default, it preheats during execution.

```
use Henzeb\Warmable\Warmable;

class HeavyOperation extends Warmable
{
    // ... your Warmable definition

    protected function getPreheated(bool $hasDefault): mixed
    {
        // ...
    }
}
```

Note: Returning `null` causes the `get` method to use the default.

### Overriding public interface

[](#overriding-public-interface)

Under the hood, `Warmable` uses `__call` and `__callStatic` to allow chaining static and dynamic calls. If you want to override a method on the public interface, you should find it's `call` counterpart.

For Example: If you want to override the `with` method, you should extend the `callWith` method.

Testing
-------

[](#testing)

```
composer test
```

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

### Security

[](#security)

If you discover any security related issues, please email  instead of using the issue tracker.

Credits
-------

[](#credits)

- [Henze Berkheij](https://github.com/henzeb)

License
-------

[](#license)

The GNU AGPLv. Please see [License File](LICENSE.md) for more information.

###  Health Score

24

—

LowBetter than 31% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity6

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity52

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~3 days

Total

2

Last Release

863d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/15928532?v=4)[henzeb](/maintainers/henzeb)[@henzeb](https://github.com/henzeb)

---

Top Contributors

[![henzeb](https://avatars.githubusercontent.com/u/15928532?v=4)](https://github.com/henzeb "henzeb (2 commits)")

---

Tags

performancecachewarmupspeedhenzebspeedupUpwarmerwarmpreheatwarmableheat

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/henzeb-warmable/health.svg)

```
[![Health](https://phpackages.com/badges/henzeb-warmable/health.svg)](https://phpackages.com/packages/henzeb-warmable)
```

###  Alternatives

[spatie/laravel-responsecache

Speed up a Laravel application by caching the entire response

2.8k9.0M69](/packages/spatie-laravel-responsecache)[putyourlightson/craft-blitz

Intelligent static page caching for creating lightning-fast sites.

155484.7k37](/packages/putyourlightson-craft-blitz)[laminas/laminas-cache

Caching implementation with a variety of storage options, as well as codified caching strategies for callbacks, classes, and output

1077.3M154](/packages/laminas-laminas-cache)[voku/simple-cache

Simple Cache library

332.7M10](/packages/voku-simple-cache)[anahkiasen/flatten

A package for the Illuminate framework that flattens pages to plain HTML

33313.0k](/packages/anahkiasen-flatten)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
