{"id":15030138,"url":"https://github.com/matchory/response-cache","last_synced_at":"2025-04-09T20:40:56.740Z","repository":{"id":62524931,"uuid":"351876900","full_name":"matchory/response-cache","owner":"matchory","description":"A Laravel package that adds a smart cache for full responses","archived":false,"fork":false,"pushed_at":"2025-03-11T11:59:16.000Z","size":455,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-23T22:37:06.977Z","etag":null,"topics":["caching","laravel","laravel-package","performance","php","php8"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matchory.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-03-26T18:27:52.000Z","updated_at":"2025-03-11T11:58:09.000Z","dependencies_parsed_at":"2024-01-29T08:39:52.523Z","dependency_job_id":"c3e125fc-2f94-4524-a9e0-47b0a7d5a123","html_url":"https://github.com/matchory/response-cache","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matchory%2Fresponse-cache","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matchory%2Fresponse-cache/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matchory%2Fresponse-cache/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matchory%2Fresponse-cache/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matchory","download_url":"https://codeload.github.com/matchory/response-cache/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248109657,"owners_count":21049356,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["caching","laravel","laravel-package","performance","php","php8"],"created_at":"2024-09-24T20:12:32.893Z","updated_at":"2025-04-09T20:40:56.717Z","avatar_url":"https://github.com/matchory.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"Response Cache [![Latest Stable Version](https://poser.pugx.org/matchory/response-cache/v)](https://packagist.org/packages/matchory/response-cache) [![Total Downloads](https://poser.pugx.org/matchory/response-cache/downloads)](https://packagist.org/packages/matchory/response-cache) [![Latest Unstable Version](https://poser.pugx.org/matchory/response-cache/v/unstable)](https://packagist.org/packages/matchory/response-cache) [![License](https://poser.pugx.org/matchory/response-cache/license)](https://packagist.org/packages/matchory/response-cache) [![Laravel Octane Compatible](https://img.shields.io/badge/Laravel%20Octane-Compatible-success?style=flat\u0026logo=laravel)](https://github.com/laravel/octane)\n==============\n\u003e A Laravel package that adds a smart cache for full responses\n\nUsing this package, you can cache full response instances returned from your controllers, simply by adding a middleware.  \nThis can speed up your application immensely!\n\nFeatures\n--------\n\n- **Easy to use**: Just [add the `CacheResponse`](#using-the-responsecache-middleware-manually) to your route!\n- **Fully customizable**: The cache probably works out of the box, but you can control every aspect of caching if necessary.\n- **Support for authenticated requests**: By default, cache entries will be unique to every authenticated user.\n- **Resolves route bindings in tags**: Cache tags may use any value in the route or request data dynamically.\n\n```php\nRoute::get('/example')-\u003emiddleware([\n    'cacheResponse:3600,examples'\n])\n```\n\nAlternatives\n------------\nCoincidentally, I just learned [spatie](https://spatie.be/) have built almost exactly the same library as we did:  \n[spatie/laravel-responsecache](https://github.com/spatie/laravel-responsecache).\n\n### Why not use Varnish?\nIn contrast to external caches, having the response cache in your app gives you the power to evaluate route bindings, authentication state, and easy programmatic cache flushing.  \nThis also makes it possible to place the cache check anywhere in your middleware stack!\n\nRequirements\n------------\n\n- **PHP 8.0 or later**\n- Laravel 7.x or later\n\nInstallation\n------------\nInstall using composer:\n\n```bash\ncomposer require matchory/response-cache\n```\n\nUnless you have disabled package discovery, everything should be set up already. Otherwise, add the service provider and the facade to your configuration.\n\nOptionally, you can publish the configuration file:\n\n```bash\nphp artisan vendor:publish --provider \"Matchory\\ResponseCache\\ResponseCacheProvider\"\n```\n\nCheck out the [configuration section](#configuration) to learn about all available options.\n\nAdd the middleware to your `app/Http/Kernel.php`:\n\n```php\nprotected $middlewareGroups = [\n   'web' =\u003e [\n       // ...\n       \\Matchory\\ResponseCache\\Http\\Middleware\\CacheResponse::class,\n       // ...\n   ],\n];\n\nprotected $routeMiddleware = [\n    // ...\n    'bypass_cache' =\u003e \\Matchory\\ResponseCache\\Http\\Middleware\\BypassCache::class,\n    // ...\n];\n```\n\nConfiguration\n-------------\nThe config file contains the following settings:\n\n### `enabled` (Environment variable: `RESPONSE_CACHE_ENABLED`)\nUsing this setting, you can globally enable or disable the response cache for all requests. If you set it to `false`, nothing will be cached.\n\nDefaults to `true`.\n\n### `ttl` (Environment variable: `RESPONSE_CACHE_TTL`)\nThis setting specifies the amount of time responses will be cached before being marked as stale. The value must be specified in seconds.\n\nDefaults to `60 * 60 * 24`, or exactly 24 hours.\n\n### `store` (Environment variable: `RESPONSE_CACHE_STORE`)\nHere you may pass any cache store defined in your `config/cache.php` file. Please note that not all stores support tagging: For better control over and\nincreased performance of your cache, we strongly recommend using a store with tag support, like Redis or APC.\n\nDefaults to `file`.\n\n### `tags` (Environment variable: `RESPONSE_CACHE_TAGS`)\nIf your store supports tags, all responses cached will also be tagged with these tags by default. Additional tags may be used depending on the middleware and\nstrategy.\n\nDefaults to `[]`.\n\n### `server_timing` (Environment variable: `RESPONSE_CACHE_SERVER_TIMING`)\nIf the server timing option is enabled, a Server-Timing header containing the initial caching time will be added to all cached responses. This makes debugging\neasier. Leaving it enabled in production probably has no negative consequences aside from a small performance penalty due to the bigger response size.\n\nDefaults to `false`.\n\n### `cache_status_enabled` (Environment variable: `RESPONSE_CACHE_STATUS_ENABLED`)\nIf the cache status option is enabled, a `Response-Cache-Status` header containing the cache status (`hit` or `miss`) will be added to all responses. This makes debugging easier.\n\nDefaults to `true`.\n\nUsage\n-----\nAfter following the installation instructions above, you should be ready to go: Responses with a status code in the `200` and `300` range will be cached and\nreturned on subsequent visits. To bypass the cache for specific routes, you can simply add the `bypass_cache` middleware:\n\n```php\nRoute::get('/kitten')-\u003emiddleware('bypass_cache');\n```\n\n### Flushing the cache manually\nTo clear the cache manually, you can use the `response-cache:flush` artisan command:\n\n```bash\nphp artisan response-cache:flush\n```\n\nThis will flush the entire response cache. To delete a given set of cache tags only, add them to the command:\n\n```bash\nphp artisan response-cache:flush tag-1 tag-2 ... tag-n\n```\n\n### Flushing the cache programmatically\nIn production use, it is often helpful to flush the cache automatically if something happens. For example, you can flush the cache whenever a model event is\nfired by setting up an observer:\n\n```php\nuse Matchory\\ResponseCache\\Facades\\ResponseCache;\n\nclass ExampleObserver {\n    public function saved(): void {\n        ResponseCache::clear();\n    }\n\n    public function deleted(): void {\n        // By passing one or more tags, only those items tagged appropriately\n        // will be cleared\n        ResponseCache::clear(['example']);\n    }\n}\n```\n\nBy invoking the `clear` method, the entire store (for the given tags) will be purged. To be more selective, use the `delete` method:\n\n```php\nuse Matchory\\ResponseCache\\Facades\\ResponseCache;\n\nResponseCache::delete('/example/url');\nResponseCache::delete(['/example/1', '/example/2']);\n```\n\n\u003e **Note:** This will not work for cache items that require context information, such as user authentication. If you hit this problem, you'll probably want to\n\u003e work with tags instead.\n\n#### Cache Tags\nCache tags are a simple, yet very powerful mechanism for efficient cache usage. By applying tags to a set of cached items, you can purge all of them, without\never knowing the individual cache keys of these items. Say, there are lots of cached data points all related to \"flights\": plane schedules, arrival dates,\npassenger records, etc. All is fine and well, until a flight is cancelled! Now, we will need to purge the cache for anything that includes the flight in\nquestion. This would be a logical nightmare, hadn't we set up cache tags: Instead of deleting lots of items manually, we instruct Laravel to purge all items\ntagged with the flight number, and we're good to go!\n\nThis library is built heavily around the concept of cache tags: By tagging properly, you can make granular cache flushing a breeze. Tags can be added to routes\nusing several approaches:\n\n- By passing them to the middleware:\n  ```php\n  Route::get('/foo')-\u003emiddleware(['cache:tag-1,tag-2']);\n  ```\n- By adding them to the `config/response-cache.php` config file:\n  ```php\n  'tags' =\u003e env('RESPONSE_CACHE_TAGS', [ 'tag-1', 'tag-2' ]),\n  ```\n- By returning them from [your strategy](#customizing-tagging).\n\n#### Using bindings in cache tags\nThis library supports adding dynamic tags that are based on route bindings. This works pretty much the same as with ordinary route bindings, but with the added\nbenefit of also having access to all request values, not just those mentioned in the route itself.  \nTo add a binding to your cache tag, simply include the name of a parameter in curly braces: `flights.{flight}`. As soon as something is to be fetched from or\nput into the cache, this binding will be resolved using the current request instance. If the parameter `flight` was an instance of an Eloquent model, it would\nbe replaced with its route key name, so probably the flight ID!\n\nTake a look at the following example:\n\n```php\nRoute::get('/api/v{version}/flights/{flight}', function(\\App\\Flight $flight) {\n    // ...\n})-\u003emiddleware('cache:api.v{version},flights,flights.v{version},flights.{flight},flights.v{version}.{flight}');\n```\n\nImagine we perform the following request: `/api/v3/flights/505`  \nNow, the response generated by this route would be tagged with the following tags:\n\n- `api.v3`\n- `flights`\n- `flights.v3`\n- `flights.505`\n- `flights.v3.505`\n\nDepending on your requirements, you can simply flush the cache for any of these and rest assured the response will be invalidated!\n\n### Caching Strategies\nA _strategy_ is what the response cache uses to determine just how a response should be cached. It generates cache keys, determines cache tags and controls\ncache bypassing. The default strategy should fit for most use cases, but if it doesn't, we got you covered, too!\n\nTo use a custom strategy, start by either extending [the default implementation](./src/Support/BaseStrategy.php) (recommended) or\nimplementing [the `CacheStrategy` interface](./src/Contracts/CacheStrategy.php).\n\n#### Customize cache keys\nTo customize the way cache keys are generated, you have several options, as the default implementation splits this process in multiple methods:\n\n```php\nuse Illuminate\\Http\\Request;use Matchory\\ResponseCache\\Support\\BaseStrategy;\n\nclass MyStrategy extends BaseStrategy\n{\n    public function key(Request $request): string\n    {\n        $identifier = $this-\u003eextractRequestIdentifier($request);\n        $suffix = $this-\u003ebuildSuffix($request);\n\n        return $this-\u003ehash($identifier . $suffix);\n    }\n}\n```\n\n- The `extractRequestIdentifier` method extracts the full request URL and method as the base of the cache key. This should be enough in most applications.\n- The `buildSuffix` method checks for the current authentication status and appends the ID of the authenticated user. You may wish to modify this to use a\n  customer or application identifier, for example.\n- The `hash` method builds a hash of the given cache key (by default it uses `md5`), so the key length stays consistent.\n\n#### Customizing cache bypass\nTo customize whether a response is cached or not, you can implement one or more helpers:\n\n```php\nuse Illuminate\\Http\\Request;\nuse Matchory\\ResponseCache\\Support\\BaseStrategy;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\nclass MyStrategy extends BaseStrategy\n{\n    public function shouldCache(Request $request, Response $response): bool\n    {\n        if (! $this-\u003eisMethodCachable($request)) {\n            return false;\n        }\n\n        return $this-\u003eisSuccessful($response);\n    }\n}\n```\n\nBy default, this will cache any request with the `GET` or `HEAD` methods, and responses with a success or redirection status.\n\n#### Customizing tagging\nTagging cached responses is an immensely powerful feature that allows you to flush a collection of cache entries if something happens. So if a single member of\na collection is deleted, for example, you can remove all cached instances of the same collection, without having to know the exact cache keys used to retrieve\nthem!  \nTo make this as easy as possible, strategies provide a method to pull tags from a request and response:\n\n```php\nuse Illuminate\\Http\\Request;\nuse Matchory\\ResponseCache\\Support\\BaseStrategy;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\nclass MyStrategy extends BaseStrategy\n{\n    public function tags(Request $request, Response|null $response = null): array\n    {\n        return [\n            $request-\u003eattributes-\u003eget('customer.id')\n        ];\n    }\n}\n```\n\n### Using the `ResponseCache` middleware manually\nInstead of simply adding the caching middleware to all web routes as shown above, you can of course also add it to selected routes manually. In this case, you\nalso have the possibility to configure the time to leave and add a set of tags per route:\n\n```php\n// Default settings as set in the config file\nRoute::get('/foo')-\u003emiddleware('response_cache')\n\n// TTL of 60 seconds\nRoute::get('/bar')-\u003emiddleware('response_cache:60');\n\n// Tags \"foo\", \"bar\" and \"baz\" are added\nRoute::get('/baz')-\u003emiddleware('response_cache:foo,bar,baz'); \n\n// TTL of 60 seconds and tags \"foo\", \"bar\" and \"baz\" are added\nRoute::get('/quz')-\u003emiddleware('response_cache:60,foo,bar,baz');\n```\n\nIf the first parameter to the middleware is a number, it will be interpreted as a TTL value, everything that follows as tags. The TTL will override the\n[configuration value](#ttl-environment-variable-response_cache_ttl), tags will be merged.\n\n### Reacting to cache events\nThis library exposes some events you can listen for and act accordingly. This is probably most helpful during [debugging](#debugging).\n\n#### `Hit`\nEmitted if a response was found in the cache. Includes the request instance.\n\n#### `Miss`\nEmitted if a response could not be found in the cache or was [indicated as non-cachable by the caching strategy](#caching-strategies) and thus had to be\ngenerated by the application. Includes the request instance.\n\n#### `Flush`\nEmitted if the cache was flushed. Includes the tags that were flushed, or `null` if all tags were flushed.\n\n### Manual response serialization\nBy default, the response cache uses a [cache repository implementation](./src/Repository.php) with a very simple serialization method: _Doing nothing_. Any\nserialization is deferred to Laravel's cache implementation. In rare cases, you may need to change this behavior and modify a response before serializing or\nafter hydrating it.  \nTo do so, start by extending the `Repository` class:\n\n```php\nuse Matchory\\ResponseCache\\Repository;\nuse Symfony\\Component\\HttpFoundation\\Response;\n\nclass CustomRepository extends Repository\n{\n    protected function serialize(Response $response) : mixed\n    {\n        return serialize($response); \n    }\n\n    protected function hydrate(mixed $responseData): Response\n    {\n        return unserialize($responseData, [Response::class])\n    }\n}\n```\n\nOverride the container binding in your `AppServiceProvider`, so your repository will be used instead of the default:\n\n```php\nuse Matchory\\ResponseCache\\Repository;\n\nprotected function register():void\n    {\n        $this-\u003eapp-\u003ebind(Repository::class, CustomRepository::class);\n    }\n```\n\n### Debugging\nCache issues can be a little annoying to debug. This library has several facilities built in to make the process as simple as possible:\n\n1. **Enable the `Server-Timing` header**: By switching this feature on, all responses will include a\n   [`Server-Timing` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Server-Timing) that includes the time your response was cached. This\n   information will automatically show up in your browser's developer tools!\n2. **Listen to cache events**: By listening to [the cache events](#reacting-to-cache-events), you can make sure everything is working as intended.\n3. **Temporarily or conditionally disable caching**: By changing the `response-cache.enabled` setting, you can quickly determine whether caching is the culprit.\n4. **Use a custom repository**: [Override the built-in serialization method](#manual-response-serialization) to take control of response serialization and\n   hydration.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatchory%2Fresponse-cache","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatchory%2Fresponse-cache","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatchory%2Fresponse-cache/lists"}