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>Validation and Data - 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=
"#form-validation-and-form-data" 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
>
314 <li class=
"md-nav__item md-nav__item--nested">
317 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5_1" type=
"checkbox" id=
"__nav_2_5_1" >
319 <label class=
"md-nav__link" for=
"__nav_2_5_1">
321 <span class=
"md-nav__icon md-icon"></span>
323 <nav class=
"md-nav" aria-label=
"Caches" data-md-level=
"3">
324 <label class=
"md-nav__title" for=
"__nav_2_5_1">
325 <span class=
"md-nav__icon md-icon"></span>
328 <ul class=
"md-nav__list" data-md-scrollfix
>
334 <li class=
"md-nav__item">
335 <a href=
"../../caches/" class=
"md-nav__link">
346 <li class=
"md-nav__item">
347 <a href=
"../../caches_persistent-caches/" class=
"md-nav__link">
358 <li class=
"md-nav__item">
359 <a href=
"../../caches_runtime-caches/" class=
"md-nav__link">
376 <li class=
"md-nav__item">
377 <a href=
"../../comments/" class=
"md-nav__link">
388 <li class=
"md-nav__item">
389 <a href=
"../../cronjobs/" class=
"md-nav__link">
400 <li class=
"md-nav__item">
401 <a href=
"../../events/" class=
"md-nav__link">
415 <li class=
"md-nav__item md-nav__item--active md-nav__item--nested">
418 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_2_5_5" type=
"checkbox" id=
"__nav_2_5_5" checked
>
420 <label class=
"md-nav__link" for=
"__nav_2_5_5">
422 <span class=
"md-nav__icon md-icon"></span>
424 <nav class=
"md-nav" aria-label=
"Form Builder" data-md-level=
"3">
425 <label class=
"md-nav__title" for=
"__nav_2_5_5">
426 <span class=
"md-nav__icon md-icon"></span>
429 <ul class=
"md-nav__list" data-md-scrollfix
>
435 <li class=
"md-nav__item">
436 <a href=
"../overview/" class=
"md-nav__link">
447 <li class=
"md-nav__item">
448 <a href=
"../structure/" class=
"md-nav__link">
459 <li class=
"md-nav__item">
460 <a href=
"../form_fields/" class=
"md-nav__link">
473 <li class=
"md-nav__item md-nav__item--active">
475 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"toc" type=
"checkbox" id=
"__toc">
480 <label class=
"md-nav__link md-nav__link--active" for=
"__toc">
482 <span class=
"md-nav__icon md-icon"></span>
485 <a href=
"./" class=
"md-nav__link md-nav__link--active">
490 <nav class=
"md-nav md-nav--secondary" aria-label=
"Table of contents">
496 <label class=
"md-nav__title" for=
"__toc">
497 <span class=
"md-nav__icon md-icon"></span>
500 <ul class=
"md-nav__list" data-md-component=
"toc" data-md-scrollfix
>
502 <li class=
"md-nav__item">
503 <a href=
"#form-validation" class=
"md-nav__link">
507 <nav class=
"md-nav" aria-label=
"Form Validation">
508 <ul class=
"md-nav__list">
510 <li class=
"md-nav__item">
511 <a href=
"#iformfieldvalidationerror-formfieldvalidationerror" class=
"md-nav__link">
512 IFormFieldValidationError / FormFieldValidationError
517 <li class=
"md-nav__item">
518 <a href=
"#iformfieldvalidator-formfieldvalidator" class=
"md-nav__link">
519 IFormFieldValidator / FormFieldValidator
529 <li class=
"md-nav__item">
530 <a href=
"#form-data" class=
"md-nav__link">
534 <nav class=
"md-nav" aria-label=
"Form Data">
535 <ul class=
"md-nav__list">
537 <li class=
"md-nav__item">
538 <a href=
"#iformdatahandler-formdatahandler" class=
"md-nav__link">
539 IFormDataHandler / FormDataHandler
544 <li class=
"md-nav__item">
545 <a href=
"#iformdataprocessor-defaultformdataprocessor" class=
"md-nav__link">
546 IFormDataProcessor / DefaultFormDataProcessor
551 <li class=
"md-nav__item">
552 <a href=
"#additional-data-processors" class=
"md-nav__link">
553 Additional Data Processors
556 <nav class=
"md-nav" aria-label=
"Additional Data Processors">
557 <ul class=
"md-nav__list">
559 <li class=
"md-nav__item">
560 <a href=
"#customformdataprocessor" class=
"md-nav__link">
561 CustomFormDataProcessor
566 <li class=
"md-nav__item">
567 <a href=
"#voidformdataprocessor" class=
"md-nav__link">
568 VoidFormDataProcessor
595 <li class=
"md-nav__item">
596 <a href=
"../dependencies/" class=
"md-nav__link">
613 <li class=
"md-nav__item">
614 <a href=
"../../package_installation_plugins/" class=
"md-nav__link">
615 Package Installation Plugins
625 <li class=
"md-nav__item">
626 <a href=
"../../user_activity_points/" class=
"md-nav__link">
637 <li class=
"md-nav__item">
638 <a href=
"../../user_notifications/" class=
"md-nav__link">
649 <li class=
"md-nav__item">
650 <a href=
"../../sitemaps/" class=
"md-nav__link">
667 <li class=
"md-nav__item">
668 <a href=
"../../../code-style/" class=
"md-nav__link">
679 <li class=
"md-nav__item">
680 <a href=
"../../../apps/" class=
"md-nav__link">
691 <li class=
"md-nav__item">
692 <a href=
"../../../gdpr/" class=
"md-nav__link">
713 <li class=
"md-nav__item md-nav__item--nested">
716 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_3" type=
"checkbox" id=
"__nav_3" >
718 <label class=
"md-nav__link" for=
"__nav_3">
719 Languages, Templates & CSS
720 <span class=
"md-nav__icon md-icon"></span>
722 <nav class=
"md-nav" aria-label=
"Languages, Templates & CSS" data-md-level=
"1">
723 <label class=
"md-nav__title" for=
"__nav_3">
724 <span class=
"md-nav__icon md-icon"></span>
725 Languages, Templates & CSS
727 <ul class=
"md-nav__list" data-md-scrollfix
>
733 <li class=
"md-nav__item">
734 <a href=
"../../../../view/languages/" class=
"md-nav__link">
745 <li class=
"md-nav__item">
746 <a href=
"../../../../view/templates/" class=
"md-nav__link">
757 <li class=
"md-nav__item">
758 <a href=
"../../../../view/template-plugins/" class=
"md-nav__link">
769 <li class=
"md-nav__item">
770 <a href=
"../../../../view/css/" class=
"md-nav__link">
791 <li class=
"md-nav__item md-nav__item--nested">
794 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_4" type=
"checkbox" id=
"__nav_4" >
796 <label class=
"md-nav__link" for=
"__nav_4">
797 TypeScript and JavaScript API
798 <span class=
"md-nav__icon md-icon"></span>
800 <nav class=
"md-nav" aria-label=
"TypeScript and JavaScript API" data-md-level=
"1">
801 <label class=
"md-nav__title" for=
"__nav_4">
802 <span class=
"md-nav__icon md-icon"></span>
803 TypeScript and JavaScript API
805 <ul class=
"md-nav__list" data-md-scrollfix
>
811 <li class=
"md-nav__item">
812 <a href=
"../../../../javascript/general-usage/" class=
"md-nav__link">
823 <li class=
"md-nav__item">
824 <a href=
"../../../../javascript/typescript/" class=
"md-nav__link">
836 <li class=
"md-nav__item md-nav__item--nested">
839 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_4_3" type=
"checkbox" id=
"__nav_4_3" >
841 <label class=
"md-nav__link" for=
"__nav_4_3">
843 <span class=
"md-nav__icon md-icon"></span>
845 <nav class=
"md-nav" aria-label=
"New API" data-md-level=
"2">
846 <label class=
"md-nav__title" for=
"__nav_4_3">
847 <span class=
"md-nav__icon md-icon"></span>
850 <ul class=
"md-nav__list" data-md-scrollfix
>
856 <li class=
"md-nav__item">
857 <a href=
"../../../../javascript/new-api_writing-a-module/" class=
"md-nav__link">
868 <li class=
"md-nav__item">
869 <a href=
"../../../../javascript/new-api_data-structures/" class=
"md-nav__link">
880 <li class=
"md-nav__item">
881 <a href=
"../../../../javascript/new-api_core/" class=
"md-nav__link">
892 <li class=
"md-nav__item">
893 <a href=
"../../../../javascript/new-api_dom/" class=
"md-nav__link">
904 <li class=
"md-nav__item">
905 <a href=
"../../../../javascript/new-api_events/" class=
"md-nav__link">
916 <li class=
"md-nav__item">
917 <a href=
"../../../../javascript/new-api_ajax/" class=
"md-nav__link">
928 <li class=
"md-nav__item">
929 <a href=
"../../../../javascript/new-api_dialogs/" class=
"md-nav__link">
940 <li class=
"md-nav__item">
941 <a href=
"../../../../javascript/new-api_browser/" class=
"md-nav__link">
942 Browser and Screen Sizes
952 <li class=
"md-nav__item">
953 <a href=
"../../../../javascript/new-api_ui/" class=
"md-nav__link">
970 <li class=
"md-nav__item">
971 <a href=
"../../../../javascript/legacy-api/" class=
"md-nav__link">
982 <li class=
"md-nav__item">
983 <a href=
"../../../../javascript/helper-functions/" class=
"md-nav__link">
994 <li class=
"md-nav__item">
995 <a href=
"../../../../javascript/code-snippets/" class=
"md-nav__link">
1016 <li class=
"md-nav__item md-nav__item--nested">
1019 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_5" type=
"checkbox" id=
"__nav_5" >
1021 <label class=
"md-nav__link" for=
"__nav_5">
1023 <span class=
"md-nav__icon md-icon"></span>
1025 <nav class=
"md-nav" aria-label=
"Package Components" data-md-level=
"1">
1026 <label class=
"md-nav__title" for=
"__nav_5">
1027 <span class=
"md-nav__icon md-icon"></span>
1030 <ul class=
"md-nav__list" data-md-scrollfix
>
1036 <li class=
"md-nav__item">
1037 <a href=
"../../../../package/package-xml/" class=
"md-nav__link">
1049 <li class=
"md-nav__item md-nav__item--nested">
1052 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_5_2" type=
"checkbox" id=
"__nav_5_2" >
1054 <label class=
"md-nav__link" for=
"__nav_5_2">
1056 <span class=
"md-nav__icon md-icon"></span>
1058 <nav class=
"md-nav" aria-label=
"PIPs" data-md-level=
"2">
1059 <label class=
"md-nav__title" for=
"__nav_5_2">
1060 <span class=
"md-nav__icon md-icon"></span>
1063 <ul class=
"md-nav__list" data-md-scrollfix
>
1069 <li class=
"md-nav__item">
1070 <a href=
"../../../../package/pip/" class=
"md-nav__link">
1081 <li class=
"md-nav__item">
1082 <a href=
"../../../../package/pip/acl-option/" class=
"md-nav__link">
1093 <li class=
"md-nav__item">
1094 <a href=
"../../../../package/pip/acp-menu/" class=
"md-nav__link">
1105 <li class=
"md-nav__item">
1106 <a href=
"../../../../package/pip/acp-search-provider/" class=
"md-nav__link">
1117 <li class=
"md-nav__item">
1118 <a href=
"../../../../package/pip/acp-template/" class=
"md-nav__link">
1129 <li class=
"md-nav__item">
1130 <a href=
"../../../../package/pip/bbcode/" class=
"md-nav__link">
1141 <li class=
"md-nav__item">
1142 <a href=
"../../../../package/pip/box/" class=
"md-nav__link">
1153 <li class=
"md-nav__item">
1154 <a href=
"../../../../package/pip/clipboard-action/" class=
"md-nav__link">
1165 <li class=
"md-nav__item">
1166 <a href=
"../../../../package/pip/core-object/" class=
"md-nav__link">
1177 <li class=
"md-nav__item">
1178 <a href=
"../../../../package/pip/cronjob/" class=
"md-nav__link">
1189 <li class=
"md-nav__item">
1190 <a href=
"../../../../package/pip/database/" class=
"md-nav__link">
1201 <li class=
"md-nav__item">
1202 <a href=
"../../../../package/pip/event-listener/" class=
"md-nav__link">
1213 <li class=
"md-nav__item">
1214 <a href=
"../../../../package/pip/file/" class=
"md-nav__link">
1225 <li class=
"md-nav__item">
1226 <a href=
"../../../../package/pip/language/" class=
"md-nav__link">
1237 <li class=
"md-nav__item">
1238 <a href=
"../../../../package/pip/media-provider/" class=
"md-nav__link">
1249 <li class=
"md-nav__item">
1250 <a href=
"../../../../package/pip/menu/" class=
"md-nav__link">
1261 <li class=
"md-nav__item">
1262 <a href=
"../../../../package/pip/menu-item/" class=
"md-nav__link">
1273 <li class=
"md-nav__item">
1274 <a href=
"../../../../package/pip/object-type/" class=
"md-nav__link">
1285 <li class=
"md-nav__item">
1286 <a href=
"../../../../package/pip/object-type-definition/" class=
"md-nav__link">
1287 objectTypeDefinition
1297 <li class=
"md-nav__item">
1298 <a href=
"../../../../package/pip/option/" class=
"md-nav__link">
1309 <li class=
"md-nav__item">
1310 <a href=
"../../../../package/pip/page/" class=
"md-nav__link">
1321 <li class=
"md-nav__item">
1322 <a href=
"../../../../package/pip/pip/" class=
"md-nav__link">
1333 <li class=
"md-nav__item">
1334 <a href=
"../../../../package/pip/script/" class=
"md-nav__link">
1345 <li class=
"md-nav__item">
1346 <a href=
"../../../../package/pip/smiley/" class=
"md-nav__link">
1357 <li class=
"md-nav__item">
1358 <a href=
"../../../../package/pip/sql/" class=
"md-nav__link">
1369 <li class=
"md-nav__item">
1370 <a href=
"../../../../package/pip/style/" class=
"md-nav__link">
1381 <li class=
"md-nav__item">
1382 <a href=
"../../../../package/pip/template/" class=
"md-nav__link">
1393 <li class=
"md-nav__item">
1394 <a href=
"../../../../package/pip/template-listener/" class=
"md-nav__link">
1405 <li class=
"md-nav__item">
1406 <a href=
"../../../../package/pip/user-group-option/" class=
"md-nav__link">
1417 <li class=
"md-nav__item">
1418 <a href=
"../../../../package/pip/user-menu/" class=
"md-nav__link">
1429 <li class=
"md-nav__item">
1430 <a href=
"../../../../package/pip/user-notification-event/" class=
"md-nav__link">
1431 userNotificationEvent
1441 <li class=
"md-nav__item">
1442 <a href=
"../../../../package/pip/user-option/" class=
"md-nav__link">
1453 <li class=
"md-nav__item">
1454 <a href=
"../../../../package/pip/user-profile-menu/" class=
"md-nav__link">
1471 <li class=
"md-nav__item">
1472 <a href=
"../../../../package/database-php-api/" class=
"md-nav__link">
1493 <li class=
"md-nav__item md-nav__item--nested">
1496 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6" type=
"checkbox" id=
"__nav_6" >
1498 <label class=
"md-nav__link" for=
"__nav_6">
1500 <span class=
"md-nav__icon md-icon"></span>
1502 <nav class=
"md-nav" aria-label=
"Migration" data-md-level=
"1">
1503 <label class=
"md-nav__title" for=
"__nav_6">
1504 <span class=
"md-nav__icon md-icon"></span>
1507 <ul class=
"md-nav__list" data-md-scrollfix
>
1514 <li class=
"md-nav__item md-nav__item--nested">
1517 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_1" type=
"checkbox" id=
"__nav_6_1" >
1519 <label class=
"md-nav__link" for=
"__nav_6_1">
1520 Migrating from WSC
5.3
1521 <span class=
"md-nav__icon md-icon"></span>
1523 <nav class=
"md-nav" aria-label=
"Migrating from WSC 5.3" data-md-level=
"2">
1524 <label class=
"md-nav__title" for=
"__nav_6_1">
1525 <span class=
"md-nav__icon md-icon"></span>
1526 Migrating from WSC
5.3
1528 <ul class=
"md-nav__list" data-md-scrollfix
>
1534 <li class=
"md-nav__item">
1535 <a href=
"../../../../migration/wsc53/php/" class=
"md-nav__link">
1546 <li class=
"md-nav__item">
1547 <a href=
"../../../../migration/wsc53/session/" class=
"md-nav__link">
1548 Session Handling and Authentication
1558 <li class=
"md-nav__item">
1559 <a href=
"../../../../migration/wsc53/javascript/" class=
"md-nav__link">
1560 TypeScript and JavaScript
1570 <li class=
"md-nav__item">
1571 <a href=
"../../../../migration/wsc53/templates/" class=
"md-nav__link">
1582 <li class=
"md-nav__item">
1583 <a href=
"../../../../migration/wsc53/libraries/" class=
"md-nav__link">
1584 Third Party Libraries
1601 <li class=
"md-nav__item md-nav__item--nested">
1604 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_2" type=
"checkbox" id=
"__nav_6_2" >
1606 <label class=
"md-nav__link" for=
"__nav_6_2">
1607 Migrating from WSC
5.2
1608 <span class=
"md-nav__icon md-icon"></span>
1610 <nav class=
"md-nav" aria-label=
"Migrating from WSC 5.2" data-md-level=
"2">
1611 <label class=
"md-nav__title" for=
"__nav_6_2">
1612 <span class=
"md-nav__icon md-icon"></span>
1613 Migrating from WSC
5.2
1615 <ul class=
"md-nav__list" data-md-scrollfix
>
1621 <li class=
"md-nav__item">
1622 <a href=
"../../../../migration/wsc52/php/" class=
"md-nav__link">
1633 <li class=
"md-nav__item">
1634 <a href=
"../../../../migration/wsc52/templates/" class=
"md-nav__link">
1635 Templates and Languages
1645 <li class=
"md-nav__item">
1646 <a href=
"../../../../migration/wsc52/libraries/" class=
"md-nav__link">
1647 Third Party Libraries
1664 <li class=
"md-nav__item md-nav__item--nested">
1667 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_3" type=
"checkbox" id=
"__nav_6_3" >
1669 <label class=
"md-nav__link" for=
"__nav_6_3">
1670 Migrating from WSC
3.1
1671 <span class=
"md-nav__icon md-icon"></span>
1673 <nav class=
"md-nav" aria-label=
"Migrating from WSC 3.1" data-md-level=
"2">
1674 <label class=
"md-nav__title" for=
"__nav_6_3">
1675 <span class=
"md-nav__icon md-icon"></span>
1676 Migrating from WSC
3.1
1678 <ul class=
"md-nav__list" data-md-scrollfix
>
1684 <li class=
"md-nav__item">
1685 <a href=
"../../../../migration/wsc31/php/" class=
"md-nav__link">
1703 <li class=
"md-nav__item md-nav__item--nested">
1706 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_4" type=
"checkbox" id=
"__nav_6_4" >
1708 <label class=
"md-nav__link" for=
"__nav_6_4">
1709 Migrating from WSC
3.0
1710 <span class=
"md-nav__icon md-icon"></span>
1712 <nav class=
"md-nav" aria-label=
"Migrating from WSC 3.0" data-md-level=
"2">
1713 <label class=
"md-nav__title" for=
"__nav_6_4">
1714 <span class=
"md-nav__icon md-icon"></span>
1715 Migrating from WSC
3.0
1717 <ul class=
"md-nav__list" data-md-scrollfix
>
1723 <li class=
"md-nav__item">
1724 <a href=
"../../../../migration/wsc30/php/" class=
"md-nav__link">
1735 <li class=
"md-nav__item">
1736 <a href=
"../../../../migration/wsc30/javascript/" class=
"md-nav__link">
1747 <li class=
"md-nav__item">
1748 <a href=
"../../../../migration/wsc30/templates/" class=
"md-nav__link">
1759 <li class=
"md-nav__item">
1760 <a href=
"../../../../migration/wsc30/css/" class=
"md-nav__link">
1771 <li class=
"md-nav__item">
1772 <a href=
"../../../../migration/wsc30/package/" class=
"md-nav__link">
1790 <li class=
"md-nav__item md-nav__item--nested">
1793 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_6_5" type=
"checkbox" id=
"__nav_6_5" >
1795 <label class=
"md-nav__link" for=
"__nav_6_5">
1796 Migrating from WCF
2.1
1797 <span class=
"md-nav__icon md-icon"></span>
1799 <nav class=
"md-nav" aria-label=
"Migrating from WCF 2.1" data-md-level=
"2">
1800 <label class=
"md-nav__title" for=
"__nav_6_5">
1801 <span class=
"md-nav__icon md-icon"></span>
1802 Migrating from WCF
2.1
1804 <ul class=
"md-nav__list" data-md-scrollfix
>
1810 <li class=
"md-nav__item">
1811 <a href=
"../../../../migration/wcf21/php/" class=
"md-nav__link">
1822 <li class=
"md-nav__item">
1823 <a href=
"../../../../migration/wcf21/templates/" class=
"md-nav__link">
1834 <li class=
"md-nav__item">
1835 <a href=
"../../../../migration/wcf21/css/" class=
"md-nav__link">
1846 <li class=
"md-nav__item">
1847 <a href=
"../../../../migration/wcf21/package/" class=
"md-nav__link">
1874 <li class=
"md-nav__item md-nav__item--nested">
1877 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_7" type=
"checkbox" id=
"__nav_7" >
1879 <label class=
"md-nav__link" for=
"__nav_7">
1881 <span class=
"md-nav__icon md-icon"></span>
1883 <nav class=
"md-nav" aria-label=
"Tutorials" data-md-level=
"1">
1884 <label class=
"md-nav__title" for=
"__nav_7">
1885 <span class=
"md-nav__icon md-icon"></span>
1888 <ul class=
"md-nav__list" data-md-scrollfix
>
1895 <li class=
"md-nav__item md-nav__item--nested">
1898 <input class=
"md-nav__toggle md-toggle" data-md-toggle=
"__nav_7_1" type=
"checkbox" id=
"__nav_7_1" >
1900 <label class=
"md-nav__link" for=
"__nav_7_1">
1902 <span class=
"md-nav__icon md-icon"></span>
1904 <nav class=
"md-nav" aria-label=
"Tutorial Series" data-md-level=
"2">
1905 <label class=
"md-nav__title" for=
"__nav_7_1">
1906 <span class=
"md-nav__icon md-icon"></span>
1909 <ul class=
"md-nav__list" data-md-scrollfix
>
1915 <li class=
"md-nav__item">
1916 <a href=
"../../../../tutorial/series/overview/" class=
"md-nav__link">
1927 <li class=
"md-nav__item">
1928 <a href=
"../../../../tutorial/series/part_1/" class=
"md-nav__link">
1939 <li class=
"md-nav__item">
1940 <a href=
"../../../../tutorial/series/part_2/" class=
"md-nav__link">
1951 <li class=
"md-nav__item">
1952 <a href=
"../../../../tutorial/series/part_3/" class=
"md-nav__link">
1979 <div class=
"md-sidebar md-sidebar--secondary" data-md-component=
"sidebar" data-md-type=
"toc" >
1980 <div class=
"md-sidebar__scrollwrap">
1981 <div class=
"md-sidebar__inner">
1983 <nav class=
"md-nav md-nav--secondary" aria-label=
"Table of contents">
1989 <label class=
"md-nav__title" for=
"__toc">
1990 <span class=
"md-nav__icon md-icon"></span>
1993 <ul class=
"md-nav__list" data-md-component=
"toc" data-md-scrollfix
>
1995 <li class=
"md-nav__item">
1996 <a href=
"#form-validation" class=
"md-nav__link">
2000 <nav class=
"md-nav" aria-label=
"Form Validation">
2001 <ul class=
"md-nav__list">
2003 <li class=
"md-nav__item">
2004 <a href=
"#iformfieldvalidationerror-formfieldvalidationerror" class=
"md-nav__link">
2005 IFormFieldValidationError / FormFieldValidationError
2010 <li class=
"md-nav__item">
2011 <a href=
"#iformfieldvalidator-formfieldvalidator" class=
"md-nav__link">
2012 IFormFieldValidator / FormFieldValidator
2022 <li class=
"md-nav__item">
2023 <a href=
"#form-data" class=
"md-nav__link">
2027 <nav class=
"md-nav" aria-label=
"Form Data">
2028 <ul class=
"md-nav__list">
2030 <li class=
"md-nav__item">
2031 <a href=
"#iformdatahandler-formdatahandler" class=
"md-nav__link">
2032 IFormDataHandler / FormDataHandler
2037 <li class=
"md-nav__item">
2038 <a href=
"#iformdataprocessor-defaultformdataprocessor" class=
"md-nav__link">
2039 IFormDataProcessor / DefaultFormDataProcessor
2044 <li class=
"md-nav__item">
2045 <a href=
"#additional-data-processors" class=
"md-nav__link">
2046 Additional Data Processors
2049 <nav class=
"md-nav" aria-label=
"Additional Data Processors">
2050 <ul class=
"md-nav__list">
2052 <li class=
"md-nav__item">
2053 <a href=
"#customformdataprocessor" class=
"md-nav__link">
2054 CustomFormDataProcessor
2059 <li class=
"md-nav__item">
2060 <a href=
"#voidformdataprocessor" class=
"md-nav__link">
2061 VoidFormDataProcessor
2084 <div class=
"md-content" data-md-component=
"content">
2085 <article class=
"md-content__inner md-typeset">
2088 <a href=
"https://github.com/WoltLab/docs.woltlab.com/edit/5.4/docs/php/api/form_builder/validation_data.md" title=
"Edit this page" class=
"md-content__button md-icon">
2089 <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>
2093 <h1 id=
"form-validation-and-form-data">Form Validation and Form Data
<a class=
"headerlink" href=
"#form-validation-and-form-data" title=
"Permanent link">#
</a></h1>
2094 <h2 id=
"form-validation">Form Validation
<a class=
"headerlink" href=
"#form-validation" title=
"Permanent link">#
</a></h2>
2095 <p>Every form field class has to implement
<code>IFormField::validate()
</code> according to their internal logic of what constitutes a valid value.
2096 If a certain constraint for the value is no met, a form field validation error object is added to the form field.
2097 Form field validation error classes have to implement the interface
<code>IFormFieldValidationError
</code>.
</p>
2098 <p>In addition to intrinsic validations like checking the length of the value of a text form field, in many cases, there are additional constraints specific to the form like ensuring that the text is not already used by a different object of the same database object class.
2099 Such additional validations can be added to (and removed from) the form field via implementations of the
<code>IFormFieldValidator
</code> interface.
</p>
2100 <h3 id=
"iformfieldvalidationerror-formfieldvalidationerror"><code>IFormFieldValidationError
</code> /
<code>FormFieldValidationError
</code><a class=
"headerlink" href=
"#iformfieldvalidationerror-formfieldvalidationerror" title=
"Permanent link">#
</a></h3>
2101 <p><code>IFormFieldValidationError
</code> requires the following methods:
</p>
2103 <li><code>__construct($type, $languageItem = null, array $information = [])
</code> creates a new validation error object for an error with the given type and message stored in the given language items.
2104 The information array is used when generating the error message.
</li>
2105 <li><code>getHtml()
</code> returns the HTML element representing the error that is shown to the user.
</li>
2106 <li><code>getMessage()
</code> returns the error message based on the language item and information array given in the constructor.
</li>
2107 <li><code>getInformation()
</code> and
<code>getType()
</code> are getters for the first and third parameter of the constructor.
</li>
2109 <p><code>FormFieldValidationError
</code> is a default implementation of the interface that shows the error in an
<code>small.innerError
</code> HTML element below the form field.
</p>
2110 <p>Form field validation errors are added to form fields via the
<code>IFormField::addValidationError(IFormFieldValidationError $error)
</code> method.
</p>
2111 <h3 id=
"iformfieldvalidator-formfieldvalidator"><code>IFormFieldValidator
</code> /
<code>FormFieldValidator
</code><a class=
"headerlink" href=
"#iformfieldvalidator-formfieldvalidator" title=
"Permanent link">#
</a></h3>
2112 <p><code>IFormFieldValidator
</code> requires the following methods:
</p>
2114 <li><code>__construct($id, callable $validator)
</code> creates a new validator with the given id that passes the validated form field to the given callable that does the actual validation.
2115 <code>static validateId($id)
</code> is used to check if the given id is valid.
</li>
2116 <li><code>__invoke(IFormField $field)
</code> is used when the form field is validated to execute the validator.
</li>
2117 <li><code>getId()
</code> returns the id of the validator.
</li>
2119 <p><code>FormFieldValidator
</code> is a default implementation of the interface.
</p>
2120 <p>Form field validators are added to form fields via the
<code>addValidator(IFormFieldValidator $validator)
</code> method.
</p>
2121 <h2 id=
"form-data">Form Data
<a class=
"headerlink" href=
"#form-data" title=
"Permanent link">#
</a></h2>
2122 <p>After a form is successfully validated, the data of the form fields (returned by
<code>IFormDocument::getData()
</code>) have to be extracted which is the job of the
<code>IFormDataHandler
</code> object returned by
<code>IFormDocument::getDataHandler()
</code>.
2123 Form data handlers themselves, however, are only iterating through all
<code>IFormDataProcessor
</code> instances that have been registered with the data handler.
</p>
2124 <h3 id=
"iformdatahandler-formdatahandler"><code>IFormDataHandler
</code> /
<code>FormDataHandler
</code><a class=
"headerlink" href=
"#iformdatahandler-formdatahandler" title=
"Permanent link">#
</a></h3>
2125 <p><code>IFormDataHandler
</code> requires the following methods:
</p>
2127 <li><code>addProcessor(IFormDataProcessor $processor)
</code> adds a new data processor to the data handler.
</li>
2128 <li><code>getFormData(IFormDocument $document)
</code> returns the data of the given form by applying all registered data handlers on the form.
</li>
2129 <li><code>getObjectData(IFormDocument $document, IStorableObject $object)
</code> returns the data of the given object which will be used to populate the form field values of the given form.
</li>
2131 <p><code>FormDataHandler
</code> is the default implementation of this interface and should also be extended instead of implementing the interface directly.
</p>
2132 <h3 id=
"iformdataprocessor-defaultformdataprocessor"><code>IFormDataProcessor
</code> /
<code>DefaultFormDataProcessor
</code><a class=
"headerlink" href=
"#iformdataprocessor-defaultformdataprocessor" title=
"Permanent link">#
</a></h3>
2133 <p><code>IFormDataProcessor
</code> requires the following methods:
</p>
2135 <li><code>processFormData(IFormDocument $document, array $parameters)
</code> is called by
<code>IFormDataHandler::getFormData()
</code>.
2136 The method processes the given parameters array and returns the processed version.
</li>
2137 <li><code>processObjectData(IFormDocument $document, array $data, IStorableObject $object)
</code> is called by
<code>IFormDataHandler::getObjectData()
</code>.
2138 The method processes the given object data array and returns the processed version.
</li>
2140 <p>When
<code>FormDocument
</code> creates its
<code>FormDataHandler
</code> instance, it automatically registers an
<code>DefaultFormDataProcessor
</code> object as the first data processor.
2141 <code>DefaultFormDataProcessor
</code> puts the save value of all form fields that are available and have a save value into
<code>$parameters['data']
</code> using the form field’s object property as the array key.
</p>
2142 <div class=
"admonition warning">
2143 <p class=
"admonition-title"><code>IFormDataProcessor
</code> should not be implemented directly. Instead,
<code>AbstractFormDataProcessor
</code> should be extended.
</p>
2145 <div class=
"admonition info">
2146 <p class=
"admonition-title">All form data is put into the
<code>data
</code> sub-array so that the whole
<code>$parameters
</code> array can be passed to a database object action object that requires the actual database object data to be in the
<code>data
</code> sub-array.
</p>
2148 <h3 id=
"additional-data-processors">Additional Data Processors
<a class=
"headerlink" href=
"#additional-data-processors" title=
"Permanent link">#
</a></h3>
2149 <h4 id=
"customformdataprocessor"><code>CustomFormDataProcessor
</code><a class=
"headerlink" href=
"#customformdataprocessor" title=
"Permanent link">#
</a></h4>
2150 <p>As mentioned above, the data in the
<code>data
</code> sub-array is intended to directly create or update the database object with.
2151 As these values are used in the database query directly, these values cannot contain arrays.
2152 Several form fields, however, store and return their data in form of arrays.
2153 Thus, this data cannot be returned by
<code>IFormField::getSaveValue()
</code> so that
<code>IFormField::hasSaveValue()
</code> returns
<code>false
</code> and the form field’s data is not collected by the standard
<code>DefaultFormDataProcessor
</code> object.
</p>
2154 <p>Instead, such form fields register a
<code>CustomFormDataProcessor
</code> in their
<code>IFormField::populate()
</code> method that inserts the form field value into the
<code>$parameters
</code> array directly.
2155 This way, the relevant database object action method has access to the data to save it appropriately.
</p>
2156 <p>The constructor of
<code>CustomFormDataProcessor
</code> requires an id (that is primarily used in error messages during the validation of the second parameter) and callables for
<code>IFormDataProcessor::processFormData()
</code> and
<code>IFormDataProcessor::processObjectData()
</code> which are passed the same parameters as the
<code>IFormDataProcessor
</code> methods.
2157 Only one of the callables has to be given, the other one then defaults to simply returning the relevant array unchanged.
</p>
2158 <h4 id=
"voidformdataprocessor"><code>VoidFormDataProcessor
</code><a class=
"headerlink" href=
"#voidformdataprocessor" title=
"Permanent link">#
</a></h4>
2159 <p>Some form fields might only exist to toggle the visibility of other form fields (via dependencies) but the data of form field itself is irrelevant.
2160 As
<code>DefaultFormDataProcessor
</code> collects the data of all form fields, an additional data processor in the form of a
<code>VoidFormDataProcessor
</code> can be added whose constructor
<code>__construct($property, $isDataProperty = true)
</code> requires the name of the relevant object property/form id and whether the form field value is stored in the
<code>data
</code> sub-array or directory in the
<code>$parameters
</code> array.
2161 When the data processor is invoked, it checks whether the relevant entry in the
<code>$parameters
</code> array exists and voids it by removing it from the array.
</p>
2167 <div class=
"md-source-date">
2170 Last update:
2021-
01-
15
2189 <footer class=
"md-footer">
2191 <nav class=
"md-footer__inner md-grid" aria-label=
"Footer">
2193 <a href=
"../form_fields/" class=
"md-footer__link md-footer__link--prev" rel=
"prev">
2194 <div class=
"md-footer__button md-icon">
2195 <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>
2197 <div class=
"md-footer__title">
2198 <div class=
"md-ellipsis">
2199 <span class=
"md-footer__direction">
2208 <a href=
"../dependencies/" class=
"md-footer__link md-footer__link--next" rel=
"next">
2209 <div class=
"md-footer__title">
2210 <div class=
"md-ellipsis">
2211 <span class=
"md-footer__direction">
2217 <div class=
"md-footer__button md-icon">
2218 <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>
2224 <div class=
"md-footer-meta md-typeset">
2225 <div class=
"md-footer-meta__inner md-grid">
2226 <div class=
"md-footer-copyright">
2228 <div class=
"md-footer-copyright__highlight">
2229 Copyright ©
2020 WoltLab GmbH
2233 <a href=
"https://squidfunk.github.io/mkdocs-material/" target=
"_blank" rel=
"noopener">
2238 <div class=
"md-footer-copyright">
2239 <a href=
"https://www.woltlab.com/legal-notice/">Legal Notice
</a>
2240 <a href=
"https://www.woltlab.com/privacy-policy/">Privacy Policy
</a>
2247 <div class=
"md-dialog" data-md-component=
"dialog">
2248 <div class=
"md-dialog__inner md-typeset"></div>
2250 <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>
2253 <script src=
"../../../../assets/javascripts/bundle.d892486b.min.js"></script>