{"id":15489416,"url":"https://github.com/webfactory/webfactoryhttpcachebundle","last_synced_at":"2026-04-02T11:56:45.653Z","repository":{"id":30157452,"uuid":"124102111","full_name":"webfactory/WebfactoryHttpCacheBundle","owner":"webfactory","description":"Symfony bundle to ease HTTP cache validation via last modified header","archived":false,"fork":false,"pushed_at":"2025-07-31T13:49:41.000Z","size":61,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-07-31T17:24:01.758Z","etag":null,"topics":["bundle","cache","caching","http-cache-bundle","httpcache","php","symfony"],"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/webfactory.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,"zenodo":null}},"created_at":"2018-03-06T15:56:06.000Z","updated_at":"2025-07-31T13:49:20.000Z","dependencies_parsed_at":"2024-03-28T18:35:07.087Z","dependency_job_id":"4a2d990e-5045-4d78-98b1-46f7cbde3315","html_url":"https://github.com/webfactory/WebfactoryHttpCacheBundle","commit_stats":{"total_commits":22,"total_committers":5,"mean_commits":4.4,"dds":0.5454545454545454,"last_synced_commit":"5a7a185dc94f2ab086fa42285a78060e85daa091"},"previous_names":[],"tags_count":10,"template":false,"template_full_name":null,"purl":"pkg:github/webfactory/WebfactoryHttpCacheBundle","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryHttpCacheBundle","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryHttpCacheBundle/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryHttpCacheBundle/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryHttpCacheBundle/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/webfactory","download_url":"https://codeload.github.com/webfactory/WebfactoryHttpCacheBundle/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/webfactory%2FWebfactoryHttpCacheBundle/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":270235590,"owners_count":24550186,"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","status":"online","status_checked_at":"2025-08-13T02:00:09.904Z","response_time":66,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["bundle","cache","caching","http-cache-bundle","httpcache","php","symfony"],"created_at":"2024-10-02T07:05:35.695Z","updated_at":"2026-04-02T11:56:45.648Z","avatar_url":"https://github.com/webfactory.png","language":"PHP","readme":"# WebfactoryHttpCacheBundle\n\n`WebfactoryHttpCacheBundle` is a Symfony bundle that features a more\npowerful [HTTP cache validation via the last modified header] than the\n`#[Cache]` attribute contained in the [symfony/http-kernel package].\n\n[HTTP cache validation via the last modified header]: https://symfony.com/doc/current/http_cache/validation.html#validation-with-the-last-modified-header\n[symfony/http-kernel package]: https://symfony.com/doc/current/http_cache.html#http-cache-expiration-intro\n\nThe `#[ReplaceWithNotModifiedResponse]` attribute lets you write small \n`LastModifiedDeterminators` for each one of the underlying resources \nof the requested page. They can be reused and combined freely and can \neven be defined as services.\n\nConsider this controller code:\n\n```php\n\u003c?php\n\n// ...\nuse Webfactory\\HttpCacheBundle\\NotModified\\Attribute\\ReplaceWithNotModifiedResponse;\n\nclass MyController {\n    // Routing etc. configuration skipped for brevity\n     \n    #[ReplaceWithNotModifiedResponse([\"@app_caching_post\", \"@app_caching_latest_posts\"])]\n    public function indexAction(Post $post): Response\n    {\n        // your code\n        // won't be called in case of a 304\n    }\n}\n```\n\nWhen Symfony's routing has chosen this controller action, all of the\n`LastModifiedDeterminator`s are called to return their respective last\nmodified date.\n\nIn this case, both LastModifiedDeterminators are configured as services:\n`@app_caching_post` and `@app_caching_latest_posts`. The first\none returns the update date of the requests `$post`, the second one may\nuse the PostRepository injected from the DI container to return the last\nupdate date of the x latest posts.\n\n`#[ReplaceWithNotModifiedResponse]` combines all of the\n`LastModifiedDeterminators` dates to determine to last modified date of\nthe overall page. Finally, if the request contains an appropriate\n`if-not-modified-since` header, the execution of the controller\naction will be skipped and an empty response with a \"304 Not Modified\"\nstatus code will be sent. If your `LastModifiedDeterminators` are fast,\nthis can improve your performance greatly.\n\nWhat we like about the `LastModifiedDeterminators` is that they encourage\nto separate the concerns nicely and encapsulate the tasks into small\nunits that are easy to understand, reusable and unit test.\n   \n*Note:* `#[ReplaceWithNotModifiedResponse]` does not alter or add\n`Cache-Control` header settings. So, by default your response will\nremain `private` and end up in browser caches only. If you want it to be\nkept in surrogate caches (like Varnish or the Symfony Http Cache), you\ncan add `#[Cache(smaxage: 0)]`. This will make the response `public`, but\nalso requires a revalidation on every request as the response is\n*always* considered stale. [Learn more about Symonfy's HTTP caching].\n\n[Learn more about Symonfy's HTTP caching]: http://symfony.com/doc/current/book/http_cache.html\n\n## Installation\n\n```\ncomposer require webfactory/http-cache-bundle\n```\n\nand add to your `bundles.php`:\n\n```\nWebfactory\\HttpCacheBundle\\WebfactoryHttpCacheBundle::class =\u003e ['all' =\u003e true],\n```\n\n## Usage\n\nChoose a controller action you want to possibly replace with a 304 Not Modified response. Write one LastModifiedDeterminator for each\nof the different underlying resources, implementing the `Webfactory\\HttpCacheBundle\\NotModified\\LastModifiedDeterminator` interface.\n\n```php\n\u003c?php\n// src/Caching/PostsLastModifiedDeterminator.php\nnamespace App\\Caching;\n\nuse App\\Entity\\PostRepository;\nuse Symfony\\Component\\HttpFoundation\\Request;\nuse Webfactory\\HttpCacheBundle\\NotModified\\LastModifiedDeterminator;\n\n/**\n * Returns the publishing date of the latest posts.\n */\nfinal class PostsLastModifiedDeterminator implements LastModifiedDeterminator\n{\n    public function __construct(\n        private readonly BlogPostRepository $blogPostRepository,\n    ) {\n    \n    public function getLastModified(Request $request): ?\\DateTimeInterface\n    {\n        $post = $this-\u003eblogPostRepository-\u003efindLatest();\n        \n        return $post?-\u003egetPublishingDate();\n    }\n}\n```\n\nYou can use the `$request` in the getLastModified e.g. to get route parameters, which is necessary e.g. if you have\nsome filters coded in the requested URL.\n\nIf your LastModifiedDeterminator has dependencies you'd like to be injected, configure it as a service.\n\nThen, add the `#[ReplaceWithNotModifiedResponse]` attribute to the chosen controller method and parameterize it\nwith your LastModifiedDeterminators:\n\n```php\n\u003c?php\n\nnamespace src\\Controller;\n\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Webfactory\\HttpCacheBundle\\NotModified\\Attribute\\ReplaceWithNotModifiedResponse;\n\nfinal class MyController\n{\n     #[ReplaceWithNotModifiedResponse([...])]\n    public function indexAction()\n    {\n        // ...\n        return new Response(...);\n    }\n}\n```\n\nThe most simple form of adding a LastModifiedDeterminator is passing its fully qualfified class name:\n\n    #[ReplaceWithNotModifiedResponse([\\App\\Caching\\MySimpleLastModifiedDeterminator::class])]\n\nIf your LastModifiedDeterminator needs simple constructor arguments, you can pass them in array form:\n\n    #[ReplaceWithNotModifiedResponse([\\App\\Caching\\MyLastModifiedDeterminator::class =\u003e [\"key1\" =\u003e 1, \"key2\" =\u003e [\"*\"]]])]\n\nThis would pass the array ['key1' =\u003e 1, 'key2' =\u003e ['*']] as an argument to MyLastModifiedDeterminator's constructor.\n\nIf your LastModifiedDeterminator has more sophisticated dependencies, you can define the LastModifiedDeterminator as a service, e.g.:\n\n`yaml\n// services.yml\nservices:\n    app_caching_latest_posts:\n        class: App\\Caching\\PostsLastModifiedDeterminator\n        arguments:\n            - @repository_post\n`\n\nand put the service name into the attribute:\n\n    #[ReplaceWithNotModifiedResponse([\"@app_caching_latest_posts\"])]\n\nTo combine multiple LastModifiedDeterminators, simply add all of them to the attribute:\n \n    #[ReplaceWithNotModifiedResponse([\n        \"@app_caching_latest_posts\",\n        \\App\\Caching\\MySimpleLastModifiedDeterminator::class,\n        [\\App\\Caching\\MyLastModifiedDeterminator::class =\u003e [\"key1\" = 1, \"key2\" =\u003e [\"*\"]]\n    ])]\n \nThe latest last modified date determines the last modified date of the response.\n\n## Credits, Copyright and License\n\nThis bundle was started at webfactory GmbH, Bonn.\n\n- \u003chttps://www.webfactory.de\u003e\n\nCopyright 2018-2025 webfactory GmbH, Bonn. Code released under [the MIT license](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebfactory%2Fwebfactoryhttpcachebundle","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwebfactory%2Fwebfactoryhttpcachebundle","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwebfactory%2Fwebfactoryhttpcachebundle/lists"}