I've looked at Gerdas latest commit - defining the has_constraint method. Initially I did not like it - as it creates another layer of indirection - but now I think it can nicely fit together with Filters.
Here is my API proposal:
So here we have one simple text field that is required to contain the string 'aaa' - this is the simple case. Then we have a number that needs to be greater than 10, but also it is being saved to the database as a string formatted with up to 8 leading zeros. And the most complex one is a DateTime field with three subfields for the year, month and day. It is saved to the database as a DateTime object, and the user is allowed to enter only dates that are Mondays. This example shows how this complex requirement is relatively easily declared using this API. One important note here is that the Compound field assembles the values of the sub-fields into a hash - and that hash is then passed to the filter as the parameter. This should be convenient for all subs with named parameters and in particular to object creators for inflation. And if the inflation fails then the error message is used.package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; use DateTime; has_constraint 'contains_aaa' => ( action => qr/aaa/, message => 'Must contain aaa' ); has_constraint 'greater_than_10' => ( action => sub { return $_[0] > + 10 } }, message => 'must be greater than 10' ); has_filter 'eight_leading_zeros' => ( action => sub{ printf("%08d", _[0] ) } ); has_constraint 'only_mondays' => ( action => sub { $_[0]->day_of_week eq 'Monday' }, message => 'Only Mondays' ); has_filter 'date_time' => ( action => sub{ DateTime->new( $_[0] ) }, message => 'Incorrect Date' ); has_field 'some_text' => ( actions => [ 'contains_aaa' ] ); has_field 'number' => ( actions => [ 'greater_than_10', 'eight_leading_zeros' ] ); has_field 'date_time' => ( type => 'Compound', actions => [ 'date_time', 'only_mondays' ], ); has_field 'date_time.year'; has_field 'date_time.month'; has_field 'date_time.day';
The main point above is that with named filters and constraints the programmer can weave them together in whatever order he needs and is not constrained by the order defined by the library (like in FormFu - where there is a specific order of applying the different actions).
I am not sure about the names - transformations would be more appropriate than filters but also two times longer. Any proposals?
To save some typing (and reading) we also could use positional declarations instead of named:
has_constraint 'contains_aaa' => ( qr/aaa/, 'Must contain aaa' );
Update: The alternative:
Shorter - but more identation - which one would you chose?package Test::Form; use HTML::FormHandler::Moose; extends 'HTML::FormHandler'; use DateTime; has_field 'some_text' => ( actions => [ { check => qr/aaa/, message => 'Must contain aaa' } ] ); has_field 'number' => ( actions => [ { check => sub { return $_[0] > 10 }, message => 'must be greater than 10' }, { transformation => sub{ printf("%08d", _[0] ) } }, ] ); has_field 'date_time' => ( type => 'Compound', actions => [ { transformation => sub{ DateTime->new( $_[0] ) }, message => 'Incorrect Date' }, { check => sub { $_[0]->day_of_week eq 'Monday' }, message => 'Only Mondays' }, ], ); has_field 'date_time.year'; has_field 'date_time.month'; has_field 'date_time.day';