{"id":15660475,"url":"https://github.com/bnomei/kirby3-lapse","last_synced_at":"2025-04-13T12:04:31.417Z","repository":{"id":37587761,"uuid":"146878531","full_name":"bnomei/kirby3-lapse","owner":"bnomei","description":"Cache any data until set expiration time","archived":false,"fork":false,"pushed_at":"2024-11-29T20:40:03.000Z","size":307,"stargazers_count":21,"open_issues_count":1,"forks_count":0,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-03T23:07:35.035Z","etag":null,"topics":["automatic","cache","expire","key-value","kirby","kirby-cms","kirby-plugin","kirby4","kirby5","memcached","modified","multi-language-support","performance"],"latest_commit_sha":null,"homepage":"https://forum.getkirby.com/t/kirby3-lapse-cache-any-data-until-set-expiration-time-with-automatic-keys/23586","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/bnomei.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},"funding":{"github":"bnomei","patreon":"bnomei","open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":["https://buymeacoff.ee/bnomei","https://paypal.me/bnomei"]}},"created_at":"2018-08-31T10:38:53.000Z","updated_at":"2025-02-14T11:10:26.000Z","dependencies_parsed_at":"2024-10-03T13:22:06.964Z","dependency_job_id":"4f8ed265-27dc-492d-8bca-252f4ca1d29d","html_url":"https://github.com/bnomei/kirby3-lapse","commit_stats":{"total_commits":87,"total_committers":2,"mean_commits":43.5,"dds":"0.26436781609195403","last_synced_commit":"9d3fc055a2d7ac6956da5fc94ae0849fc4e819c6"},"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fkirby3-lapse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fkirby3-lapse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fkirby3-lapse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bnomei%2Fkirby3-lapse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bnomei","download_url":"https://codeload.github.com/bnomei/kirby3-lapse/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245773172,"owners_count":20669719,"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":["automatic","cache","expire","key-value","kirby","kirby-cms","kirby-plugin","kirby4","kirby5","memcached","modified","multi-language-support","performance"],"created_at":"2024-10-03T13:21:54.948Z","updated_at":"2025-03-29T08:31:31.162Z","avatar_url":"https://github.com/bnomei.png","language":"PHP","funding_links":["https://github.com/sponsors/bnomei","https://patreon.com/bnomei","https://buymeacoff.ee/bnomei","https://paypal.me/bnomei","https://www.buymeacoffee.com/bnomei"],"categories":[],"sub_categories":[],"readme":"# Kirby Lapse\n\n[![Kirby 5](https://flat.badgen.net/badge/Kirby/5?color=ECC748)](https://getkirby.com)\n![PHP 8.2](https://flat.badgen.net/badge/PHP/8.2?color=4E5B93\u0026icon=php\u0026label)\n![Release](https://flat.badgen.net/packagist/v/bnomei/kirby3-lapse?color=ae81ff\u0026icon=github\u0026label)\n![Downloads](https://flat.badgen.net/packagist/dt/bnomei/kirby3-lapse?color=272822\u0026icon=github\u0026label)\n[![Coverage](https://flat.badgen.net/codeclimate/coverage/bnomei/kirby3-lapse?icon=codeclimate\u0026label)](https://codeclimate.com/github/bnomei/kirby3-lapse)\n[![Maintainability](https://flat.badgen.net/codeclimate/maintainability/bnomei/kirby3-lapse?icon=codeclimate\u0026label)](https://codeclimate.com/github/bnomei/kirby3-lapse/issues)\n[![Discord](https://flat.badgen.net/badge/discord/bnomei?color=7289da\u0026icon=discord\u0026label)](https://discordapp.com/users/bnomei)\n[![Buymecoffee](https://flat.badgen.net/badge/icon/donate?icon=buymeacoffee\u0026color=FF813F\u0026label)](https://www.buymeacoffee.com/bnomei)\n\nCache any data until set expiration time (with automatic keys).\n\n## Installation\n\n- unzip [master.zip](https://github.com/bnomei/kirby3-lapse/archive/master.zip) as folder `site/plugins/kirby3-lapse` or\n- `git submodule add https://github.com/bnomei/kirby3-lapse.git site/plugins/kirby3-lapse` or\n- `composer require bnomei/kirby3-lapse`\n\n## Usecase\n\nThe Kirby Pages-Cache can cache the output of Page Templates. It invalidates **all** cache files if any Object in the Panel is changed. This is a good choice if you do not make changes often. But if you do make changes often you need a cache that knows what has been modified and which caches to devalidate and which not. \n\nSometimes you can not cache the complete Page since...\n- it contains a [form](https://github.com/mzur/kirby-uniform) with a csrf hash, \n- you use [content security headers](https://github.com/bnomei/kirby3-security-headers) with nouces,\n- build and cache data for a logicless templating system like [handlebars](https://github.com/bnomei/kirby3-handlebars) or\n- you want to cache data from an external source like an API. \n\nLapse was build to do exactly that: **Cache any data until set expiration time.**\n\n## Usage Examples\n\n### Example 1: get/set\n```php\n$key = hash('xxh3', $page-\u003eurl()); // unique key\n// to delay data creation until need use a callback. do not use a plain array or object.\n$data = function () {\n    return [1, 2, 3];\n};\n$data = lapse($key, $data);\n```\n\n### Example 2: with custom expiration time\n```php\n$key = hash('xxh3', $page-\u003eurl()); // unique key\n$expires = 5; // in minutes. default: 0 aka infinite\n$data = function () {\n    return [1, 2, 3];\n};\n$data = lapse($key, $data, $expires);\n```\n\n### Example 3: page object\n```php\n$data = lapse(hash('xxh3', $page-\u003eurl()), function () use ($kirby, $site, $page) {\n    // create some data\n    return [\n        'author' =\u003e site()-\u003eauthor(),\n        'title' =\u003e $page-\u003etitle(),\n        'text' =\u003e $page-\u003etext()-\u003ekirbytext(),\n        'url' =\u003e $page-\u003eurl(),\n    ];\n});\n```\n\n### Remove by Key\n\n```php\n$key = hash('xxh3', $page-\u003eurl()); // unique key\n$wasRemoved = \\Bnomei\\Lapse::rm($key);\n```\n\n## Static Cache helper - lapseStatic()\n\nSometimes you need to cache things only for the current request like\nwhen [reusing Kirbys Collections](https://forum.getkirby.com/t/remember-this-caching-in-kirby/23705/4#solution-with-a-static-cache-3)\n. The `lapseStatic()`-helper makes things like that a bit easier. The closure to generate the data will only be called\nonce, set its return value to a static cache and every recurring call to the collection will get the cached collection\nback from static memory array.\n\n**site/plugins/example/index.php**\n\n```php\n\u003c?php\n\nKirby::plugin('bnomei/example', [\n  'collections' =\u003e [\n    // collections have to be a closure that is why it is wrapped in a fn\n    'recent-courses' =\u003e fn() =\u003e lapseStatic(\n        'recent-courses', // key \n        function () { // value\n            return page('courses')-\u003echildren()-\u003elisted()-\u003esortBy('name')-\u003elimit(10);\n        }\n    )\n]);\n```\n\n## Clever keys\n\n### Unique but not modified\n\nCaches use a string value as key to store and later retrieve the data. The key is usually a hash of the objects id plus\nsome meta data like the contents language. Storing data related to a Page using the `$key = hash('xxh3', $page-\u003eurl());` will\nwork just fine. It takes care of the language if you use a multi-language setup since the language is included in the\nurl. But it will expire only if you provide a fixed time or devalidate it yourself.\n\n### Modified\n\nThe solution is to include the modification timestamp of every object related to the data. So if you store the result of\na Page Object with Images being rendered you need to include the modification timestamp of all of these. That will cause\nthe creation of a new cache every time your source changes.\n\n#### Basic\n\n```php\n$keys = [ $page-\u003eurl().$page-\u003emodified() ];\nforeach($page-\u003eimages() as $image) {\n    $keys[] = $image-\u003eid().$image-\u003emodified();\n}\n$key = hash('xxh3', implode($keys));\n```\n\n#### Objects\n\nSince version 2 of this plugin you can also forward any of these and the key will be magically created for you.\n\n- Page-Objects, \n- File-Objects and FileVersion-Objects (aka Thumbs), \n- Collections or\n- the Site-Object \n\n\n```php\n$objects = [$page, $page-\u003eimages()];\n$data = lapse($objects, ...)\n```\n\n#### Multi-language support\n\nThe keys created by the plugin are [tagged with the current language](https://github.com/bnomei/kirby3-lapse/blob/master/classes/Lapse.php#L181). You will get a different cache value for each language.\n\n#### BoostID\nIf you use the [Boost plugin](https://github.com/bnomei/kirby3-boost) the modification timestamps will be retrieved at almost zero-cpu-cost and not causing the file to be checked on disk.\n\n\n## FAQ\n\n### Infinite cache duration by default\n\nUnless you set an expiration when using `lapse()` the cache file will never devalidate. This is because the plugin is intended to be used with keys defining the expiration like `$key = hash('xxh3', $page-\u003eid().$page-\u003emodified());`.\n\n```php\n$expires = 5; // in minutes. default: 0 aka infinite\n$data = lapse($key, $data, $expires);\n```\n\nWhen using Memcache or APCu you need to limit the maximum number of caches created since you have a very limited amount if memory of 64MB at default. You can set a limit at `bnomei.lapse.indexLimit` to something like `300`. But be aware that this makes writing to the cache a tiny bit slower since the plugins internal index must be updated.\n\n### No cache when debugging\n\nWhen Kirbys global debug config is set to `true` the **complete** plugin cache will be flushed and no caches will be created. This will make you live easier – trust me.\n\n### Kirby Field-Objects and serialization \n\nThe plugin uses the default Kirby serialization of objects and since memory references are lost anyway all Kirby Field-Objects are stored by calling their `-\u003evalue()` method. The File-Cache uses a json format.\n\n### Migrating from v1 of this plugin\n\n- `$force` param has been removed: use proper keys.\n- all settings have been removed: they are not needed anymore like explained above.\n\n## Performance\n\n### Use crc32 to generate the hash\n\n`xxh3` is the [fastest](https://php.watch/versions/8.1/xxHash) non cryptographic hashing hashing algorithm in PHP 8.1 . The keys for lapse do not need to be encrypted.\n\n### Cache Driver\nFor best performance set the **global** [cache driver](https://getkirby.com/docs/reference/system/options/cache#cache-driver) to one using the servers memory not files on the harddisk (even on SSDs). Memcache or ApcuCache can be activated on most hosting environments but rarely are by default. Also see `bnomei.lapse.indexLimit` setting explained above. My [Redis Cache Driver](https://github.com/bnomei/kirby3-redis-cachedriver) and [SQLite Cache Driver](https://github.com/bnomei/kirby3-sqlite-cachedriver) are faster than other cache drivers and have no memory limit. In all other cases use the very fast [PHP Cache Driver](https://github.com/bnomei/kirby3-php-cachedriver) or APCu.\n\n```php\nreturn [\n  'cache' =\u003e [\n    'driver' =\u003e 'apcu', // php, redis, sqlite\n  ],\n];\n```\n\n## Examples\n\n```php\n// lapse v1 could already do this:\n// store data until objects are modified with optional expire\n$data = lapse(\n    $page-\u003eid().$page-\u003emodified(),\n    ['some', 'kind', 'of', 'data'],\n    60*24*7 // one week\n);\n\n// now it can create magic cache keys from kirby objects\n$data = lapse(\n    $page, // key with modification date created by lapse based on object \n    function () use ($page) {\n        return [\n           'title' =\u003e $page-\u003etitle(),\n       ];\n    }\n);\n\n// or from an collection of pages or files\n$collection = collection('mycollection');\n$data = lapse(\n    $collection, // this will turn into a key taking modification date of all objects into consideration\n    function () use ($collection) {\n        return [ /*...*/ ];\n    }\n);\n\n// or from an array combining all these\n$data = lapse(\n    ['myhash', $page, $page-\u003echildren()-\u003eimages(), $collection, $site], // will create key from array of objects\n    function () use ($site, $page, $collection) {\n        return [\n            // will not break serialization =\u003e automatically store -\u003evalue() of fields\n            'author' =\u003e $site-\u003eauthor(),\n            'title' =\u003e $page-\u003etitle(),\n            'hero' =\u003e $page-\u003echildren()-\u003eimages()-\u003efirst()-\u003esrcset()-\u003ehtml(),\n            'count' =\u003e $collection-\u003ecount(),\n        ];\n    }\n);\n\n// remove by dynamic key\n$wasRemoved = \\Bnomei\\Lapse::rm(\n    ['myhash', $page, $page-\u003echildren()-\u003eimages(), $collection, $site]\n);\n```\n\n\u003e 🏎️ if you use boost the modified lookups will be at almost zero-cpu cost.\n\n## Cancel the caching\n\nIf you want to cancel the caching you can throw the `LapseCancelException` in the closure. This will prevent the caching of the data and return `null`.\n\n```php\n$data = lapse(\n    $page,\n    function () use ($page) {\n        if ($page-\u003eisUnpublished()) {\n            // do not cache unpublished pages\n            throw new \\Bnomei\\LapseCancelException();\n        }\n        return $page-\u003etitle()-\u003evalue();\n    }\n);\n// $data === null for unpublished pages\n```\n\n## Disclaimer\n\nThis plugin is provided \"as is\" with no guarantee. Use it at your own risk and always test it yourself before using it in a production environment. If you find any issues, please [create a new issue](https://github.com/bnomei/kirby3-lapse/issues/new).\n\n## License\n\n[MIT](https://opensource.org/licenses/MIT)\n\nIt is discouraged to use this plugin in any project that promotes racism, sexism, homophobia, animal abuse, violence or any other form of hate speech.\n\n## Credits\n\nbased on V2 version of\n- https://github.com/jenstornell/kirby-time-cache\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbnomei%2Fkirby3-lapse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbnomei%2Fkirby3-lapse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbnomei%2Fkirby3-lapse/lists"}