{"id":15045102,"url":"https://github.com/toflar/psr6-symfony-http-cache-store","last_synced_at":"2025-04-09T09:08:51.210Z","repository":{"id":45322528,"uuid":"105002553","full_name":"Toflar/psr6-symfony-http-cache-store","owner":"Toflar","description":"An alternative store implementation for Symfony's HttpCache reverse proxy that supports auto-pruning of expired entries and cache invalidation by tags.","archived":false,"fork":false,"pushed_at":"2024-01-15T15:42:29.000Z","size":107,"stargazers_count":56,"open_issues_count":1,"forks_count":5,"subscribers_count":5,"default_branch":"4.x","last_synced_at":"2025-04-09T09:08:44.097Z","etag":null,"topics":["http-cache","reverse-proxy","symfony-bundle"],"latest_commit_sha":null,"homepage":null,"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/Toflar.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":"2017-09-27T10:01:17.000Z","updated_at":"2025-02-13T08:54:06.000Z","dependencies_parsed_at":"2024-06-18T14:07:49.268Z","dependency_job_id":null,"html_url":"https://github.com/Toflar/psr6-symfony-http-cache-store","commit_stats":{"total_commits":67,"total_committers":5,"mean_commits":13.4,"dds":0.07462686567164178,"last_synced_commit":"25623d8e0858223f6849d2200d36a43df17c655d"},"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toflar%2Fpsr6-symfony-http-cache-store","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toflar%2Fpsr6-symfony-http-cache-store/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toflar%2Fpsr6-symfony-http-cache-store/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Toflar%2Fpsr6-symfony-http-cache-store/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Toflar","download_url":"https://codeload.github.com/Toflar/psr6-symfony-http-cache-store/tar.gz/refs/heads/4.x","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248008630,"owners_count":21032556,"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":["http-cache","reverse-proxy","symfony-bundle"],"created_at":"2024-09-24T20:51:27.594Z","updated_at":"2025-04-09T09:08:51.183Z","avatar_url":"https://github.com/Toflar.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PSR-6 compatible Symfony HttpCache Store\n\n## Supported branches\n\n* For PHP ^7.2 and Symfony \u003c6, use version 3.x\n* For PHP ^8.0 and Symfony \u003e6, use version 4.x\n\n## Introduction\n\nSymfony's `HttpCache` store implementation is rather old and was developed\nwhen there were no separate components for locking and caching yet. Moreover, \nexpired cache entries are never pruned and thus causes your cache directory\nto continue to grow forever until you delete it manually.\n\nAlong the way, I needed support for cache invalidation based on tags which was\npretty easy to implement thanks to the Symfony Cache component.\n\nThis bundle thus provides an alternative `StoreInterface` implementation\nthat…\n\n* …instead of re-implementing locking and caching mechanisms again, uses the well\ntested Symfony Cache and Lock components, both with the local filesystem adapters\nby default.\n* …thanks to the `TagAwareAdapterInterface` of the Cache component, supports tag\nbased cache invalidation.\n* …thanks to the `PrunableInterface` of the Cache component, supports auto-pruning\nof expired entries on the filesystem trying to prevent flooding the filesystem.\n* …allows you to use a different PSR-6 cache adapters as well as a different \nlock adapter than the local filesystem ones.\n However, **be careful about choosing the right adapters**, see warning below.\n* …supports `BinaryFileResponse` instances.\n\n## Installation\n\n```\n$ composer require toflar/psr6-symfony-http-cache-store\n```\n\n## Configuration\n\nFor the Symfony 4/Flex structure, you need to adjust your `index.php` like this:\n\n```php\n\u003c?php\n\n// public/index.php\n$kernel = new Kernel($env, $debug);\n$kernel = new HttpCache(\n    $kernel,\n    new Psr6Store(['cache_directory' =\u003e $kernel-\u003egetCacheDir()]),\n    null,\n    ['debug' =\u003e $debug]\n);\n```\n\nThat's it, that's all there is to do. The `Psr6Store` will automatically\ncreate the best caching and locking adapters available for your local filesystem.\n\nIf you want to go beyond this point, the `Psr6Store` can be configured by\npassing an array of `$options` in the constructor:\n\n* **cache_directory**: Path to the cache directory for the default cache\n  adapter and lock factory.\n\n  Either this or both `cache` and `lock_factory` are required.\n\n  **Type**: `string`\n\n* **cache**: Explicitly specify the cache adapter you want to use.\n\n  Note that if you want to make use of cache tagging, this cache must\n  implement the `Symfony\\Component\\Cache\\Adapter\\TagAwareAdapterInterface`\n  Make sure that `lock` and `cache` have the same scope. *See warning below!*\n\n  **Type**: `Symfony\\Component\\Cache\\Adapter\\AdapterInterface`\n  **Default**: `FilesystemAdapter` instance with `cache_directory`\n\n* **lock_factory**: Explicitly specify the lock factory you want to use. Make\n  sure that lock and cache have the same scope. *See warning below!*\n\n  **Type**: `Symfony\\Component\\Lock\\Factory`\n  **Default**: `Factory` with `SemaphoreStore` if supported, `FlockStore` otherwise\n\n* **prune_threshold**: Configure the number of write actions until the store\n  will prune the expired cache entries. Pass `0` to disable automated pruning.\n\n  **Type**: `int`\n  **Default**: `500`\n\n* **cache_tags_header**: The HTTP header name that's used to check for tags.\n\n  **Type**: `string`\n  **Default**: `Cache-Tags`\n\n* **generate_content_digests**: Whether or not content digests should be generated.\n  See \"Generating Content Digests\" for more information.\n\n  **Type**: `boolean`\n  **Default**: `true`\n  \n### Generating Content Digests\n\nBy default, this cache implementation generates content digests.\nThis means that the response meta data is stored separately from the\nresponse content. If multiple responses share the same content, it\nis stored in the cache only once.\nCompare the following illustrations to see the difference:\n\n**With generating content digests**:\n\n![Illustration of the cache with generating content digests](docs/with_content_digests.svg)\n\n**Without generating content digests**:\n\n![Illustration of the cache without generating content digests](docs/without_content_digests.svg)\n\nGenerating content digests optimizes the cache so it uses up less\nstorage. Using them, however, also comes at the costs of requiring\na second round trip to fetch the content digest from the cache during\nthe lookup process.\n\nWhether or not you want to use content digests depends on your PSR-6\ncache back end. If lookups are fast and storage is rather limited (e.g. Redis),\nyou might want to use content digests. If lookups are rather slow and\nstorage is less of an issue (e.g. Filesystem), you might want to disable\nthem.\n\nYou can control the behaviour using the `generate_content_digests` configuration\noption.\n  \n### Caching `BinaryFileResponse` Instances\n\nThis cache implementation allows to cache `BinaryFileResponse` instances but\nthe files are not actually copied to the cache directory. It will just try to\nfetch the original file and if that does not exist anymore, the store returns\n`null`, causing HttpCache to deal with it as a cache miss and continue normally.\nIt is ideal for use cases such as caching `/favicon.ico` requests where you would\nlike to prevent the application from being started and thus deliver the response\nfrom HttpCache.\n\n### Cache Tagging\n\nTag cache entries by adding a response header with the tags as a comma \nseparated value. By default, that header is called `Cache-Tags`, this can be\noverwritten in `cache_tags_header`.\n\nTo invalidate tags, call the method `Psr6Store::invalidateTags` or use the\n`PurgeTagsListener` from the [FOSHttpCache][3] library to handle tag \ninvalidation requests.\n\n### Pruning Expired Cache Items\n\nBy default, this store removes expired entries from the cache after every `500`\ncache **write** operations. Fetching data does not affect performance.\nYou can change the automated pruning frequency with the `prune_threshold`\nconfiguration setting.\n\nYou can also manually trigger pruning by calling the `prune()` method on the\ncache. With this, you could for example implement a cron job that loads the store\nand prunes it at a configured interval, to prevent slowing down random requests\nthat were cache misses because they have to wait for the pruning to happen. If you\nhave set up a cron job, you should disable auto pruning by setting the threshold\nto `0`.\n\n### WARNING\n\nIt is possible to configure other cache adapters or lock stores than the\nfilesystem ones. Only do this if you are sure of what you are doing. In\n[this pull request][1] Fabien refused to add PSR-6 store support to\nthe Symfony `AppCache` with the following arguments:\n\n* Using a filesystem allows for `opcache` to make the cache very\n  effective;\n* The cache contains some PHP (when using ESI for instance) and storing\n  PHP in anything else than a filesystem would mean `eval()`-ing\n  strings coming from Redis / Memcache /...;\n* HttpCache is triggered very early and does not have access to the\n  container or anything else really. And it should stay that way to be\n  efficient.\n\nWhile the first and third point depend on what you do and need, be sure to\nrespect the second point. If you use network enabled caches like Redis or\nMemcache, make sure that they are not shared with other systems to avoid code\ninjection!\n\n\n### Credits\n\nI would like to thank [David][2] for his invaluable feedback on this library\nwhile we were working on an integration for the awesome [FOSHttpCache][3] library.\n\n[1]: https://github.com/symfony/symfony/pull/20061#issuecomment-313339092\n[2]: https://github.com/dbu\n[3]: https://github.com/FriendsOfSymfony/FOSHttpCache\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoflar%2Fpsr6-symfony-http-cache-store","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftoflar%2Fpsr6-symfony-http-cache-store","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftoflar%2Fpsr6-symfony-http-cache-store/lists"}