The Form Population Filter (FPF)
The Form Population Filter wraps around the whole request processing and repopulates forms when errors occur. It also inserts error messages at appropriate places. The FPF parses the resulting HTML code and uses DOM/XPATH to insert the form values and messages. The FPF refills the fields in any form that has an "action" attribute matching the incoming request uri.
The FPF and HTML Entities
As the FPF parses xhtml code as valid XML by default it does not like HTML entities such as  , ©, so they should be avoided. The general recommendation is to serve your pages with an UTF-8 charset that eliminates the need for most of those entities as they can be represented by regular chars. So instead of © use the regular © sign. For all other entities that don't have a character to display use the numeric entities - instead of use &160;. Numeric entities parse just fine in XML.
An alternative way would be to add all entities you use to a local DTD or to use the HTML parsing mode, but those have their own drawbacks.
Advantages
Because the FPF evaluates the resulting HTML code, it is independent from any template engine you might want to use and works with all of them. Using the FPF to prefill and refill the form data also makes your application immune to XSS injection attacks in forms as the FPF handles all escaping. However, other XSS injection attacks might still be possible - for example when you display user-provided data at any other place.
Configuring the FPF
The FPF uses XPATH-expressions to insert the error messages into the document, so using the FPF requires at least a basic knowledge of XPATH. The configuration is done in the app/config/global_filters.xml or at runtime. The FPF take a long list of configuration options:
- methods
- on which request-methods the FPF should be invoked. Usually the FPF should only act on write requests as these indicate a form submission. The FPF parses the resulting HTML code for each request of the given method, so having the FPF act on read requests would be a major performance issue. If the parameter is omitted, the FPF never runs.
- output_types
- A list of ouput types for which the FPF should be invoked. The FPF can only be used on output types that produce valid (X)HTML output. It must not be used for output types that produce JSON or other non-html output. If the parameter is omitted, the FPF runs for all output types.
- field_error_messages
- Where to insert error messages that affect a single field only - regular textfields, checkboxes and the like. The parameter contains a list of XPATH expressions with corresponding insertion rules. The expressions and insertion rules are relative to the form field for which the messages are inserted.
- multi_field_error_messages
- Where to insert error messages that affect multiple fields like messages from a date validator or a validator that compares two fields. The parameter contains a list of XPATH expressions with corresponding insertion rules. The expressions and insertion rules are relative to the form field for which the messages are inserted.
- error_messages
- Where to insert error messages that have no corresponding field or did not match in field_error_messages or multi_field_error_messages. The parameter contains a list of XPATH expressions with corresponding insertion rules. The expressions and insertion rules are relative to the form field for which the messages are inserted or relative to the form element itself when a message has no corresponding field.
- error_class
- The CSS class to set on all element that have an error. Defaults to 'error'.
- error_class_map
- A list of xpath expressions as key and a class as value. Sets the given class on all elements that match the given xpath expression. Defaults to 'self::${htmlnsPrefix}*' => '<error_class>'.
- include_password_inputs
- True if password input fields should be refilled as well, defaults to false.
- include_hidden_inputs
- True if hidden input fields should be refilled as well, defaults to true
- skip
- contains a list of field names that should not be refilled.
- parse_xhtml_as_xml
- true to use XML parsing mode for XHTML documents. If XML parsing mode is enabled DomDocument::loadXml() is used to parse the document, otherwise DomDocument::loadHtml() . XML parsing mode offers major advantages in character encoding handling. Defaults to true.
- ignore_parse_errors
- True to ignore parse errors and continue processing. The form will not be refilled and no error messages inserted but will be displayed to the user instead of throwing an exeception. Defaults to false.
- dom_substitute_entities
- Sets the substitutEntities flag on the DomDocument created, defaults to false. If true, entities are substituted.
- dom_resolve_externals
- Sets the resolveExternals flag on the DomDocument created, defaults to false. Enabling this option may slow processing down by a large factor as all externals for the Document Type Definition may be loaded from an external server.
- dom_validate_on_parse
- Sets the validateOnParse flag on the DomDocument created, defaults to false. If true, the XLML code is validated against the DTD on load.
- dom_preserve_white_space
- Sets the preserveWhiteSpace flag on the DomDocument created, defaults to true. If false, redundant white space is removed from the document.
- dom_format_output
- Sets the formatOutput flag on the DomDocument, defaults to false. If true, the output is nicely formatted with indenting and extra space.
- log_parse_errors
- True to write parse errors to a logfile. The log will contain the parse errors as well as the HTML code that cause the errors. Requires logging, defaults to true.
- logging_severity
- Any of the AgaviLogger logging severities. The severity of the log message, defaults to AgaviLogger::FATAL.
- logging_logger
- The logger to write the message to, can be any configured logger name, null to write to no specific logger. Defaults to null.
- force_encoding
- Force the output to be in the specified encoding. Any encoding that is supported by your PHP installation is a valid value, false to keep the document encoding. Requires the iconv extension for any encoding other than ISO-8859-1 an UTF-8. Defaults to false.
- force_output_mode
- Enforce the given output mode regardless of how the document was formatted. 'xhtml' or 'html' are valid and supported values, false to keep the documents output mode. Defaults to false.
- force_request_uri
- Don't use the incoming request uri to detect the form to populate but the given one. Any URI is a valid value, false to use the incoming URI. Defaults to false.
- cdata_fix
- Fix CDATA wrappers in inline style and script blocks. Defaults to true.
- remove_auto_xml_prolog
- remove any XML prolog that is autogenerated by libxml, defaults to true.
- validation_report
- The validation result to obtain the error messages from. Defaults to the main containers validation result.
The insertion rules contain three parameters:
- location
- Where to insert the message in respect to the matched element.
The location accepts three possible values:
- before
- Insert as previous sibling of the element matched - i.e. before the element in the dom structure.
- after
- Insert as next sibling of the element matched - i.e. after the element in the dom structure.
- child
- Insert as last child element of the element matched.
- container
- Contains markup for a container element. If this paramater is set, all error message will be collected in the container and then the whole container will be inserted at the given location. The markup consists entirely of HTML code and must contain the special variable ${errorMessages} which marks the place where the messages will be inserted in the HTML code.
- markup
- Contains markup for the error message. The markup consists entirely of HTML code and must contain the special variable ${errorMessage} which marks the place where the message will be inserted in the HTML code.
Errors that did not match will be set in the request attribute 'orphaned_errors' in the namespace 'org.agavi.filter.FormPopulationFilter'.
XML-Configuration
The defaults for the FPF configuration are set in the app/config/global_filters.xml:
<filter name="FormPopulationFilter" class="AgaviFormPopulationFilter">
<!-- only run for request method "write" (=POST on web) by default (can be changed at runtime, of course) -->
<!-- if you omit this, it will never run -->
<ae:parameter name="methods">
<ae:parameter>write</ae:parameter>
</ae:parameter>
<!-- only run for output type "html" (so it doesn't break on, say, JSON data) -->
<!-- if you omit this, it will run for all output types -->
<ae:parameter name="output_types">
<ae:parameter>html</ae:parameter>
</ae:parameter>
<!-- error message insertion rules -->
<!-- they are run in sequence; once the first one matched, execution stops -->
<!--
errors that belong to more than one field (e.g. date validator) can be handled using "multi_field_error_messages"
"normal" errors are handled through "field_error_messages"
errors that yield no match and those that have no corresponding field are inserted using rules defined in "error_messages".
-->
<!--
for all field error messages.
-->
<ae:parameter name="field_error_messages">
<!-- ${htmlnsPrefix} is either empty (for HTML) or something like "html:" for XHTML documents with xmlns="..." notation. Always use this, makes your code more bullet proof. XPath needs the namespaces when the document is namespaced -->
<!-- all input fields that are not checkboxes or radios, and all textareas -->
<ae:parameter name="self::${htmlnsPrefix}input[not(@type='checkbox' or @type='radio')] | self::${htmlnsPrefix}textarea">
<!-- if this rule matched, then the node found by the rule is our starting point for inserting the error message(s). -->
<!-- can be any of "before", "after" or "child" (to insert as prev, next sibling or last child) -->
<ae:parameter name="location">after</ae:parameter>
<!-- a container groups all errors for one element. ${errorMessages} is a string containing all errors (see below) -->
<ae:parameter name="container"><![CDATA[<div class="errors">${errorMessages}</div>]]></ae:parameter>
<!-- this defines the HTML for each individual error message; those are then put into the container. ${errorMessage} is the error message string -->
<ae:parameter name="markup"><![CDATA[<p class="error">${errorMessage}</p>]]></ae:parameter>
</ae:parameter>
<!-- all other inputs - note how we select the parent element and insert ourselves as last child of it -->
<ae:parameter name="parent::*">
<ae:parameter name="location">child</ae:parameter>
<ae:parameter name="container"><![CDATA[<div class="errors">${errorMessages}</div>]]></ae:parameter>
<ae:parameter name="markup"><![CDATA[<p class="error">${errorMessage}</p>]]></ae:parameter>
</ae:parameter>
</ae:parameter>
<!--
<ae:parameter name="multi_field_error_messages">
</ae:parameter>
-->
<!-- everything that did not match any of the rules above, or errors that do not belong to a field -->
<ae:parameter name="error_messages">
<!-- insert before the element -->
<!-- that can be an input, or a form, if the error does not belong to a field or didn't match anywhere else -->
<ae:parameter name="self::*">
<ae:parameter name="location">before</ae:parameter>
<!-- no container here! we just insert paragraph elements -->
<ae:parameter name="markup"><![CDATA[<p class="error">${errorMessage}</p>]]></ae:parameter>
</ae:parameter>
</ae:parameter>
</filter>
Common Pitfalls
A list of common WTF?! moments that occur when using the FPF.
- mangled specialchars
- A common cause for mangled specialchars is the HTML parsing mode. HTML parsing mode requires a <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> tag with a valid charset and this tag must be the first thing in the document's head.

