I kept needing a cache method that would only store a value permanently if the result was truthy. For expensive operations that might return null or false, I wanted to keep trying until I got a real result, then cache that forever.
The problem
Laravel’s Cache::rememberForever()
caches any result, including null/false values. Fairly often I want to cache successful results and keep retrying failed ones.
The solution
Add this macro to your AppServiceProvider
boot method:
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Cache;
public function boot()
{
// ... other boot code
// Calculate until we get a truthy result and then cache that forever
Cache::macro('rememberForeverIfTruthy', function (string $key, callable $cb) {
$val = Cache::get($key, false);
if ($val) {
return $val;
}
$result = $cb();
if ($result) {
Cache::forever($key, $result);
}
return $result;
});
}
Usage
// This will keep trying the API call until it succeeds,
// then cache the successful response forever
$data = Cache::rememberForeverIfTruthy('api_data', function () {
return Http::get('https://api.example.com/data')->json();
});
// Perfect for user milestone/activation status checks
$hasCompletedOnboarding = Cache::rememberForeverIfTruthy("user.{$user->id}.onboarding_complete", function () use ($user) {
return $user->profile_complete && $user->email_verified && $user->first_login_complete;
});
// Or checking if a user has reached an achievement
$isPowerUser = Cache::rememberForeverIfTruthy("user.{$user->id}.power_user", function () use ($user) {
return $user->posts()->count() >= 100 && $user->followers()->count() >= 1000;
});
Why this is useful
- Failed API calls don’t get cached, so you’ll retry on the next request
- Expensive operations that return null won’t prevent future attempts
- Once you get a truthy result, it’s cached forever
- Simple and clean API that follows Laravel conventions
The macro checks if there’s already a cached value, runs your callback if not, and only caches the result if it’s truthy. Perfect for those cases where you want persistence only after success.