[html-formfu] Date element validation

Carl Franks fireartist at gmail.com
Thu Jun 26 14:32:41 BST 2008


2008/6/12 Michele Beltrame <mb at cattlegrid.info>:
>> If the only error in the submissions is an invalid date, then the form will
>> be rendered with the "Invalid date" error message, as expected. However, if
>> there are any other errors in the submission (such as a missing required
>> field), then only those error messages are displayed; the invalid date
>> error is not generated.
>> I feel that this makes for a poor user experience, because it adds an extra
>> step for the user to fix all the errors.
>
> This is because Inflators are not evaluated if there are unsatisfied
> Constraints. You're right it makes the user experience poor, as he(/
> thinks a field is OK and then discovers it isn't.
>
> What I do is to also have a callback Constraint which converts the
> date/time field into a DateTime object and returns error if the
> conversion is not successful. I often use this Constraint also to
> perform other checks (i.e. for the date not to be in the future,
> etc...). After that, I also use the Inflator in order to get a
> DateTime object once the form processing is finished.
>
> This gives the user the experience he/she expects.
>
> I know that doing the conversion 2 times might seem a little awkward,
> but it seems that the way FormFu is meant to be: the Inflators stage
> doesn't happen before the Constraints stage has compelted succesfully.
>
> It would maybe be nice to have a "force_all_stages" option which would
> go one with processing in any case, but I don't know enough of FormFu
> internals to understand if it's easy or even possible to implement.

The "force_all_stages" idea isn't the way to go. If we need to use
that to achieve simple things in basic forms, then it'll be a
nightmare when you want to add a file upload field and need to do a
Constraint:::File::MIME check before running it through an
Inflator::Imager.

I've added a DateTime constraint which simply verifies the input is a
valid date.

I had initially been hesitant, because I was worried it would be prone
to errors, having to provide both the constraint and the inflator with
the same 'parser' config - but I discovered in the yaml spec that yaml
supports references to values, so you can get around the duplication
like so:

elements:
  - type: Date
    name: date

    - constraints:
        type: DateTime
        parser: &PARSER
          strptime: '%d-%m-%Y'

    - inflators:
        type: DateTime
        parser: *PARSER

I think it's both very cool, and very scary that yaml supports this :)

I was considering adding some date-logic checking, but have decided
that these checks should probably belong in a separate constraint.
Partly because the config could get very hairy, but also because it's
probably best to chain the constraints, so it checks it's a valid date
first, then that the date is in range - this will allow for more
accurate error messages for each check.
Probably something like:

elements:
  - type: Date
    name: date

    - constraints:
        - type: DateTime
          # message: 'Invalid date'

        - type: DateTime::TodayOrBefore
          # message: 'Date cannot be in the future'

I'll need to think further though, on which date constraints to
initially implement.

To compliment the CompoundJoin filter, I've also added a
CompoundSprintf filter. This effectively makes
Inflator::CompoundDateTime redundant.
An example of use might be:

elements:
  - type: Multi
    name: date

    - elements:
      - name: day
      - name: month
      - name: year

    - filters:
      - type: CompoundSprintf
        sprintf: '%02d-%02d-%04d'

    - constraints:
        type: DateTime
        parser: &PARSER
          strptime: '%d-%m-%Y'

    - inflators:
        type: DateTime
        parser: *PARSER

The benefit of this over Inflator::DateTime, is obviously that the
date is validated at 'constraint' time.

Carl



More information about the HTML-FormFu mailing list