Forms

A form is a component responsible for validation of data entered by users. Every form consists of set of fields and set of rules configured in an XML document.

A field in a form is validated when all validators given for this field pass the validation.

Order of validators for the field is important - they are checked in the same order as they appear in the document. Validator that fails stops the validation procedure for the field. This way one can obtain proper message code. Important issue: properties of validators are cumulative, i.e. next validator inherits properties from the previous one. Consider the following structures:

<!-- STRUCTURE A -->
<field name="field_string" class="pl.aislib.util.validators.StringValidator">
  <validation msg-code="1">
    <property name="required" value="true"/>
  </validation>
  <validation msg-code="2">
    <property name="required" value="false"/>
    <property name="minimumLength" value="5"/>
  </validation>
  <validation msg-code="3">
    <property name="maximumLength" value="10"/>
  </validation>
</field>

<!-- STRUCTURE B -->
<field name="field_string" class="pl.aislib.util.validators.StringValidator">
  <validation msg-code="1">
    <property name="required" value="true"/>
    <property name="minimumLength" value="5"/>
    <property name="maximumLength" value="10"/>
  </validation>
</field>
Both examples show configuration of a field that should take strings 5 to 10 characters long. But if a user enters value "abcdefghijklmnopq" (too long), using structure A yields message code number 3 (first two validators will pass), while structure B gives error message number 1.

Fields may be simple (or "normal", like in examples in previous paragraph). Another types of fields can also be applied. Namely:

  • complex - built from another simple fields;
  • dynamic - defining validation of fields with the same structure;
Consider the following configuration (the context here is "three input fields"):
<!-- STRUCTURE C -->
<field name="field_int_day" class="pl.aislib.util.validators.IntegerValidator">
  <validation msg-code="1">
    <property name="required" value="false"/>
  </validation>
</field>
<field name="field_int_month" class="pl.aislib.util.validators.IntegerValidator">
  <validation msg-code="2">
    <property name="required" value="false"/>
  </validation>
</field>
<field name="field_int_year" class="pl.aislib.util.validators.IntegerValidator">
  <validation msg-code="3">
    <property name="required" value="false"/>
  </validation>
</field>
<field name="field_date" class="pl.aislib.util.validators.DateValidator">
  <builder class="pl.aislib.util.builder.DateBuilder">
    <builder-mapping field-param="day" field-name="field_int_day"/>
    <builder-mapping field-param="month" field-name="field_int_month"/>
    <builder-mapping field-param="year" field-name="field_int_year"/>
  </builder>
  <validation msg-code="4">
    <property name="required" value="true"/>
  </validation>
  <validation msg-code="5">
    <property name="required" value="false"/>
  </validation>
</field>
Class DateBuilder is responsible for validating those three input fields as one. And validation of field-date field will be used. Message code number 5 should state that date is invalid.

Consider also the following configuration:

<!-- STRUCTURE D -->
<field name="field_int" class="pl.aislib.util.validators.IntegerValidator" dynamic="true">
  <validation msg-code="1">
    <property name="required" value="true"/>
  </validation>
  <validation msg-code="2">
    <property name="required" value="false"/>
  </validation>
</field>
Field field_int is dynamic, meaning the form will validate multiple fields with the same structure. Those fields' names share the same prefix which, in this case, is exactly field_int and the names differ with a number. So, we can put in an HTML form three fields: field_int1, field_int2, field_int3 that will be validated against integer numbers one by one using the structure described above.

Notes: It is recommended to put number of dynamic fields in the HTML form's hidden field named as the field in structure with _count suffix. In case of STRUCTURE D above, it should be named field_int_count and should have value of 3. If field_int_count is not given, a procedure will be run to count dynamic fields for field_int.

There is also a possibility of defining relations, or rules between fields. Here is a sample configuration:

<!-- STRUCTURE E -->
<fields&>
  <field name="field_date_from" class="pl.aislib.util.validators.DateValidator">
    <validation msg-code="1">
      <property name="required" value="true"/>
    </validation>
    <validation msg-code="2">
      <property name="required" value="false"/>
    </validation>
  </field>
  <field name="field_date_to" class="pl.aislib.util.validators.DateValidator">
    <validation msg-code="3">
      <property name="required" value="true"/>
    </validation>
    <validation msg-code="4">
      <property name="required" value="false"/>
    </validation>
  </field>
</fields>
<rules>
  <rule name="rule_dates" class="pl.aislib.util.rules.DateRangeRule">
    <mapping rule-param="date_from" field-name="field_date_from"/>
    <mapping rule-param="date_to" field-name="field_date_to"/>
  </rule>
</rules>
Rule rule_dates will apply when fields field_date_from and field_date_to are validated successfully. The rule is in aislib and its function is to check whether dates are in proper order.

Rules may also be dynamic, provided that at least one of a field for the rule is dynamic. The same messages' conversion can be applied.

Forms also have a special treatment of message handling. It is done by the use of implementations of pl.aislib.fm.forms.IMessageConverter interface. The interface contains method converting message keys and contents to something new. Look at the following message configuration:

<message code="1">
  <key>message_key{entity:name}</key>
  <content>Invalid integer in field number {entity:dynamicNumberFrom1}.</content>
</message>
and in the following code:
... in subclass of Page, after validation ...
Map messages = form.getErrorMessages(new pl.aislib.util.messages.MessageFormatConverter());
Class pl.aislib.util.messages.MessageFormatConverter uses extended MessageFormat class to format each message key and content. Namely, each time a string in curly braces occurs (e.g. {entity:name}) it is converted to appriopriate value that may correspond to the interior of those braces (e.g. name_of_field). So, in scenario of dynamic fields, the following messages can be created:
  • Invalid integer in field number 1.
  • Invalid integer in field number 2.
  • Invalid integer in field number 3.