3 <html lang=
"en" class=
"no-js">
7 <meta name=
"viewport" content=
"width=device-width,initial-scale=1">
12 <link rel=
"icon" href=
"../../../assets/default.favicon.ico">
13 <meta name=
"generator" content=
"mkdocs-1.1.2, mkdocs-material-7.1.0">
17 <title>Overview - WoltLab Suite Documentation
</title>
21 <link rel=
"stylesheet" href=
"../../../assets/stylesheets/main.33e2939f.min.css">
24 <link rel=
"stylesheet" href=
"../../../assets/stylesheets/palette.ef6f36e2.min.css">
28 <meta name=
"theme-color" content=
"#009485">
38 <link rel=
"stylesheet" href=
"../../../stylesheets/extra.css">
52 <body dir=
"ltr" data-md-color-scheme=
"" data-md-color-primary=
"teal" data-md-color-accent=
"">
55 <script>function __prefix(e){return new URL(
"../../..",location).pathname+
"."+e}function __get(e,t=localStorage){return JSON.parse(t.getItem(__prefix(e)))}
</script>
57 <input class=
"md-toggle" data-md-toggle=
"drawer" type=
"checkbox" id=
"__drawer" autocomplete=
"off">
58 <input class=
"md-toggle" data-md-toggle=
"search" type=
"checkbox" id=
"__search" autocomplete=
"off">
59 <label class=
"md-overlay" for=
"__drawer"></label>
60 <div data-md-component=
"skip">
63 <a href=
"#caches" class=
"md-skip">
68 <div data-md-component=
"announce">
70 <aside class=
"md-announce">
71 <div class=
"md-announce__inner md-grid md-typeset">
73 <a href=
"https://www.woltlab.com">Back to
<strong>woltlab.com
</strong></a>
80 <header class=
"md-header" data-md-component=
"header">
81 <nav class=
"md-header__inner md-grid" aria-label=
"Header">
82 <a href=
"../../.." title=
"WoltLab Suite Documentation" class=
"md-header__button md-logo" aria-label=
"WoltLab Suite Documentation" data-md-component=
"logo">
84 <img src=
"../../../assets/logo.png" alt=
"logo">
87 <label class=
"md-header__button md-icon" for=
"__drawer">
88 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M3 6h18v2H3V6m0 5h18v2H3v-2m0 5h18v2H3v-2z"/></svg>
90 <div class=
"md-header__title" data-md-component=
"header-title">
91 <div class=
"md-header__ellipsis">
92 <div class=
"md-header__topic">
93 <span class=
"md-ellipsis">
94 WoltLab Suite Documentation
97 <div class=
"md-header__topic" data-md-component=
"header-topic">
98 <span class=
"md-ellipsis">
109 <label class=
"md-header__button md-icon" for=
"__search">
110 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
113 <div class=
"md-search" data-md-component=
"search" role=
"dialog">
114 <label class=
"md-search__overlay" for=
"__search"></label>
115 <div class=
"md-search__inner" role=
"search">
116 <form class=
"md-search__form" name=
"search">
117 <input type=
"text" class=
"md-search__input" name=
"query" aria-label=
"Search" placeholder=
"Search" autocapitalize=
"off" autocorrect=
"off" autocomplete=
"off" spellcheck=
"false" data-md-component=
"search-query" data-md-state=
"active" required
>
118 <label class=
"md-search__icon md-icon" for=
"__search">
119 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5z"/></svg>
120 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
122 <button type=
"reset" class=
"md-search__icon md-icon" aria-label=
"Clear" tabindex=
"-1">
123 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41z"/></svg>
126 <div class=
"md-search__output">
127 <div class=
"md-search__scrollwrap" data-md-scrollfix
>
128 <div class=
"md-search-result" data-md-component=
"search-result">
129 <div class=
"md-search-result__meta">
132 <ol class=
"md-search-result__list"></ol>
140 <div class=
"md-header__source">
142 <a href=
"https://github.com/WoltLab/docs.woltlab.com/" title=
"Go to repository" class=
"md-source" data-md-component=
"source">
143 <div class=
"md-source__icon md-icon">
145 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 448 512"><path d=
"M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
147 <div class=
"md-source__repository">
156 <div class=
"md-container" data-md-component=
"container">
161 <main class=
"md-main" data-md-component=
"main">
162 <div class=
"md-main__inner md-grid">
166 <div class=
"md-sidebar md-sidebar--primary" data-md-component=
"sidebar" data-md-type=
"navigation" >
167 <div class=
"md-sidebar__scrollwrap">
168 <div class=
"md-sidebar__inner">
172 <nav class=
"md-nav md-nav--primary" aria-label=
"Navigation" data-md-level=
"0">
173 <label class=
"md-nav__title" for=
"__drawer">
174 <a href=
"../../.." title=
"WoltLab Suite Documentation" class=
"md-nav__button md-logo" aria-label=
"WoltLab Suite Documentation" data-md-component=
"logo">
176 <img src=
"../../../assets/logo.png" alt=
"logo">
179 WoltLab Suite Documentation
182 <div class=
"md-nav__source">
184 <a href=
"https://github.com/WoltLab/docs.woltlab.com/" title=
"Go to repository" class=
"md-source" data-md-component=
"source">
185 <div class=
"md-source__icon md-icon">
187 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 448 512"><path d=
"M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
189 <div class=
"md-source__repository">
195 <ul class=
"md-nav__list" data-md-scrollfix
>
204 <li class=
"md-nav__item">
205 <a href=
"../../../getting-started/" class=
"md-nav__link">
222 <li class=
"md-nav__item md-nav__item--active md-nav__item--nested">
225 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2" type=
"checkbox" id=
"__nav_2" checked
>
227 <label class=
"md-nav__link" for=
"__nav_2">
229 <span class=
"md-nav__icon md-icon"></span>
231 <nav class=
"md-nav" aria-label=
"PHP API" data-md-level=
"1">
232 <label class=
"md-nav__title" for=
"__nav_2">
233 <span class=
"md-nav__icon md-icon"></span>
236 <ul class=
"md-nav__list" data-md-scrollfix
>
242 <li class=
"md-nav__item">
243 <a href=
"../../pages/" class=
"md-nav__link">
254 <li class=
"md-nav__item">
255 <a href=
"../../database-objects/" class=
"md-nav__link">
266 <li class=
"md-nav__item">
267 <a href=
"../../database-access/" class=
"md-nav__link">
278 <li class=
"md-nav__item">
279 <a href=
"../../exceptions/" class=
"md-nav__link">
293 <li class=
"md-nav__item md-nav__item--active md-nav__item--nested">
296 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5" type=
"checkbox" id=
"__nav_2_5" checked
>
298 <label class=
"md-nav__link" for=
"__nav_2_5">
300 <span class=
"md-nav__icon md-icon"></span>
302 <nav class=
"md-nav" aria-label=
"API" data-md-level=
"2">
303 <label class=
"md-nav__title" for=
"__nav_2_5">
304 <span class=
"md-nav__icon md-icon"></span>
307 <ul class=
"md-nav__list" data-md-scrollfix
>
316 <li class=
"md-nav__item md-nav__item--active md-nav__item--nested">
319 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5_1" type=
"checkbox" id=
"__nav_2_5_1" checked
>
321 <label class=
"md-nav__link" for=
"__nav_2_5_1">
323 <span class=
"md-nav__icon md-icon"></span>
325 <nav class=
"md-nav" aria-label=
"Caches" data-md-level=
"3">
326 <label class=
"md-nav__title" for=
"__nav_2_5_1">
327 <span class=
"md-nav__icon md-icon"></span>
330 <ul class=
"md-nav__list" data-md-scrollfix
>
338 <li class=
"md-nav__item md-nav__item--active">
340 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"toc" type=
"checkbox" id=
"__toc">
345 <label class=
"md-nav__link md-nav__link--active" for=
"__toc">
347 <span class=
"md-nav__icon md-icon"></span>
350 <a href=
"./" class=
"md-nav__link md-nav__link--active">
355 <nav class=
"md-nav md-nav--secondary" aria-label=
"Table of contents">
361 <label class=
"md-nav__title" for=
"__toc">
362 <span class=
"md-nav__icon md-icon"></span>
365 <ul class=
"md-nav__list" data-md-component=
"toc" data-md-scrollfix
>
367 <li class=
"md-nav__item">
368 <a href=
"#understanding-caching" class=
"md-nav__link">
369 Understanding Caching
372 <nav class=
"md-nav" aria-label=
"Understanding Caching">
373 <ul class=
"md-nav__list">
375 <li class=
"md-nav__item">
376 <a href=
"#when-to-use-a-cache" class=
"md-nav__link">
382 <li class=
"md-nav__item">
383 <a href=
"#when-not-to-use-a-cache" class=
"md-nav__link">
384 When not to Use a Cache
406 <li class=
"md-nav__item">
407 <a href=
"../caches_persistent-caches/" class=
"md-nav__link">
418 <li class=
"md-nav__item">
419 <a href=
"../caches_runtime-caches/" class=
"md-nav__link">
436 <li class=
"md-nav__item">
437 <a href=
"../comments/" class=
"md-nav__link">
448 <li class=
"md-nav__item">
449 <a href=
"../cronjobs/" class=
"md-nav__link">
460 <li class=
"md-nav__item">
461 <a href=
"../events/" class=
"md-nav__link">
473 <li class=
"md-nav__item md-nav__item--nested">
476 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5_5" type=
"checkbox" id=
"__nav_2_5_5" >
478 <label class=
"md-nav__link" for=
"__nav_2_5_5">
480 <span class=
"md-nav__icon md-icon"></span>
482 <nav class=
"md-nav" aria-label=
"Form Builder" data-md-level=
"3">
483 <label class=
"md-nav__title" for=
"__nav_2_5_5">
484 <span class=
"md-nav__icon md-icon"></span>
487 <ul class=
"md-nav__list" data-md-scrollfix
>
493 <li class=
"md-nav__item">
494 <a href=
"../form_builder/overview/" class=
"md-nav__link">
505 <li class=
"md-nav__item">
506 <a href=
"../form_builder/structure/" class=
"md-nav__link">
517 <li class=
"md-nav__item">
518 <a href=
"../form_builder/form_fields/" class=
"md-nav__link">
529 <li class=
"md-nav__item">
530 <a href=
"../form_builder/validation_data/" class=
"md-nav__link">
541 <li class=
"md-nav__item">
542 <a href=
"../form_builder/dependencies/" class=
"md-nav__link">
559 <li class=
"md-nav__item">
560 <a href=
"../package_installation_plugins/" class=
"md-nav__link">
561 Package Installation Plugins
571 <li class=
"md-nav__item">
572 <a href=
"../user_activity_points/" class=
"md-nav__link">
583 <li class=
"md-nav__item">
584 <a href=
"../user_notifications/" class=
"md-nav__link">
595 <li class=
"md-nav__item">
596 <a href=
"../sitemaps/" class=
"md-nav__link">
613 <li class=
"md-nav__item">
614 <a href=
"../../code-style/" class=
"md-nav__link">
625 <li class=
"md-nav__item">
626 <a href=
"../../apps/" class=
"md-nav__link">
637 <li class=
"md-nav__item">
638 <a href=
"../../gdpr/" class=
"md-nav__link">
659 <li class=
"md-nav__item md-nav__item--nested">
662 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_3" type=
"checkbox" id=
"__nav_3" >
664 <label class=
"md-nav__link" for=
"__nav_3">
665 Languages, Templates & CSS
666 <span class=
"md-nav__icon md-icon"></span>
668 <nav class=
"md-nav" aria-label=
"Languages, Templates & CSS" data-md-level=
"1">
669 <label class=
"md-nav__title" for=
"__nav_3">
670 <span class=
"md-nav__icon md-icon"></span>
671 Languages, Templates & CSS
673 <ul class=
"md-nav__list" data-md-scrollfix
>
679 <li class=
"md-nav__item">
680 <a href=
"../../../view/languages/" class=
"md-nav__link">
691 <li class=
"md-nav__item">
692 <a href=
"../../../view/templates/" class=
"md-nav__link">
703 <li class=
"md-nav__item">
704 <a href=
"../../../view/template-plugins/" class=
"md-nav__link">
715 <li class=
"md-nav__item">
716 <a href=
"../../../view/css/" class=
"md-nav__link">
737 <li class=
"md-nav__item md-nav__item--nested">
740 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_4" type=
"checkbox" id=
"__nav_4" >
742 <label class=
"md-nav__link" for=
"__nav_4">
743 TypeScript and JavaScript API
744 <span class=
"md-nav__icon md-icon"></span>
746 <nav class=
"md-nav" aria-label=
"TypeScript and JavaScript API" data-md-level=
"1">
747 <label class=
"md-nav__title" for=
"__nav_4">
748 <span class=
"md-nav__icon md-icon"></span>
749 TypeScript and JavaScript API
751 <ul class=
"md-nav__list" data-md-scrollfix
>
757 <li class=
"md-nav__item">
758 <a href=
"../../../javascript/general-usage/" class=
"md-nav__link">
769 <li class=
"md-nav__item">
770 <a href=
"../../../javascript/typescript/" class=
"md-nav__link">
782 <li class=
"md-nav__item md-nav__item--nested">
785 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_4_3" type=
"checkbox" id=
"__nav_4_3" >
787 <label class=
"md-nav__link" for=
"__nav_4_3">
789 <span class=
"md-nav__icon md-icon"></span>
791 <nav class=
"md-nav" aria-label=
"New API" data-md-level=
"2">
792 <label class=
"md-nav__title" for=
"__nav_4_3">
793 <span class=
"md-nav__icon md-icon"></span>
796 <ul class=
"md-nav__list" data-md-scrollfix
>
802 <li class=
"md-nav__item">
803 <a href=
"../../../javascript/new-api_writing-a-module/" class=
"md-nav__link">
814 <li class=
"md-nav__item">
815 <a href=
"../../../javascript/new-api_data-structures/" class=
"md-nav__link">
826 <li class=
"md-nav__item">
827 <a href=
"../../../javascript/new-api_core/" class=
"md-nav__link">
838 <li class=
"md-nav__item">
839 <a href=
"../../../javascript/new-api_dom/" class=
"md-nav__link">
850 <li class=
"md-nav__item">
851 <a href=
"../../../javascript/new-api_events/" class=
"md-nav__link">
862 <li class=
"md-nav__item">
863 <a href=
"../../../javascript/new-api_ajax/" class=
"md-nav__link">
874 <li class=
"md-nav__item">
875 <a href=
"../../../javascript/new-api_dialogs/" class=
"md-nav__link">
886 <li class=
"md-nav__item">
887 <a href=
"../../../javascript/new-api_browser/" class=
"md-nav__link">
888 Browser and Screen Sizes
898 <li class=
"md-nav__item">
899 <a href=
"../../../javascript/new-api_ui/" class=
"md-nav__link">
916 <li class=
"md-nav__item">
917 <a href=
"../../../javascript/legacy-api/" class=
"md-nav__link">
928 <li class=
"md-nav__item">
929 <a href=
"../../../javascript/helper-functions/" class=
"md-nav__link">
940 <li class=
"md-nav__item">
941 <a href=
"../../../javascript/code-snippets/" class=
"md-nav__link">
962 <li class=
"md-nav__item md-nav__item--nested">
965 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_5" type=
"checkbox" id=
"__nav_5" >
967 <label class=
"md-nav__link" for=
"__nav_5">
969 <span class=
"md-nav__icon md-icon"></span>
971 <nav class=
"md-nav" aria-label=
"Package Components" data-md-level=
"1">
972 <label class=
"md-nav__title" for=
"__nav_5">
973 <span class=
"md-nav__icon md-icon"></span>
976 <ul class=
"md-nav__list" data-md-scrollfix
>
982 <li class=
"md-nav__item">
983 <a href=
"../../../package/package-xml/" class=
"md-nav__link">
995 <li class=
"md-nav__item md-nav__item--nested">
998 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_5_2" type=
"checkbox" id=
"__nav_5_2" >
1000 <label class=
"md-nav__link" for=
"__nav_5_2">
1002 <span class=
"md-nav__icon md-icon"></span>
1004 <nav class=
"md-nav" aria-label=
"PIPs" data-md-level=
"2">
1005 <label class=
"md-nav__title" for=
"__nav_5_2">
1006 <span class=
"md-nav__icon md-icon"></span>
1009 <ul class=
"md-nav__list" data-md-scrollfix
>
1015 <li class=
"md-nav__item">
1016 <a href=
"../../../package/pip/" class=
"md-nav__link">
1027 <li class=
"md-nav__item">
1028 <a href=
"../../../package/pip/acl-option/" class=
"md-nav__link">
1039 <li class=
"md-nav__item">
1040 <a href=
"../../../package/pip/acp-menu/" class=
"md-nav__link">
1051 <li class=
"md-nav__item">
1052 <a href=
"../../../package/pip/acp-search-provider/" class=
"md-nav__link">
1063 <li class=
"md-nav__item">
1064 <a href=
"../../../package/pip/acp-template/" class=
"md-nav__link">
1075 <li class=
"md-nav__item">
1076 <a href=
"../../../package/pip/bbcode/" class=
"md-nav__link">
1087 <li class=
"md-nav__item">
1088 <a href=
"../../../package/pip/box/" class=
"md-nav__link">
1099 <li class=
"md-nav__item">
1100 <a href=
"../../../package/pip/clipboard-action/" class=
"md-nav__link">
1111 <li class=
"md-nav__item">
1112 <a href=
"../../../package/pip/core-object/" class=
"md-nav__link">
1123 <li class=
"md-nav__item">
1124 <a href=
"../../../package/pip/cronjob/" class=
"md-nav__link">
1135 <li class=
"md-nav__item">
1136 <a href=
"../../../package/pip/database/" class=
"md-nav__link">
1147 <li class=
"md-nav__item">
1148 <a href=
"../../../package/pip/event-listener/" class=
"md-nav__link">
1159 <li class=
"md-nav__item">
1160 <a href=
"../../../package/pip/file/" class=
"md-nav__link">
1171 <li class=
"md-nav__item">
1172 <a href=
"../../../package/pip/language/" class=
"md-nav__link">
1183 <li class=
"md-nav__item">
1184 <a href=
"../../../package/pip/media-provider/" class=
"md-nav__link">
1195 <li class=
"md-nav__item">
1196 <a href=
"../../../package/pip/menu/" class=
"md-nav__link">
1207 <li class=
"md-nav__item">
1208 <a href=
"../../../package/pip/menu-item/" class=
"md-nav__link">
1219 <li class=
"md-nav__item">
1220 <a href=
"../../../package/pip/object-type/" class=
"md-nav__link">
1231 <li class=
"md-nav__item">
1232 <a href=
"../../../package/pip/object-type-definition/" class=
"md-nav__link">
1233 objectTypeDefinition
1243 <li class=
"md-nav__item">
1244 <a href=
"../../../package/pip/option/" class=
"md-nav__link">
1255 <li class=
"md-nav__item">
1256 <a href=
"../../../package/pip/page/" class=
"md-nav__link">
1267 <li class=
"md-nav__item">
1268 <a href=
"../../../package/pip/pip/" class=
"md-nav__link">
1279 <li class=
"md-nav__item">
1280 <a href=
"../../../package/pip/script/" class=
"md-nav__link">
1291 <li class=
"md-nav__item">
1292 <a href=
"../../../package/pip/smiley/" class=
"md-nav__link">
1303 <li class=
"md-nav__item">
1304 <a href=
"../../../package/pip/sql/" class=
"md-nav__link">
1315 <li class=
"md-nav__item">
1316 <a href=
"../../../package/pip/style/" class=
"md-nav__link">
1327 <li class=
"md-nav__item">
1328 <a href=
"../../../package/pip/template/" class=
"md-nav__link">
1339 <li class=
"md-nav__item">
1340 <a href=
"../../../package/pip/template-listener/" class=
"md-nav__link">
1351 <li class=
"md-nav__item">
1352 <a href=
"../../../package/pip/user-group-option/" class=
"md-nav__link">
1363 <li class=
"md-nav__item">
1364 <a href=
"../../../package/pip/user-menu/" class=
"md-nav__link">
1375 <li class=
"md-nav__item">
1376 <a href=
"../../../package/pip/user-notification-event/" class=
"md-nav__link">
1377 userNotificationEvent
1387 <li class=
"md-nav__item">
1388 <a href=
"../../../package/pip/user-option/" class=
"md-nav__link">
1399 <li class=
"md-nav__item">
1400 <a href=
"../../../package/pip/user-profile-menu/" class=
"md-nav__link">
1417 <li class=
"md-nav__item">
1418 <a href=
"../../../package/database-php-api/" class=
"md-nav__link">
1439 <li class=
"md-nav__item md-nav__item--nested">
1442 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6" type=
"checkbox" id=
"__nav_6" >
1444 <label class=
"md-nav__link" for=
"__nav_6">
1446 <span class=
"md-nav__icon md-icon"></span>
1448 <nav class=
"md-nav" aria-label=
"Migration" data-md-level=
"1">
1449 <label class=
"md-nav__title" for=
"__nav_6">
1450 <span class=
"md-nav__icon md-icon"></span>
1453 <ul class=
"md-nav__list" data-md-scrollfix
>
1460 <li class=
"md-nav__item md-nav__item--nested">
1463 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_1" type=
"checkbox" id=
"__nav_6_1" >
1465 <label class=
"md-nav__link" for=
"__nav_6_1">
1466 Migrating from WSC
5.3
1467 <span class=
"md-nav__icon md-icon"></span>
1469 <nav class=
"md-nav" aria-label=
"Migrating from WSC 5.3" data-md-level=
"2">
1470 <label class=
"md-nav__title" for=
"__nav_6_1">
1471 <span class=
"md-nav__icon md-icon"></span>
1472 Migrating from WSC
5.3
1474 <ul class=
"md-nav__list" data-md-scrollfix
>
1480 <li class=
"md-nav__item">
1481 <a href=
"../../../migration/wsc53/php/" class=
"md-nav__link">
1492 <li class=
"md-nav__item">
1493 <a href=
"../../../migration/wsc53/session/" class=
"md-nav__link">
1494 Session Handling and Authentication
1504 <li class=
"md-nav__item">
1505 <a href=
"../../../migration/wsc53/javascript/" class=
"md-nav__link">
1506 TypeScript and JavaScript
1516 <li class=
"md-nav__item">
1517 <a href=
"../../../migration/wsc53/templates/" class=
"md-nav__link">
1528 <li class=
"md-nav__item">
1529 <a href=
"../../../migration/wsc53/libraries/" class=
"md-nav__link">
1530 Third Party Libraries
1547 <li class=
"md-nav__item md-nav__item--nested">
1550 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_2" type=
"checkbox" id=
"__nav_6_2" >
1552 <label class=
"md-nav__link" for=
"__nav_6_2">
1553 Migrating from WSC
5.2
1554 <span class=
"md-nav__icon md-icon"></span>
1556 <nav class=
"md-nav" aria-label=
"Migrating from WSC 5.2" data-md-level=
"2">
1557 <label class=
"md-nav__title" for=
"__nav_6_2">
1558 <span class=
"md-nav__icon md-icon"></span>
1559 Migrating from WSC
5.2
1561 <ul class=
"md-nav__list" data-md-scrollfix
>
1567 <li class=
"md-nav__item">
1568 <a href=
"../../../migration/wsc52/php/" class=
"md-nav__link">
1579 <li class=
"md-nav__item">
1580 <a href=
"../../../migration/wsc52/templates/" class=
"md-nav__link">
1581 Templates and Languages
1591 <li class=
"md-nav__item">
1592 <a href=
"../../../migration/wsc52/libraries/" class=
"md-nav__link">
1593 Third Party Libraries
1610 <li class=
"md-nav__item md-nav__item--nested">
1613 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_3" type=
"checkbox" id=
"__nav_6_3" >
1615 <label class=
"md-nav__link" for=
"__nav_6_3">
1616 Migrating from WSC
3.1
1617 <span class=
"md-nav__icon md-icon"></span>
1619 <nav class=
"md-nav" aria-label=
"Migrating from WSC 3.1" data-md-level=
"2">
1620 <label class=
"md-nav__title" for=
"__nav_6_3">
1621 <span class=
"md-nav__icon md-icon"></span>
1622 Migrating from WSC
3.1
1624 <ul class=
"md-nav__list" data-md-scrollfix
>
1630 <li class=
"md-nav__item">
1631 <a href=
"../../../migration/wsc31/php/" class=
"md-nav__link">
1649 <li class=
"md-nav__item md-nav__item--nested">
1652 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_4" type=
"checkbox" id=
"__nav_6_4" >
1654 <label class=
"md-nav__link" for=
"__nav_6_4">
1655 Migrating from WSC
3.0
1656 <span class=
"md-nav__icon md-icon"></span>
1658 <nav class=
"md-nav" aria-label=
"Migrating from WSC 3.0" data-md-level=
"2">
1659 <label class=
"md-nav__title" for=
"__nav_6_4">
1660 <span class=
"md-nav__icon md-icon"></span>
1661 Migrating from WSC
3.0
1663 <ul class=
"md-nav__list" data-md-scrollfix
>
1669 <li class=
"md-nav__item">
1670 <a href=
"../../../migration/wsc30/php/" class=
"md-nav__link">
1681 <li class=
"md-nav__item">
1682 <a href=
"../../../migration/wsc30/javascript/" class=
"md-nav__link">
1693 <li class=
"md-nav__item">
1694 <a href=
"../../../migration/wsc30/templates/" class=
"md-nav__link">
1705 <li class=
"md-nav__item">
1706 <a href=
"../../../migration/wsc30/css/" class=
"md-nav__link">
1717 <li class=
"md-nav__item">
1718 <a href=
"../../../migration/wsc30/package/" class=
"md-nav__link">
1736 <li class=
"md-nav__item md-nav__item--nested">
1739 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_5" type=
"checkbox" id=
"__nav_6_5" >
1741 <label class=
"md-nav__link" for=
"__nav_6_5">
1742 Migrating from WCF
2.1
1743 <span class=
"md-nav__icon md-icon"></span>
1745 <nav class=
"md-nav" aria-label=
"Migrating from WCF 2.1" data-md-level=
"2">
1746 <label class=
"md-nav__title" for=
"__nav_6_5">
1747 <span class=
"md-nav__icon md-icon"></span>
1748 Migrating from WCF
2.1
1750 <ul class=
"md-nav__list" data-md-scrollfix
>
1756 <li class=
"md-nav__item">
1757 <a href=
"../../../migration/wcf21/php/" class=
"md-nav__link">
1768 <li class=
"md-nav__item">
1769 <a href=
"../../../migration/wcf21/templates/" class=
"md-nav__link">
1780 <li class=
"md-nav__item">
1781 <a href=
"../../../migration/wcf21/css/" class=
"md-nav__link">
1792 <li class=
"md-nav__item">
1793 <a href=
"../../../migration/wcf21/package/" class=
"md-nav__link">
1820 <li class=
"md-nav__item md-nav__item--nested">
1823 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_7" type=
"checkbox" id=
"__nav_7" >
1825 <label class=
"md-nav__link" for=
"__nav_7">
1827 <span class=
"md-nav__icon md-icon"></span>
1829 <nav class=
"md-nav" aria-label=
"Tutorials" data-md-level=
"1">
1830 <label class=
"md-nav__title" for=
"__nav_7">
1831 <span class=
"md-nav__icon md-icon"></span>
1834 <ul class=
"md-nav__list" data-md-scrollfix
>
1841 <li class=
"md-nav__item md-nav__item--nested">
1844 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_7_1" type=
"checkbox" id=
"__nav_7_1" >
1846 <label class=
"md-nav__link" for=
"__nav_7_1">
1848 <span class=
"md-nav__icon md-icon"></span>
1850 <nav class=
"md-nav" aria-label=
"Tutorial Series" data-md-level=
"2">
1851 <label class=
"md-nav__title" for=
"__nav_7_1">
1852 <span class=
"md-nav__icon md-icon"></span>
1855 <ul class=
"md-nav__list" data-md-scrollfix
>
1861 <li class=
"md-nav__item">
1862 <a href=
"../../../tutorial/series/overview/" class=
"md-nav__link">
1873 <li class=
"md-nav__item">
1874 <a href=
"../../../tutorial/series/part_1/" class=
"md-nav__link">
1885 <li class=
"md-nav__item">
1886 <a href=
"../../../tutorial/series/part_2/" class=
"md-nav__link">
1897 <li class=
"md-nav__item">
1898 <a href=
"../../../tutorial/series/part_3/" class=
"md-nav__link">
1925 <div class=
"md-sidebar md-sidebar--secondary" data-md-component=
"sidebar" data-md-type=
"toc" >
1926 <div class=
"md-sidebar__scrollwrap">
1927 <div class=
"md-sidebar__inner">
1929 <nav class=
"md-nav md-nav--secondary" aria-label=
"Table of contents">
1935 <label class=
"md-nav__title" for=
"__toc">
1936 <span class=
"md-nav__icon md-icon"></span>
1939 <ul class=
"md-nav__list" data-md-component=
"toc" data-md-scrollfix
>
1941 <li class=
"md-nav__item">
1942 <a href=
"#understanding-caching" class=
"md-nav__link">
1943 Understanding Caching
1946 <nav class=
"md-nav" aria-label=
"Understanding Caching">
1947 <ul class=
"md-nav__list">
1949 <li class=
"md-nav__item">
1950 <a href=
"#when-to-use-a-cache" class=
"md-nav__link">
1956 <li class=
"md-nav__item">
1957 <a href=
"#when-not-to-use-a-cache" class=
"md-nav__link">
1958 When not to Use a Cache
1976 <div class=
"md-content" data-md-component=
"content">
1977 <article class=
"md-content__inner md-typeset">
1980 <a href=
"https://github.com/WoltLab/docs.woltlab.com/edit/5.4/docs/php/api/caches.md" title=
"Edit this page" class=
"md-content__button md-icon">
1981 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25z"/></svg>
1985 <h1 id=
"caches">Caches
<a class=
"headerlink" href=
"#caches" title=
"Permanent link">#
</a></h1>
1986 <p>WoltLab Suite offers two distinct types of caches:
</p>
1988 <li><a href=
"../caches_persistent-caches/">Persistent caches
</a> created by cache builders whose data can be stored using different cache sources.
</li>
1989 <li><a href=
"../caches_runtime-caches/">Runtime caches
</a> store objects for the duration of a single request.
</li>
1991 <h2 id=
"understanding-caching">Understanding Caching
<a class=
"headerlink" href=
"#understanding-caching" title=
"Permanent link">#
</a></h2>
1992 <p>Every so often, plugins make use of cache builders or runtime caches to store
1993 their data, even if there is absolutely no need for them to do so. Usually, this
1994 involves a strong opinion about the total number of SQL queries on a page,
1995 including but not limited to some magic treshold numbers, which should not be
1996 exceeded for
"performance reasons".
</p>
1997 <p>This misconception can easily lead into thinking that SQL queries should be
1998 avoided or at least written to a cache, so that it doesn't need to be executed
1999 so often. Unfortunately, this completely ignores the fact that both a single
2000 query can take down your app (e. g. full table scan on millions of rows), but
2001 10 queries using a primary key on a table with a few hundred rows will not slow
2003 <p>There are some queries that should go into caches by design, but most of the
2004 cache builders weren't initially there, but instead have been added because
2005 they were required to reduce the load
<em>significantly
</em>. You need to understand
2006 that caches always come at a cost, even a runtime cache does! In particular,
2007 they will always consume memory that is not released over the duration of the
2008 request lifecycle and potentially even leak memory by holding references to
2009 objects and data structures that are no longer required.
</p>
2010 <p>Caching should always be a solution for a problem.
</p>
2011 <h3 id=
"when-to-use-a-cache">When to Use a Cache
<a class=
"headerlink" href=
"#when-to-use-a-cache" title=
"Permanent link">#
</a></h3>
2012 <p>It's difficult to provide a definite answer or checklist when to use a cache
2013 and why it is required at this point, because the answer is: It depends. The
2014 permission cache for user groups is a good example for a valid cache, where
2015 we can achieve significant performance improvement compared to processing this
2016 data on every request.
</p>
2017 <p>Its caches are build for each permutation of user group memberships that are
2018 encountered for a page request. Building this data is an expensive process that
2019 involves both inheritance and specific rules in regards to when a value for a
2020 permission overrules another value. The added benefit of this cache is that one
2021 cache usually serves a large number of users with the same group memberships and
2022 by computing these permissions once, we can serve many different requests. Also,
2023 the permissions are rather static values that change very rarely and thus we can
2024 expect a very high cache lifetime before it gets rebuild.
</p>
2025 <h3 id=
"when-not-to-use-a-cache">When not to Use a Cache
<a class=
"headerlink" href=
"#when-not-to-use-a-cache" title=
"Permanent link">#
</a></h3>
2026 <p>I remember, a few years ago, there was a plugin that displayed a user's character
2027 from an online video game. The character sheet not only included a list of basic
2028 statistics, but also displayed the items that this character was wearing and or
2029 holding at the time.
</p>
2030 <p>The data for these items were downloaded in bulk from the game's vendor servers
2031 and stored in a persistent cache file that periodically gets renewed. There is
2032 nothing wrong with the idea of caching the data on your own server rather than
2033 requesting them everytime from the vendor's servers - not only because they
2034 imposed a limit on the number of requests per hour.
</p>
2035 <p>Unfortunately, the character sheet had a sub-par performance and the users were
2036 upset by the significant loading times compared to literally every other page
2037 on the same server. The author of the plugin was working hard to resolve this
2038 issue and was evaluating all kind of methods to improve the page performance,
2039 including deep-diving into the realm of micro-optimizations to squeeze out every
2040 last bit of performance that is possible.
</p>
2041 <p>The real problem was the cache file itself, it turns out that it was holding the
2042 data for several thousand items with a total file size of about
13 megabytes.
2043 It doesn't look that much at first glance, after all this isn't the '
90s anymore,
2044 but unserializing a
13 megabyte array is really slow and looking up items in such
2045 a large array isn't exactly fast either.
</p>
2046 <p>The solution was rather simple, the data that was fetched from the vendor's API
2047 was instead written into a separate database table. Next, the persistent cache
2048 was removed and the character sheet would now request the item data for that
2049 specific character straight from the database. Previously, the character sheet
2050 took several seconds to load and after the change it was done in a fraction of
2051 a second. Although quite extreme, this illustrates a situation where the cache
2052 file was introduced in the design process, without evaluating if the cache -
2053 at least how it was implemented - was really necessary.
</p>
2054 <p>Caching should always be a solution for a problem. Not the other way around.
</p>
2060 <div class=
"md-source-date">
2063 Last update:
2021-
01-
08
2082 <footer class=
"md-footer">
2084 <nav class=
"md-footer__inner md-grid" aria-label=
"Footer">
2086 <a href=
"../../exceptions/" class=
"md-footer__link md-footer__link--prev" rel=
"prev">
2087 <div class=
"md-footer__button md-icon">
2088 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12z"/></svg>
2090 <div class=
"md-footer__title">
2091 <div class=
"md-ellipsis">
2092 <span class=
"md-footer__direction">
2101 <a href=
"../caches_persistent-caches/" class=
"md-footer__link md-footer__link--next" rel=
"next">
2102 <div class=
"md-footer__title">
2103 <div class=
"md-ellipsis">
2104 <span class=
"md-footer__direction">
2110 <div class=
"md-footer__button md-icon">
2111 <svg xmlns=
"http://www.w3.org/2000/svg" viewBox=
"0 0 24 24"><path d=
"M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4z"/></svg>
2117 <div class=
"md-footer-meta md-typeset">
2118 <div class=
"md-footer-meta__inner md-grid">
2119 <div class=
"md-footer-copyright">
2121 <div class=
"md-footer-copyright__highlight">
2122 Copyright ©
2020 WoltLab GmbH
2126 <a href=
"https://squidfunk.github.io/mkdocs-material/" target=
"_blank" rel=
"noopener">
2131 <div class=
"md-footer-copyright">
2132 <a href=
"https://www.woltlab.com/legal-notice/">Legal Notice
</a>
2133 <a href=
"https://www.woltlab.com/privacy-policy/">Privacy Policy
</a>
2140 <div class=
"md-dialog" data-md-component=
"dialog">
2141 <div class=
"md-dialog__inner md-typeset"></div>
2143 <script id=
"__config" type=
"application/json">{
"base":
"../../..",
"features": [],
"translations": {
"clipboard.copy":
"Copy to clipboard",
"clipboard.copied":
"Copied to clipboard",
"search.config.lang":
"en",
"search.config.pipeline":
"trimmer, stopWordFilter",
"search.config.separator":
"[\\s\\-]+",
"search.placeholder":
"Search",
"search.result.placeholder":
"Type to start searching",
"search.result.none":
"No matching documents",
"search.result.one":
"1 matching document",
"search.result.other":
"# matching documents",
"search.result.more.one":
"1 more on this page",
"search.result.more.other":
"# more on this page",
"search.result.term.missing":
"Missing"},
"search":
"../../../assets/javascripts/workers/search.fe42c31b.min.js",
"version": {
"provider":
"mike"}}
</script>
2146 <script src=
"../../../assets/javascripts/bundle.d892486b.min.js"></script>