Layer 4: Service & Repository Layer (HasAtomicCache)
Standardize caching in your service or repository classes by adding the HasAtomicCache trait.
4.1 Automatic Pagination & Filter Isolation (rememberCollection)
When caching paginated or filtered lists, rememberCollection() automatically inspects request()->query() and hashes the page number and filters into the cache key:
php
namespace App\Services;
use App\Models\Product;
use KaziOmar\AtomicCache\Traits\HasAtomicCache;
class ProductService
{
use HasAtomicCache;
protected string $cacheResource = 'products'; // Resource name and cache tag
public function getActiveProducts()
{
// GET /products?page=1 and GET /products?page=2 are cached separately:
return $this->rememberCollection('active', fn() => Product::where('status', 'active')->paginate(15));
}
}4.2 Single Item Caching (rememberItem)
php
public function findProduct(int $id)
{
// Caches under key "products:{id}", tagged with "products:{id}" and "products":
return $this->rememberItem($id, fn() => Product::findOrFail($id));
}4.3 Query Parameter Sanitization & Whitelisting
To prevent Cache Fragmentation, rememberCollection automatically strips common marketing and tracking query parameters (utm_*, fbclid, gclid, ttclid, ref, etc.). When 10,000 visitors arrive from ad campaigns with unique tracking IDs, they all share the exact same cached payload!
To enforce an explicit whitelist of allowed query parameters:
php
class ProductService
{
use HasAtomicCache;
// Only these parameters will be hashed into the cache key:
protected array $allowedQueryParams = ['page', 'sort', 'category'];
}4.4 DoS & Cache Poisoning Limits
To protect against memory exhaustion attacks, Atomic Cache enforces strict limits on request queries:
- Max Parameters (Default: 20): Queries exceeding 20 parameters cleanly bypass the cache and run against the database.
- Max Size (Default: 2048 bytes): Serialized query strings exceeding 2KB cleanly bypass caching.
4.5 Critical Rules & What Breaks Service Caching
- Do NOT use
remember()for paginated data:- If you call
$this->remember('active_products', 3600, fn() => Product::paginate(15))instead ofrememberCollection(), it will not inspectrequest()->query(). Page 1 results will be cached and returned for Page 2, Page 3, and all other pages. Always userememberCollection().
- If you call
- Resource name guessing mismatches:
- If your service class is named
CatalogManager, the trait guesses the resource tag as'catalog_managers'. If your database table isproducts,Productmodel events will clear'products', leaving'catalog_managers'stale. - Solution: Always explicitly declare
protected string $cacheResource = 'products';when the class name does not match the table name.
- If your service class is named
- Un-serializable objects in
$extraArgs:- Passing closures with un-serializable references into
$extraArgswill prevent deterministic cache key generation. Pass scalar values (integers, strings, arrays) instead.
- Passing closures with un-serializable references into