Skip Menu |

This queue is for tickets about the Data-FormValidator CPAN distribution.

Maintainer(s)' notes

This is the bug queue for Data::FormValidator.

Report information
The Basics
Id: 13226
Status: resolved
Priority: 0/
Queue: Data-FormValidator

People
Owner: MARKSTOS [...] cpan.org
Requestors: m.romani [...] spinsoft.it
Cc:
AdminCc:

Bug Information
Severity: Wishlist
Broken in: (no value)
Fixed in: (no value)



Subject: Patch to handle coderefs in defaults
Using this patch I can write something like: $input_profile->{defaults} = { creation_date => sub { require Time::Piece; my $now = Timie::Piece->new(); return $now->ymd; } } and have the 'creation_date' filled with current date left blank.
262c262,269 < $valid{$field} = $value unless exists $valid{$field}; --- > #$valid{$field} = $value unless exists $valid{$field}; > unless(exists $valid{$field}) { > if (ref($value) && ref($value) eq "CODE") { > $valid{$field} = $value->(); > } else { > $valid{$field} = $value; > } > }
[guest - Mon Jun 13 12:11:47 2005]: Show quoted text
> Using this patch I can write something like: > > $input_profile->{defaults} = { > creation_date => sub { > require Time::Piece; > my $now = Timie::Piece->new(); > return $now->ymd; > } > } > > and have the 'creation_date' filled with current date if left blank.
RT-Send-CC: cascade-dataform [...] lists.sourceforge.net
[guest - Mon Jun 13 12:11:47 2005]: Show quoted text
> Using this patch I can write something like: > > $input_profile->{defaults} = { > creation_date => sub { > require Time::Piece; > my $now = Timie::Piece->new(); > return $now->ymd; > } > } > > and have the 'creation_date' filled with current date left blank.
I will accept this feature addition. Could you also add a test for it and update the docs and Changes files as well? I'm CC'ing the mailing list against someone else wants to contribute that work as well. Otherwise, I'll get to it eventually myself. Stalling ticket for feedback. Mark
From: mromani
[MARKSTOS - Sun Jul 3 15:29:20 2005]: Show quoted text
> [guest - Mon Jun 13 12:11:47 2005]: >
> > Using this patch I can write something like: > > > > $input_profile->{defaults} = { > > creation_date => sub { > > require Time::Piece; > > my $now = Timie::Piece->new(); > > return $now->ymd; > > } > > } > > > > and have the 'creation_date' filled with current date left blank.
> > I will accept this feature addition. Could you also add a test for it > and update the docs and Changes files as well? I'm CC'ing the mailing > list against someone else wants to contribute that work as well. > > Otherwise, I'll get to it eventually myself. > > Stalling ticket for feedback. > > Mark >
I have written a simple addition to 25_results.t, and while doing that I realized it might be useful to pass $field as an argument to the coderef. So here are the new Restuls.pm patch and the 25_results.t patch: -------------------- 25_results.t ------------------ 1c1 < use Test::More tests => 4; --- Show quoted text
> use Test::More tests => 6;
13c13 < required => 'stick', --- Show quoted text
> required => [ 'stick', 'fromsub', 'whoami' ],
15c15,18 < --- Show quoted text
> defaults => { > fromsub => sub { return "got value from a subroutine"; }, > whoami => sub { my $me = shift; return "I am field $me"; }, > },
29c32,33 < --- Show quoted text
> ok($results->valid('fromsub') eq "got value from a subroutine", 'usg
CODE references as default values'); Show quoted text
> ok($results->valid('whoami') eq "I am field whoami", 'usg CODE
references as default values'); ~ ~ -------------------- Results.pm ------------------ 262c262,268 < $valid{$field} = $value unless exists $valid{$field}; --- Show quoted text
> unless(exists $valid{$field}) { > if (ref($value) && ref($value) eq "CODE") { > $valid{$field} = $value->($field); > } else { > $valid{$field} = $value; > } > }
I'll post a patch to the docs ASAP.
1c1 < use Test::More tests => 4; --- > use Test::More tests => 6; 13c13 < required => 'stick', --- > required => [ 'stick', 'fromsub', 'whoami' ], 15c15,18 < --- > defaults => { > fromsub => sub { return "got value from a subroutine"; }, > whoami => sub { my $me = shift; return "I am field $me"; }, > }, 29c32,33 < --- > ok($results->valid('fromsub') eq "got value from a subroutine", 'usg CODE references as default values'); > ok($results->valid('whoami') eq "I am field whoami", 'usg CODE references as default values');
Added a couple lines to Changes: 0a1,4 Show quoted text
> 3.64 > [ENHANCEMENTS] > - support for coderefs as default values >
The feature is mentioned in the docs, with a simple example: --------------------- FormValidator.pm -------------------- 477a478,482 Show quoted text
> creation_date => sub { > require Time::Piece; > my $now = Timie::Piece->new(); > return $now->ymd; > }
482a488,492 Show quoted text
> If the default value is a coderef, its return value will be used. > This can be useful if you want the default value to be the current date, > the number of items in a database table, etc. > The only parameter that gets passed to the code is the field name. >
477a478,482 > creation_date => sub { > require Time::Piece; > my $now = Timie::Piece->new(); > return $now->ymd; > } 482a488,492 > If the default value is a coderef, its return value will be used. > This can be useful if you want the default value to be the current date, > the number of items in a database table, etc. > The only parameter that gets passed to the code is the field name. >
Date: Tue, 5 Jul 2005 08:07:04 -0500
From: Mark Stosberg <mark [...] summersault.com>
To: Guest via RT <bug-Data-FormValidator [...] rt.cpan.org>
CC: cascade-dataform [...] lists.sourceforge.net
Subject: Re: [cpan #13226] Patch to handle coderefs in defaults
RT-Send-Cc:
Thanks for the patch allowing us to use coderefs to set default values! Show quoted text
> I have written a simple addition to 25_results.t, and while doing that I > realized it might be useful to pass $field as an argument to the > coderef.
This is an interesting thought, and in line with how constraints work. But it leads me to consider another design niggle. We also have 'constraint_methods', which take the DFV object as the input. That allows you access the current field name, as well as much more. With that approach some could set a default based on current value of other CGI fields. See here for the methods that are most useful for this: http://search.cpan.org/~markstos/Data-FormValidator-3.63/lib/Data/FormValidator/Constraints.pm#WRITING_YOUR_OWN_CONSTRAINT_ROUTINES Unless there are objections from the list, I think I will go the route of passing the DFV object instead of the field name. My reasoning is that the common simple case, neither will be needed (such as your own Time::Piece example). Even for a case when you need the field name, it's a /static/ value. So to write a default routine for a single field, you can just write "field_name" in your routine, because you know what it is. I think that leaves a minority of cases which will actually be more complex. In that case we might as well give them the full power of the DFV object instead figuring out a way to graft that feature on later when someone asks for it. Let's see if there are any other opinions from the list before proceeding. Mark Show quoted text
> So here are the new Restuls.pm patch and the 25_results.t patch: > > -------------------- 25_results.t ------------------ > 1c1 > < use Test::More tests => 4; > ---
> > use Test::More tests => 6;
> 13c13 > < required => 'stick', > ---
> > required => [ 'stick', 'fromsub', 'whoami' ],
> 15c15,18 > < > ---
> > defaults => { > > fromsub => sub { return "got value from a subroutine"; }, > > whoami => sub { my $me = shift; return "I am field $me"; }, > > },
> 29c32,33 > < > ---
> > ok($results->valid('fromsub') eq "got value from a subroutine", 'usg
> CODE references as default values');
> > ok($results->valid('whoami') eq "I am field whoami", 'usg CODE
> references as default values'); > ~ > ~ > > > > -------------------- Results.pm ------------------ > 262c262,268 > < $valid{$field} = $value unless exists $valid{$field}; > ---
> > unless(exists $valid{$field}) { > > if (ref($value) && ref($value) eq "CODE") { > > $valid{$field} = $value->($field); > > } else { > > $valid{$field} = $value; > > } > > }
> > > I'll post a patch to the docs ASAP.
-- http://mark.stosberg.com/
[mark@summersault.com - Tue Jul 5 09:07:20 2005]: Show quoted text
> > Thanks for the patch allowing us to use coderefs to set default > values! >
> > I have written a simple addition to 25_results.t, and while doing
> that I
> > realized it might be useful to pass $field as an argument to the > > coderef.
> > This is an interesting thought, and in line with how constraints work. > But it leads me to consider another design niggle. We also have > 'constraint_methods', which take the DFV object as the input. > > That allows you access the current field name, as well as much more. > With that approach some could set a default based on current value of > other CGI fields. > > See here for the methods that are most useful for this: > http://search.cpan.org/~markstos/Data-FormValidator- >
3.63/lib/Data/FormValidator/Constraints.pm#WRITING_YOUR_OWN_CONSTRAINT_ROUTINES Show quoted text
> > Unless there are objections from the list, I think I will go the route > of > passing the DFV object instead of the field name. My reasoning is that > the > common simple case, neither will be needed (such as your own > Time::Piece example).
Yes, it makes much more sense to pass the whole DFV object instead of just a small portion of information (e.g. the field name). In fact I didn't need any extra information (as per my example) so I included the field name just as a simple addition to write a slightly more complex test.
Date: Tue, 5 Jul 2005 10:16:33 -0500
From: Mark Stosberg <mark [...] summersault.com>
To: Guest via RT <bug-Data-FormValidator [...] rt.cpan.org>
Subject: Re: [cpan #13226] Patch to handle coderefs in defaults
RT-Send-Cc:
On Tue, Jul 05, 2005 at 10:07:10AM -0400, Guest via RT wrote: Show quoted text
> > Yes, it makes much more sense to pass the whole DFV object instead of > just a small portion of information (e.g. the field name). > In fact I didn't need any extra information (as per my example) so I > included the field name just as a simple addition to write a slightly > more complex test.
Would you mind making that refinement in your patch then? I'll get to it soon anyway if you don't since you've graciously done most of the work already. Mark
[mark@summersault.com - Tue Jul 5 11:16:50 2005]: Show quoted text
> On Tue, Jul 05, 2005 at 10:07:10AM -0400, Guest via RT wrote:
> > > > Yes, it makes much more sense to pass the whole DFV object instead
> of
> > just a small portion of information (e.g. the field name). > > In fact I didn't need any extra information (as per my example) so I > > included the field name just as a simple addition to write a
> slightly
> > more complex test.
> > Would you mind making that refinement in your patch then? > > I'll get to it soon anyway if you don't since you've graciously done > most of the work already.
Don't we need something in the lines of __CURRENT_CONSTRAINT_FIELD, something like __CURRENT_DEFAULT_FIELD and a method like current_default_field() ? (Please correct me if I misunderstood your code). Show quoted text
> > Mark
Marcello
Date: Sun, 10 Jul 2005 19:30:31 -0500
From: Mark Stosberg <mark [...] summersault.com>
To: Guest via RT <bug-Data-FormValidator [...] rt.cpan.org>
Subject: Re: [cpan #13226] Patch to handle coderefs in defaults
RT-Send-Cc:
On Wed, Jul 06, 2005 at 08:17:07AM -0400, Guest via RT wrote: Show quoted text
> > This message about Data-FormValidator was sent to you by guest <> via rt.cpan.org > > Full context and any attached attachments can be found at: > <URL: https://rt.cpan.org/Ticket/Display.html?id=13226 > > > [mark@summersault.com - Tue Jul 5 11:16:50 2005]: >
> > On Tue, Jul 05, 2005 at 10:07:10AM -0400, Guest via RT wrote:
> > > > > > Yes, it makes much more sense to pass the whole DFV object instead
> > of
> > > just a small portion of information (e.g. the field name). > > > In fact I didn't need any extra information (as per my example) so I > > > included the field name just as a simple addition to write a
> > slightly
> > > more complex test.
> > > > Would you mind making that refinement in your patch then? > > > > I'll get to it soon anyway if you don't since you've graciously done > > most of the work already.
> > Don't we need something in the lines of __CURRENT_CONSTRAINT_FIELD, > something like __CURRENT_DEFAULT_FIELD and a method like > current_default_field() ?
Can't we make a first cut without it, just to keep things simple. It seems to me it would only be necessary if you wrote a default-settor that changed it's behavior based on the name of the field. Seems uncommon. With constraints, somes you might want "field" to refer to "field_value", making it more necessary there. I'm not opposed to the idea, I just want to make sure it will get used. Mark -- http://mark.stosberg.com/
[mark@summersault.com - Sun Jul 10 20:30:22 2005]: Show quoted text
> On Wed, Jul 06, 2005 at 08:17:07AM -0400, Guest via RT wrote:
> > > > This message about Data-FormValidator was sent to you by guest <>
> via rt.cpan.org
> > > > Full context and any attached attachments can be found at: > > <URL: https://rt.cpan.org/Ticket/Display.html?id=13226 > > > > > [mark@summersault.com - Tue Jul 5 11:16:50 2005]: > >
> > > On Tue, Jul 05, 2005 at 10:07:10AM -0400, Guest via RT wrote:
> > > > > > > > Yes, it makes much more sense to pass the whole DFV object
> instead
> > > of
> > > > just a small portion of information (e.g. the field name). > > > > In fact I didn't need any extra information (as per my example)
> so I
> > > > included the field name just as a simple addition to write a
> > > slightly
> > > > more complex test.
> > > > > > Would you mind making that refinement in your patch then? > > > > > > I'll get to it soon anyway if you don't since you've graciously
> done
> > > most of the work already.
> > > > Don't we need something in the lines of __CURRENT_CONSTRAINT_FIELD, > > something like __CURRENT_DEFAULT_FIELD and a method like > > current_default_field() ?
> > Can't we make a first cut without it, just to keep things simple. It > seems to me it would only be necessary if you wrote a default-settor > that > changed it's behavior based on the name of the field. Seems uncommon.
You're right. I should have been more clear perhaps. My question was: if I pass the whole DFV object instead of the field name, how can I access (potential) useful informations such as the field name, etc. provided by the DFV object ? It seemed to me this was similar to the constraints part, so I looked at the code and thought that a similar method could be used here. Show quoted text
> > With constraints, somes you might want "field" to refer to > "field_value", making it more necessary there. > > I'm not opposed to the idea, I just want to make sure it will get > used. > > Mark
Since the motivation behind passing the field name to the coderef did not arise from practical needs, I think we should just KIS for now and go with the first version of the patch.
Date: Sat, 13 Aug 2005 10:53:25 -0500
From: Mark Stosberg <mark [...] summersault.com>
To: Guest via RT <bug-Data-FormValidator [...] rt.cpan.org>
Subject: Fwd: Re: [cpan #13226] sample code from Cees.
RT-Send-Cc:
Cees has provided the code for this feature, below. I recommended naming it 'summarize_errors' and otherwise dropping it into Results.pm with light changes. Cees has even helped to document it. :) It should just need some simple tests and it's ready to go. Mark ----- Forwarded message from Cees Hek <ceeshek@gmail.com> ----- Date: Sat, 13 Aug 2005 11:19:55 -0400 From: Cees Hek <ceeshek@gmail.com> To: Mark Stosberg <mark@summersault.com> Subject: Re: DFV template integration request for code sub summarize_form_errors { my $self = shift; my $results = shift; my $errors = {}; # get 'invalid' elements as a hashref, and then convert any arrayrefs to hashrefs $errors->{invalid} = $results->invalid; foreach my $invalid ( keys %{ $errors->{invalid} } ) { if ( ref $errors->{invalid}->{$invalid} eq 'ARRAY' ) { $errors->{invalid}->{$invalid} = { map { $_ => 1 } @{ $errors->{invalid}->{$invalid} } }; } } # get 'missing' elements and convert to hashref $errors->{missing} = { map { $_ => 1 } $results->missing }; return $errors; } It is pretty simple really. Calling invalid gets us a hashref already, but when you have multiple constraints, it is nice to know the name of those constraints that failed as well, so if we have an arrayref, we just map it to a hash. And calling missing gets us a simple array which we convert to a hash. I return the entire thing as a hashref containing the keys 'invalid' and 'missing', but that could be separated out easily. Then in the templates I call [% IF errors.missing.first_name %]...[% END %]. And for invalid, I sometimes have constraints that look something like this: email => [ { name => 'exists', constraint => sub { ! Users->search( email => $_[0] )->first }, }, { name => 'length', constraint => max_length(200), } ], Which makes sure we don't get duplicate email accounts and keeps the length to a max of 200 characters. Then in the template I can access them like this: [% errors.invalid.email.exists %]This email address is already registered[% END %] [% errors.invalid.email.length %]The email address is too long[% END %] [% errors.missing.email %]The email field is a required field[% END %] As for an API into D::FV that generates the results like this. That is a tough one. It is not that far off what is already returned. We are just returning a hashes for everything, instead of arrays. The easiest might be to pull an idea from DBI with the fetchall_arrayref({}) which will return hashes instead of arrays. So a call to $results->invalid would remain the same, but $results->invalid({}) returns the new hash only form. The same could work for missing. It is a bit magical though, so it might be better to pass in a named parameter directly, or to provide new methods for it. It's really up to you what you like. Cheers, Cees Show quoted text
----- End forwarded message ----- -- http://mark.stosberg.com/