File Coverage

blib/lib/Catalyst/Plugin/Form/Processor.pm
Criterion Covered Total %
statement 1 3 33.3
branch n/a
condition n/a
subroutine 1 1 100.0
pod n/a
total 2 4 50.0


line stmt bran cond sub pod time code
1             package Catalyst::Plugin::Form::Processor;
2             $Catalyst::Plugin::Form::Processor::VERSION = '1.140270';
3 1     1   25320 use Moose::Role;
  0            
  0            
4             use Class::Load 0.20;
5             use HTML::FillInForm;
6             use Module::Find;
7             use Scalar::Util;
8              
9              
10              
11              
12             # ABSTRACT: Use Form::Processor with Catalyst
13              
14              
15             sub form {
16             my ( $c, $args_ref, $form_name ) = @_;
17              
18              
19             # Determine the form package name
20             my $package;
21             if ( defined $form_name ) {
22              
23             $package
24             = $form_name =~ s/^\+//
25             ? $form_name
26             : ref( $c ) . '::Form::' . $form_name;
27             }
28             else {
29             $package = $c->action->class;
30             $package =~ s/::C(?:ontroller)?::/::Form::/;
31             $package .= '::' . ucfirst( $c->action->name );
32             }
33              
34             Class::Load::load_class( $package );
35              
36              
37             # Single argument to Form::Processor->new means it's an item id or object.
38             # Hash references must be turned into lists.
39              
40             my %args;
41             if ( defined $args_ref ) {
42             if ( ref $args_ref eq 'HASH' ) {
43             %args = %{$args_ref};
44             }
45             elsif ( Scalar::Util::blessed( $args_ref ) ) {
46             %args = (
47             item => $args_ref,
48             item_id => $args_ref->id,
49             );
50             }
51             else {
52             %args = ( item_id => $args_ref );
53             }
54             }
55              
56             # Set schema name -- mostly for DBIC
57              
58             if ( $package->can( 'schema' ) ) {
59             unless ( exists $args{schema} ) {
60             my $schema_name = $c->config->{form}{model_name}
61             || $c->stash->{model_name};
62              
63              
64             $args{schema} = $c->model( $schema_name )->schema
65             if defined $schema_name;
66             }
67             }
68              
69             $args{user_data}{context} = $c;
70              
71             # Since $c holds a reference to the form and the form holds
72             # a reference to the context must weaken.
73             Scalar::Util::weaken( $args{user_data}{context} );
74              
75              
76             return $c->stash->{form} = $package->new( %args );
77              
78             } ## end sub form
79              
80              
81              
82             sub validate_form {
83             my ( $c, @rest ) = @_;
84              
85             my $form = $c->form( @rest );
86              
87             return
88             $c->form_posted
89             && $form->validate( $c->req->parameters );
90              
91             }
92              
93              
94              
95              
96             sub update_from_form {
97             my ( $c, @rest ) = @_;
98              
99             my $form = $c->form( @rest ) || return;
100              
101             return
102             $c->form_posted
103             && $form->update_from_form( $c->req->parameters );
104              
105             }
106              
107              
108             sub form_posted {
109             my $c = shift;
110              
111             return $c->req->method eq 'POST' || $c->req->method eq 'PUT';
112             }
113              
114              
115             # Used to override finalize, but that's not called in a redirect.
116             # TODO: add support for multiple forms on a page (and multiple forms
117             # in the stash).
118             #
119             # And better, simply remove this.
120              
121             before 'finalize' => sub {
122             my $c = shift;
123              
124              
125             my $form = $c->stash->{form} || return;
126              
127              
128             # Disabled in configuration
129             return if $c->config->{form}{no_fillin};
130              
131              
132             return if $c->res->status != 200;
133              
134             my $params = $form->fif;
135              
136             return unless ref $params && %{$params};
137              
138             return unless defined $c->response->{body};
139              
140             $c->log->debug( 'Filling in form with HTML::FillInForm' ) if $c->debug;
141              
142              
143             # Run FillInForm
144             $c->response->output(
145             HTML::FillInForm->new->fill(
146             scalarref => \$c->response->{body},
147             fdat => $params,
148             ) );
149              
150             return;
151              
152             };
153              
154              
155             after 'setup_finalize' => sub {
156             my $c = shift;
157              
158             my $config = $c->config->{form} || {};
159              
160             return unless $config->{pre_load_forms};
161              
162             my $debug = $config->{debug};
163              
164             my $name_space = $c->config->{form_name_space} || $c->config->{name} . '::Form';
165             my @namespace = ref $name_space eq 'ARRAY' ? @{$name_space} : ( $name_space );
166              
167              
168             for my $ns ( @namespace ) {
169             warn "Searching for forms in the [$ns] namespace\n" if $debug;
170              
171             for my $form ( Module::Find::findallmod( $ns ) ) {
172              
173             warn "Loading form module [$form]\n" if $debug;
174              
175             Class::Load::load_class( $form );
176              
177             # Should we pre-load the form's fields by attempting
178             # to init the form? May fail if the profile method
179             # assumes it is running per request instead of at load time.
180              
181             next unless $config->{pre_load_fields};
182              
183             eval { $form->load_form; 1 }
184             || die "Failed load_module for form module [$form]: $@";
185             }
186             }
187              
188             return;
189             };
190              
191              
192              
193              
194             no Moose::Role;
195              
196             1;
197              
198              
199              
200              
201              
202              
203             __END__
204             =pod
205              
206             =head1 NAME
207              
208             Catalyst::Plugin::Form::Processor - Use Form::Processor with Catalyst
209              
210             =head1 VERSION
211              
212             version 1.140270
213              
214             =head1 SYNOPSIS
215              
216             In the Catalyst application base class:
217              
218             use Catalyst;
219              
220             with 'Catalyst::Plugin::Form::Processor';
221              
222             __PACKAGE__->config->{form} = {
223             no_fillin => 1, # Don't auto-fill forms with HTML::FillInForm
224             pre_load_forms => 1, # Try and load forms at setup time
225             form_name_space => 'My::Forms',
226             debug => 1, # Show forms pre-loaded.
227             schema_class => 'MyApp::DB',
228             };
229              
230             Then in a controller:
231              
232             package App::Controller::User;
233             use strict;
234             use warnings;
235             use base 'Catalyst::Controller';
236              
237             # Create or edit
238             sub edit : Local {
239             my ( $self, $c, $user_id ) = @_;
240              
241             # Validate and insert/update database
242             return unless $c->update_from_form( $user_id );
243              
244             # Form validated.
245              
246             $c->stash->{first_name} = $c->stash->{form}->value( 'first_name' );
247             }
248              
249             # Form that doesn't update database
250             sub profile : Local {
251             my ( $self, $c ) = @_;
252              
253             # Redisplay form
254             return unless $c->validate_form;
255              
256             # Form validated.
257              
258             $c->stash->{first_name} = $c->stash->{form}->value( 'first_name' );
259             }
260              
261              
262             # Use HTML::FillInForm to populate a form:
263             $c->stash->{fillinform} = $c->req->parameters;
264              
265             =head1 DESCRIPTION
266              
267             "This distribution should not exist" - https://rt.cpan.org/Ticket/Display.html?id=40733
268              
269             This plugin adds methods to make L<Form::Processor> easy to use with Catalyst.
270             The plugin uses the current action name to find the form module, creates the
271             form object and stuffs it into the stash, and passes the Catalyst request
272             parameters to the form for validation.
273              
274             The method C<< $c->update_from_form >> is used when the form inherits from a
275             Form::Processor model class (e.g. L<Form::Processor::Model::CDBI>) which will
276             load a form's current values from a database and update/create rows in the
277             database from a posted form.
278              
279             C<< $c->validate_form >> simply validates the form and you must then decide
280             what to do with the validated data. This is useful when the posted data
281             will be used for something other than updating a row in a database.
282              
283             The C<< $c->form >> method will create an instance of your form class.
284             Both C<< $c->update_from_form >> and C<< $c->validate_form >> call this method
285             to load the form for you. So, you generally don't need to call this directly.
286              
287             Forms are assumed to be in the $App::Form name space. But, that's just
288             the default. This can be overridden with the C<form_name_space> option.
289              
290             The form object is stored in the stash as C<< $c->stash->{form} >>. Templates
291             can use this to access for form.
292              
293             In addition, this Plugin use HTML-FillInForm to populate the form. Typically,
294             this data will come automatically form the current values in the form object,
295             but can be overridden by populating the stash with a hash reference:
296              
297             $c->stash->{fillinform} = $c->req->parameters;
298              
299             Note that this can also be used to populate forms not managed by Form::Processor.
300             Currently, only one form per page is supported.
301              
302             =head1 METHODS
303              
304             =head2 form ( $item_or_args_ref, $form_name );
305              
306             $form = $c->form;
307             $form = $c->form( $user_id );
308             $form = $c->form( $args_ref );
309             $form = $c->form( $args_ref, $form_name );
310              
311             Generates a form object, populates the stash "form" and returns the
312             form object. This method is typically not used. Use
313             L<update_from_form> or L<validate_form> instead.
314              
315             The form will be require()ed at run time so the form does not need to be
316             explicitly loaded by your application. The form is expected to be in the
317             App::Form name space, but that can be overridden.
318              
319             But, it might be worth loading the modules at compile time if you
320             have a lot of modules to save on memory (e.g. under mod_perl).
321             See L</pre_load_forms> below.
322              
323             The Catalyst context (C<$c>) is made available to the form
324             via the form's user data attribute. In the form you may do:
325              
326             my $c = $form->user_data->{context};
327              
328             Pass:
329             $item_or_args_ref. This can be
330             scalar:
331             it will be assumed to be the id of the row to edit
332             hash ref:
333             assumed to be a list of options and will be passed
334             as a list to Form::Processor->new.
335             object:
336             and will be set as the item and item_id is set by
337             calling the "id" method on this object. If id
338             is not the correct method then pass a hash reference
339             instead.
340              
341             If $form_name is not provided then will use the current controller
342             class and the action for the form name. If $form_name is defined then
343             it is appended to C<$App::Form::>. A plus sign can be included
344             to avoid prefixing the form name.
345              
346              
347             package MyApp::Controller::Foo::Bar
348             sub edit : Local {
349              
350             # MyAPP::Form::Foo::Bar::Edit->new
351             # Note the upper case -- ucfirst is used
352             my $form = $c->form;
353              
354             # MyAPP::Form::Login::User->new
355             my $form = $c->form( $args_ref, 'Login::User' );
356              
357             # External form Other::Form->new
358             my $form = $c->form( $args_ref, '+Other::Form' );
359              
360             Returns:
361             Sets $c->{form} by calling new on the form object.
362             That value is also returned.
363              
364             =head2 validate_form
365              
366             return unless $c->validate_form;
367              
368             This method passes the request parameters to
369             the form's C<validate> method and returns true
370             if all fields validate.
371              
372             This is the method to use if you are not using
373             a Form::Processor::Model class to automatically
374             update or insert a row into the database.
375              
376             =head2 update_from_form
377              
378             This combines common actions on CRUD tables.
379             It replaces, say:
380              
381             my $form = $c->form( $item );
382              
383             return unless $c->form_posted
384             && $form->update_from_form( $c->req->parameters );
385              
386             with
387              
388             $c->update_from_form( $item )
389              
390             For this to work your form should inherit from a Form::Processor::Model
391             class (e.g. see L<Form::Processor::Model::CDBI>), or your form must
392             have an C<update_from_form()> method (which calls validate).
393              
394             =head2 form_posted
395              
396             This returns true if the request was a post request.
397             This could be replace with a method that does more extensive
398             checking, such as validating a form token to prevent double-posting
399             of forms.
400              
401             =head2 finalize
402              
403             Automatically fills in a form if $form variable is found.
404             This can be disabled by setting
405              
406             $c->config->{form}{no_fillin};
407              
408             =head2 setup
409              
410             If the C<pre_load_forms> configuration options is set will search for forms in
411             the name space provided by the C<form_name_space> configuration list or by
412             default the application name space with the suffix ::Form appended (e.g.
413             MyApp::Form).
414              
415             =head1 EXTENDED METHODS
416              
417             =head1 CONFIGURATION
418              
419             Configuration is specified within C<< MyApp->config->{form}} >>.
420             The following options are available:
421              
422             =over 4
423              
424             =item no_fillin
425              
426             Don't use use L<HTML::FillInForm> to populate the form data.
427              
428             =item pre_load_forms
429              
430             It this is true then will pre-load all modules in the MyApp::Form name space
431             during setup. This works by requiring the form module and loading associated
432             form fields. The form is not initialized so any fields dynamically loaded may
433             not be included.
434              
435             This is useful in a persistent environments like mod_perl or FastCGI.
436              
437             =item form_name_space
438              
439             This is a list of name spaces where to look for forms to pre load. It defaults
440             to the application name with the ::Form suffix (e.g. MyApp::Form). Note, this
441             DOES NOT currently change where C<< $c->form >> looks for form modules.
442             Not quite sure why that's not implemented yet.
443              
444             =item model_name
445              
446             Defines the default model class. To play nicely with
447             L<Form::Processor::Model::DBIC> will set "schema" option when
448             creating a new Form if this value is set.
449              
450             Basically does:
451              
452             $schema = $c->model( $model_name )->schema;
453              
454             Can be overridden by a stash element of the same name.
455              
456             =item debug
457              
458             If true will write brief debugging information when running setup.
459              
460             =back
461              
462             =head1 See also
463              
464             L<Form::Processor>
465              
466             L<Form::Processor::Model::CDBI>
467              
468             =head1 AUTHOR
469              
470             Bill Moseley <mods@hank.org>
471              
472             =head1 COPYRIGHT AND LICENSE
473              
474             This software is copyright (c) 2012 by iParadigms, LLC..
475              
476             This is free software; you can redistribute it and/or modify it under
477             the same terms as the Perl 5 programming language system itself.
478              
479             =cut
480