4 <meta http-equiv=
"X-UA-Compatible" content=
"IE=edge">
5 <meta name=
"viewport" content=
"width=device-width, initial-scale=1">
6 <meta name=
"description" content=
"">
7 <meta name=
"keywords" content=
" ">
8 <title>Form Validation and Form Data | WoltLab Suite
5.3 Documentation
</title>
10 <link rel=
"stylesheet" href=
"https://docs.woltlab.com/5.3/css/syntax.css">
11 <link rel=
"stylesheet" href=
"https://fonts.googleapis.com/css?family=Open+Sans:400,300,600">
12 <link rel=
"stylesheet" href=
"https://docs.woltlab.com/5.3/css/font-awesome.min.css">
13 <!--<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">-->
14 <link rel=
"stylesheet" href=
"https://docs.woltlab.com/5.3/css/modern-business.css">
15 <link rel=
"stylesheet" href=
"https://docs.woltlab.com/5.3/css/lavish-bootstrap.css">
16 <link rel=
"stylesheet" href=
"https://docs.woltlab.com/5.3/css/customstyles.css">
17 <link rel=
"stylesheet" href=
"https://docs.woltlab.com/5.3/css/theme-blue.css?v=3">
19 <script src=
"https://docs.woltlab.com/5.3/js/jquery.min.js"></script>
20 <script src=
"https://docs.woltlab.com/5.3/js/jquery.cookie.min.js"></script>
21 <script src=
"https://docs.woltlab.com/5.3/js/jquery.navgoco.min.js"></script>
22 <script src=
"https://docs.woltlab.com/5.3/js/bootstrap.min.js"></script>
23 <script src=
"https://docs.woltlab.com/5.3/js/anchor.min.js"></script>
24 <script src=
"https://docs.woltlab.com/5.3/js/toc.js"></script>
25 <script src=
"https://docs.woltlab.com/5.3/js/customscripts.js"></script>
27 <link rel=
"shortcut icon" href=
"https://docs.woltlab.com/5.3/images/favicon.ico">
29 <link rel=
"alternate" type=
"application/rss+xml" title=
"woltlab.github.io" href=
"https://docs.woltlab.com/5.3feed.xml">
32 $(document).ready(function() {
33 // Initialize navgoco with default options
34 $(
"#mysidebar").navgoco({
37 openClass: 'active', // open
38 save: false, // leave false or nav highlighting doesn't work right
50 $(
"#collapseAll").click(function(e) {
52 $(
"#mysidebar").navgoco('toggle', false);
55 $(
"#expandAll").click(function(e) {
57 $(
"#mysidebar").navgoco('toggle', true);
65 $('[
data-toggle=
"tooltip"]').tooltip()
73 <nav class=
"navbar navbar-inverse navbar-fixed-top">
74 <div class=
"container topnavlinks">
75 <div class=
"navbar-header">
76 <button type=
"button" class=
"navbar-toggle" data-toggle=
"collapse" data-target=
"#bs-example-navbar-collapse-1">
77 <span class=
"sr-only">Toggle navigation
</span>
78 <span class=
"icon-bar"></span>
79 <span class=
"icon-bar"></span>
80 <span class=
"icon-bar"></span>
82 <a class=
"fa fa-home fa-lg navbar-brand" href=
"index.html"> <span class=
"projectTitle"> WoltLab Suite
5.3 Documentation
</span></a>
84 <div class=
"collapse navbar-collapse" id=
"bs-example-navbar-collapse-1">
85 <ul class=
"nav navbar-nav navbar-right">
86 <!-- entries without drop-downs appear here -->
90 <li><a href=
"https://www.woltlab.com" target=
"_blank">woltlab.com
</a></li>
96 <li><a href=
"https://github.com/WoltLab/WCF/" target=
"_blank">Code on github.com
</a></li>
100 <!-- entries with drop-downs appear here -->
101 <!-- conditional logic to control which topnav appears for the audience defined in the configuration file.-->
104 <!--comment out this block if you want to hide search-->
107 <div id=
"search-demo-container">
108 <input type=
"text" id=
"search-input" placeholder=
"search...">
109 <ul id=
"results-container"></ul>
111 <script src=
"https://docs.woltlab.com/5.3/js/jekyll-search.js" type=
"text/javascript"></script>
112 <script type=
"text/javascript">
113 SimpleJekyllSearch.init({
114 searchInput: document.getElementById('search-input'),
115 resultsContainer: document.getElementById('results-container'),
116 dataSource: 'https://docs.woltlab.com/
5.3/search.json',
117 searchResultTemplate: '
<li><a href=
"{url}" title=
"Form Validation and Form Data">{title}
</a></li>',
118 noResultsText: 'No results found.',
132 <div class=
"container">
133 <div class=
"col-lg-12"> </div>
136 <div class=
"col-md-3">
140 <ul id=
"mysidebar" class=
"nav">
141 <li class=
"sidebarTitle">WoltLab Suite
5.3</li>
146 <a href=
"#">Getting Started
</a>
152 <li data-identifier=
"index"><a href=
"index.html">Introduction
</a></li>
161 <li data-identifier=
"getting-started_quick-start"><a href=
"getting-started_quick-start.html">Quick Start
</a></li>
171 <a href=
"#">PHP API
</a>
177 <li data-identifier=
"php_pages"><a href=
"php_pages.html">Pages
</a></li>
186 <li data-identifier=
"php_database-objects"><a href=
"php_database-objects.html">Database Objects
</a></li>
195 <li data-identifier=
"php_database-access"><a href=
"php_database-access.html">Database Access
</a></li>
204 <li data-identifier=
"php_exceptions"><a href=
"php_exceptions.html">Exceptions
</a></li>
213 <li class=
"subfolders">
219 <li data-identifier=
"php_api_caches"><a href=
"php_api_caches.html">Caches
</a></li>
224 <li data-identifier=
"php_api_comments"><a href=
"php_api_comments.html">Comments
</a></li>
229 <li data-identifier=
"php_api_cronjobs"><a href=
"php_api_cronjobs.html">Cronjobs
</a></li>
234 <li data-identifier=
"php_api_events"><a href=
"php_api_events.html">Events
</a></li>
239 <li data-identifier=
"php_api_form_builder"><a href=
"php_api_form_builder.html">Form Builder
</a></li>
244 <li data-identifier=
"php_api_package_installation_plugins"><a href=
"php_api_package_installation_plugins.html">Package Installation Plugins
</a></li>
249 <li data-identifier=
"php_api_user_activity_points"><a href=
"php_api_user_activity_points.html">User Activity Points
</a></li>
254 <li data-identifier=
"php_api_user_notifications"><a href=
"php_api_user_notifications.html">User Notifications
</a></li>
259 <li data-identifier=
"php_api_sitemaps"><a href=
"php_api_sitemaps.html">Sitemaps
</a></li>
269 <li data-identifier=
"php_code-style"><a href=
"php_code-style.html">Code Style
</a></li>
278 <li data-identifier=
"php_apps"><a href=
"php_apps.html">Apps
</a></li>
287 <li data-identifier=
"php_gdpr"><a href=
"php_gdpr.html">GDPR
</a></li>
297 <a href=
"#">Languages, Templates & CSS
</a>
303 <li data-identifier=
"view_languages"><a href=
"view_languages.html">Languages
</a></li>
312 <li data-identifier=
"view_templates"><a href=
"view_templates.html">Templates
</a></li>
321 <li data-identifier=
"view_css"><a href=
"view_css.html">CSS
</a></li>
331 <a href=
"#">JavaScript API
</a>
337 <li data-identifier=
"javascript_general-usage"><a href=
"javascript_general-usage.html">General Usage
</a></li>
346 <li class=
"subfolders">
347 <a href=
"#">New API
</a>
352 <li data-identifier=
"javascript_new-api_writing-a-module"><a href=
"javascript_new-api_writing-a-module.html">Writing a module
</a></li>
357 <li data-identifier=
"javascript_new-api_data-structures"><a href=
"javascript_new-api_data-structures.html">Data Structures
</a></li>
362 <li data-identifier=
"javascript_new-api_core"><a href=
"javascript_new-api_core.html">Core Functions
</a></li>
367 <li data-identifier=
"javascript_new-api_dom"><a href=
"javascript_new-api_dom.html">DOM
</a></li>
372 <li data-identifier=
"javascript_new-api_events"><a href=
"javascript_new-api_events.html">Event Handling
</a></li>
377 <li data-identifier=
"javascript_new-api_ajax"><a href=
"javascript_new-api_ajax.html">Ajax
</a></li>
382 <li data-identifier=
"javascript_new-api_dialogs"><a href=
"javascript_new-api_dialogs.html">Dialogs
</a></li>
387 <li data-identifier=
"javascript_new-api_browser"><a href=
"javascript_new-api_browser.html">Browser and Screen Sizes
</a></li>
392 <li data-identifier=
"javascript_new-api_ui"><a href=
"javascript_new-api_ui.html">User Interface
</a></li>
402 <li data-identifier=
"javascript_legacy-api"><a href=
"javascript_legacy-api.html">Legacy API
</a></li>
411 <li data-identifier=
"javascript_helper-functions"><a href=
"javascript_helper-functions.html">Helper Functions
</a></li>
420 <li data-identifier=
"javascript_code-snippets"><a href=
"javascript_code-snippets.html">Code Snippets
</a></li>
430 <a href=
"#">Package Components
</a>
436 <li data-identifier=
"package_package-xml"><a href=
"package_package-xml.html">package.xml
</a></li>
445 <li data-identifier=
"package_pip"><a href=
"package_pip.html">PIPs
</a></li>
455 <a href=
"#">Migration
</a>
461 <li class=
"subfolders">
462 <a href=
"#">Migrating from WSC
5.2</a>
467 <li data-identifier=
"migration_wsc-52_php"><a href=
"migration_wsc-52_php.html">PHP API
</a></li>
472 <li data-identifier=
"migration_wsc-52_templates"><a href=
"migration_wsc-52_templates.html">Templates and Languages
</a></li>
477 <li data-identifier=
"migration_wsc-52_libraries"><a href=
"migration_wsc-52_libraries.html">Third Party Libraries
</a></li>
483 <li class=
"subfolders">
484 <a href=
"#">Migrating from WSC
3.1</a>
489 <li data-identifier=
"migration_wsc-31_php"><a href=
"migration_wsc-31_php.html">PHP API
</a></li>
495 <li class=
"subfolders">
496 <a href=
"#">Migrating from WSC
3.0</a>
501 <li data-identifier=
"migration_wsc-30_php"><a href=
"migration_wsc-30_php.html">PHP API
</a></li>
506 <li data-identifier=
"migration_wsc-30_javascript"><a href=
"migration_wsc-30_javascript.html">JavaScript API
</a></li>
511 <li data-identifier=
"migration_wsc-30_templates"><a href=
"migration_wsc-30_templates.html">Templates
</a></li>
516 <li data-identifier=
"migration_wsc-30_css"><a href=
"migration_wsc-30_css.html">CSS
</a></li>
521 <li data-identifier=
"migration_wsc-30_package"><a href=
"migration_wsc-30_package.html">Package Components
</a></li>
527 <li class=
"subfolders">
528 <a href=
"#">Migrating from WCF
2.1</a>
533 <li data-identifier=
"migration_wcf-21_php"><a href=
"migration_wcf-21_php.html">PHP API
</a></li>
538 <li data-identifier=
"migration_wcf-21_templates"><a href=
"migration_wcf-21_templates.html">Templates
</a></li>
543 <li data-identifier=
"migration_wcf-21_css"><a href=
"migration_wcf-21_css.html">CSS
</a></li>
548 <li data-identifier=
"migration_wcf-21_package"><a href=
"migration_wcf-21_package.html">Package Components
</a></li>
559 <a href=
"#">Tutorials
</a>
565 <li data-identifier=
"tutorial_tutorial-series"><a href=
"tutorial_tutorial-series.html">Tutorial Series
</a></li>
579 var sidebar = $('#mysidebar');
580 var item = sidebar.find('.active');
581 if (item.length ===
0) {
582 var parent = 'php_api_form_builder';
584 sidebar.find('li[
data-identifier=
"' + parent + '"]').addClass('active');
588 sidebar.find(
".active").parents('li').toggleClass(
"active");
594 <div class=
"col-md-9">
595 <div class=
"post-header">
596 <h1 class=
"post-title-main">Form Validation and Form Data
</h1>
601 <div class=
"post-content">
607 <!-- this handles the automatic toc. use ## for subheads to auto-generate the on-page minitoc. if you use html tags, you must supply an ID for the heading element in order for it to appear in the minitoc. -->
609 $( document ).ready(function() {
610 // Handler for .ready() called.
612 $('#toc').toc({ minimumHeaders:
0, listType: 'ul', showSpeed:
0, headers: 'h2,h3,h4' });
614 /* this offset helps account for the space taken up by the floating toolbar. */
615 $('#toc').on('click', 'a', function() {
616 var target = $(this.getAttribute('href'))
617 , scroll_target = target.offset().top
619 $(window).scrollTop(scroll_target -
10);
630 <h2 id=
"form-validation">Form Validation
</h2>
632 <p>Every form field class has to implement
<code class=
"language-plaintext highlighter-rouge">IFormField::validate()
</code> according to their internal logic of what constitutes a valid value.
633 If a certain constraint for the value is no met, a form field validation error object is added to the form field.
634 Form field validation error classes have to implement the interface
<code class=
"language-plaintext highlighter-rouge">IFormFieldValidationError
</code>.
</p>
636 <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.
637 Such additional validations can be added to (and removed from) the form field via implementations of the
<code class=
"language-plaintext highlighter-rouge">IFormFieldValidator
</code> interface.
</p>
639 <h3 id=
"iformfieldvalidationerror--formfieldvalidationerror"><code class=
"language-plaintext highlighter-rouge">IFormFieldValidationError
</code> /
<code class=
"language-plaintext highlighter-rouge">FormFieldValidationError
</code></h3>
641 <p><code class=
"language-plaintext highlighter-rouge">IFormFieldValidationError
</code> requires the following methods:
</p>
644 <li><code class=
"language-plaintext highlighter-rouge">__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.
645 The information array is used when generating the error message.
</li>
646 <li><code class=
"language-plaintext highlighter-rouge">getHtml()
</code> returns the HTML element representing the error that is shown to the user.
</li>
647 <li><code class=
"language-plaintext highlighter-rouge">getMessage()
</code> returns the error message based on the language item and information array given in the constructor.
</li>
648 <li><code class=
"language-plaintext highlighter-rouge">getInformation()
</code> and
<code class=
"language-plaintext highlighter-rouge">getType()
</code> are getters for the first and third parameter of the constructor.
</li>
651 <p><code class=
"language-plaintext highlighter-rouge">FormFieldValidationError
</code> is a default implementation of the interface that shows the error in an
<code class=
"language-plaintext highlighter-rouge">small.innerError
</code> HTML element below the form field.
</p>
653 <p>Form field validation errors are added to form fields via the
<code class=
"language-plaintext highlighter-rouge">IFormField::addValidationError(IFormFieldValidationError $error)
</code> method.
</p>
655 <h3 id=
"iformfieldvalidator--formfieldvalidator"><code class=
"language-plaintext highlighter-rouge">IFormFieldValidator
</code> /
<code class=
"language-plaintext highlighter-rouge">FormFieldValidator
</code></h3>
657 <p><code class=
"language-plaintext highlighter-rouge">IFormFieldValidator
</code> requires the following methods:
</p>
660 <li><code class=
"language-plaintext highlighter-rouge">__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.
661 <code class=
"language-plaintext highlighter-rouge">static validateId($id)
</code> is used to check if the given id is valid.
</li>
662 <li><code class=
"language-plaintext highlighter-rouge">__invoke(IFormField $field)
</code> is used when the form field is validated to execute the validator.
</li>
663 <li><code class=
"language-plaintext highlighter-rouge">getId()
</code> returns the id of the validator.
</li>
666 <p><code class=
"language-plaintext highlighter-rouge">FormFieldValidator
</code> is a default implementation of the interface.
</p>
668 <p>Form field validators are added to form fields via the
<code class=
"language-plaintext highlighter-rouge">addValidator(IFormFieldValidator $validator)
</code> method.
</p>
670 <h2 id=
"form-data">Form Data
</h2>
672 <p>After a form is successfully validated, the data of the form fields (returned by
<code class=
"language-plaintext highlighter-rouge">IFormDocument::getData()
</code>) have to be extracted which is the job of the
<code class=
"language-plaintext highlighter-rouge">IFormDataHandler
</code> object returned by
<code class=
"language-plaintext highlighter-rouge">IFormDocument::getDataHandler()
</code>.
673 Form data handlers themselves, however, are only iterating through all
<code class=
"language-plaintext highlighter-rouge">IFormDataProcessor
</code> instances that have been registered with the data handler.
</p>
675 <h3 id=
"iformdatahandler--formdatahandler"><code class=
"language-plaintext highlighter-rouge">IFormDataHandler
</code> /
<code class=
"language-plaintext highlighter-rouge">FormDataHandler
</code></h3>
677 <p><code class=
"language-plaintext highlighter-rouge">IFormDataHandler
</code> requires the following methods:
</p>
680 <li><code class=
"language-plaintext highlighter-rouge">addProcessor(IFormDataProcessor $processor)
</code> adds a new data processor to the data handler.
</li>
681 <li><code class=
"language-plaintext highlighter-rouge">getFormData(IFormDocument $document)
</code> returns the data of the given form by applying all registered data handlers on the form.
</li>
682 <li><code class=
"language-plaintext highlighter-rouge">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>
685 <p><code class=
"language-plaintext highlighter-rouge">FormDataHandler
</code> is the default implementation of this interface and should also be extended instead of implementing the interface directly.
</p>
687 <h3 id=
"iformdataprocessor--defaultformdataprocessor"><code class=
"language-plaintext highlighter-rouge">IFormDataProcessor
</code> /
<code class=
"language-plaintext highlighter-rouge">DefaultFormDataProcessor
</code></h3>
689 <p><code class=
"language-plaintext highlighter-rouge">IFormDataProcessor
</code> requires the following methods:
</p>
692 <li><code class=
"language-plaintext highlighter-rouge">processFormData(IFormDocument $document, array $parameters)
</code> is called by
<code class=
"language-plaintext highlighter-rouge">IFormDataHandler::getFormData()
</code>.
693 The method processes the given parameters array and returns the processed version.
</li>
694 <li><code class=
"language-plaintext highlighter-rouge">processObjectData(IFormDocument $document, array $data, IStorableObject $object)
</code> is called by
<code class=
"language-plaintext highlighter-rouge">IFormDataHandler::getObjectData()
</code>.
695 The method processes the given object data array and returns the processed version.
</li>
698 <p>When
<code class=
"language-plaintext highlighter-rouge">FormDocument
</code> creates its
<code class=
"language-plaintext highlighter-rouge">FormDataHandler
</code> instance, it automatically registers an
<code class=
"language-plaintext highlighter-rouge">DefaultFormDataProcessor
</code> object as the first data processor.
699 <code class=
"language-plaintext highlighter-rouge">DefaultFormDataProcessor
</code> puts the save value of all form fields that are available and have a save value into
<code class=
"language-plaintext highlighter-rouge">$parameters['data']
</code> using the form field’s object property as the array key.
</p>
701 <div class=
"bs-callout bs-callout-warning"><code class=
"language-plaintext highlighter-rouge">IFormDataProcessor
</code> should not be implemented directly. Instead,
<code class=
"language-plaintext highlighter-rouge">AbstractFormDataProcessor
</code> should be extended.
</div>
703 <div class=
"bs-callout bs-callout-info">All form data is put into the
<code class=
"language-plaintext highlighter-rouge">data
</code> sub-array so that the whole
<code class=
"language-plaintext highlighter-rouge">$parameters
</code> array can be passed to a database object action object that requires the actual database object data to be in the
<code class=
"language-plaintext highlighter-rouge">data
</code> sub-array.
</div>
705 <h3 id=
"additional-data-processors">Additional Data Processors
</h3>
707 <h4 id=
"customformdataprocessor"><code class=
"language-plaintext highlighter-rouge">CustomFormDataProcessor
</code></h4>
709 <p>As mentioned above, the data in the
<code class=
"language-plaintext highlighter-rouge">data
</code> sub-array is intended to directly create or update the database object with.
710 As these values are used in the database query directly, these values cannot contain arrays.
711 Several form fields, however, store and return their data in form of arrays.
712 Thus, this data cannot be returned by
<code class=
"language-plaintext highlighter-rouge">IFormField::getSaveValue()
</code> so that
<code class=
"language-plaintext highlighter-rouge">IFormField::hasSaveValue()
</code> returns
<code class=
"language-plaintext highlighter-rouge">false
</code> and the form field’s data is not collected by the standard
<code class=
"language-plaintext highlighter-rouge">DefaultFormDataProcessor
</code> object.
</p>
714 <p>Instead, such form fields register a
<code class=
"language-plaintext highlighter-rouge">CustomFormDataProcessor
</code> in their
<code class=
"language-plaintext highlighter-rouge">IFormField::populate()
</code> method that inserts the form field value into the
<code class=
"language-plaintext highlighter-rouge">$parameters
</code> array directly.
715 This way, the relevant database object action method has access to the data to save it appropriately.
</p>
717 <p>The constructor of
<code class=
"language-plaintext highlighter-rouge">CustomFormDataProcessor
</code> requires an id (that is primarily used in error messages during the validation of the second parameter) and callables for
<code class=
"language-plaintext highlighter-rouge">IFormDataProcessor::processFormData()
</code> and
<code class=
"language-plaintext highlighter-rouge">IFormDataProcessor::processObjectData()
</code> which are passed the same parameters as the
<code class=
"language-plaintext highlighter-rouge">IFormDataProcessor
</code> methods.
718 Only one of the callables has to be given, the other one then defaults to simply returning the relevant array unchanged.
</p>
720 <h4 id=
"voidformdataprocessor"><code class=
"language-plaintext highlighter-rouge">VoidFormDataProcessor
</code></h4>
722 <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.
723 As
<code class=
"language-plaintext highlighter-rouge">DefaultFormDataProcessor
</code> collects the data of all form fields, an additional data processor in the form of a
<code class=
"language-plaintext highlighter-rouge">VoidFormDataProcessor
</code> can be added whose constructor
<code class=
"language-plaintext highlighter-rouge">__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 class=
"language-plaintext highlighter-rouge">data
</code> sub-array or directory in the
<code class=
"language-plaintext highlighter-rouge">$parameters
</code> array.
724 When the data processor is invoked, it checks whether the relevant entry in the
<code class=
"language-plaintext highlighter-rouge">$parameters
</code> array exists and voids it by removing it from the array.
</p>
739 <div class=
"footerBox">
740 <div class=
"container">
741 <div class=
"footerBoxLeft">
743 <a target=
"_blank" href=
"https://github.com/woltlab/woltlab.github.io/blob/master/pages/php/api/formBuilder/php_api_form_builder-validation_data.md" class=
"btn btn-default githubEditButton no_icon" role=
"button"><i class=
"fa fa-github fa-lg"></i> Edit on GitHub
</a>
744 <p>Site last generated: Mar
5,
2021</p>
746 <div class=
"footerBoxRight">
747 <a class=
"no_icon" href=
"https://www.woltlab.com"><img src=
"https://docs.woltlab.com/5.3/images/woltlab-black.png" srcset=
"https://docs.woltlab.com/5.3/images/woltlab-black@2x.png 2x" height=
"40" width=
"204" alt=
""></a>
752 <div class=
"pageFooter">
753 <div class=
"container">
754 © 2001 ‐
2021 <a class=
"no_icon" href=
"https://www.woltlab.com">WoltLab GmbH
</a>. All rights reserved. |
<a class=
"no_icon" href=
"https://www.woltlab.com/legal-notice/">Legal Notice
</a> |
<a class=
"no_icon" href=
"https://www.woltlab.com/privacy-policy/">Privacy Policy
</a>