File Coverage

blib/lib/Catalyst/Controller/FormBuilder.pm
Criterion Covered Total %
statement 15 41 36.5
branch 0 4 0.0
condition 0 17 0.0
subroutine 5 9 55.5
pod n/a
total 20 71 28.1


line stmt bran cond sub pod time code
1             package Catalyst::Controller::FormBuilder;
2              
3 1     1   30874 use strict;
  1         2  
  1         37  
4 1     1   6 use base qw/Catalyst::Controller/;
  1         3  
  1         770  
5 1     1   972 use MRO::Compat;
  1         3816  
  1         30  
6 1     1   7 use mro 'c3';
  1         2  
  1         7  
7              
8             our $VERSION = "0.06";
9              
10             __PACKAGE__->mk_accessors(qw/_fb_setup/);
11              
12             sub new {
13 0     0     my $class = shift;
14 0           my $self = $class->next::method(@_);
15 0           $self->__setup();
16 0           return $self;
17             }
18              
19             sub __setup {
20 0     0     my $self = shift;
21 0           my $class = ref $self;
22              
23 0   0       my $config = $self->config->{'Controller::FormBuilder'} || {};
24              
25 0   0       my $tmpl_type = $config->{template_type} || "TT";
26 0   0       my $method = $config->{method_name} || 'formbuilder';
27 0   0       my $action = $config->{action}
28             || "Catalyst::Controller::FormBuilder::Action::$tmpl_type";
29              
30 0   0       $self->_fb_setup(
      0        
      0        
      0        
31             {
32             method_name => $method,
33             stash_name => $config->{stash_name} || 'formbuilder',
34             obj_name => $config->{obj_name} || 'FormBuilder',
35             action => $action,
36             attr_name => $config->{attr_name} || 'Form',
37             source_type => $config->{source_type} || undef,
38             template_type => $tmpl_type,
39             }
40             );
41 1     1   199 no strict 'refs';
  1         2  
  1         256  
42 0           *{"$class\::$method"} = $class->make_accessor($method);
  0            
43             }
44              
45             sub _formbuilder {
46 0     0     my $self = shift;
47 0           my $method = $self->_fb_setup->{method_name};
48 0           $self->$method(@_);
49             }
50              
51             sub create_action {
52 0     0     my $self = shift;
53 0           my %args = @_;
54              
55 0           my $attr_name = $self->_fb_setup->{attr_name};
56              
57 0 0         if ( exists $args{attributes}{$attr_name} ) {
58 0           $args{_attr_params} = delete $args{attributes}{$attr_name};
59 0 0         if ( my $source_type = $self->_fb_setup->{source_type} ) {
60 0           $args{_source_type} = $source_type;
61             }
62 0           push @{ $args{attributes}{ActionClass} }, $self->_fb_setup->{action};
  0            
63             }
64              
65 0           $self->SUPER::create_action(%args);
66             }
67              
68             1;
69              
70             __END__
71              
72             # Copyright (c) 2006 Juan Camacho <formbuilder@suspenda.com>. All Rights Reserved.
73              
74             =head1 NAME
75              
76             Catalyst::Controller::FormBuilder - Catalyst FormBuilder Base Controller
77              
78             =head1 SYNOPSIS
79              
80             package MyApp::Controller::Books;
81             use base 'Catalyst::Controller::FormBuilder';
82              
83             # optional config setup
84             __PACKAGE__->config(
85             'Controller::FormBuilder' = {
86             template_type => 'HTML::Template', # default is 'TT' (e.g. TT2)
87             }
88             );
89              
90             # looks for books/edit.fb form configuration file, based on the presence of
91             # the ":Form" attribute.
92             sub edit : Local Form {
93             my ( $self, $c, @args ) = @_;
94              
95             my $form = $self->formbuilder;
96              
97             # add email form field to fields already defined edit.fb
98             $form->field( name => 'email', validate => 'EMAIL' );
99              
100             if ( $form->submitted ) {
101             if ( $form->validate ) {
102             return $c->response->body("VALID FORM");
103             }
104             else {
105             $c->stash->{ERROR} = "INVALID FORM";
106             $c->stash->{invalid_fields} =
107             [ grep { !$_->validate } $form->fields ];
108             }
109             }
110             }
111              
112             # explicitedly use books/edit.fb, otherwise books/view.fb is used
113             sub view : Local Form('/books/edit') {
114             my ( $self, $c ) = @_;
115             $c->stash->{template} = "books/edit.tt" # TT2 template;
116             }
117              
118             =cut
119              
120              
121             =head1 DESCRIPTION
122              
123             This base controller merges the functionality of B<CGI::FormBuilder> with
124             Catalyst and the following templating systems: Template Toolkit, Mason and
125             HTML::Template. This gives you access to all of FormBuilder's niceties,
126             such as controllablefield stickiness, multilingual support, and Javascript
127             generation. For more details, see L<CGI::FormBuilder> or the website at:
128              
129             http://www.formbuilder.org
130              
131             FormBuilder usage within Catalyst is straightforward. Since Catalyst handles
132             page rendering, you don't call FormBuilder's C<render()> method, as you
133             would normally. Instead, you simply add a C<:Form> attribute to each method
134             that you want to associate with a form. This will give you access to a
135             FormBuilder C<< $self->formbuilder >> object within that controller method:
136              
137             # An editing screen for books
138             sub edit : Local Form {
139             my ( $self, $c ) = @_;
140             $self->formbuilder->method('post'); # set form method
141             }
142              
143             The out-of-the-box setup is to look for a form configuration file that follows
144             the L<CGI::FormBuilder::Source::File> format (essentially YAML), named for the
145             current action url. So, if you were serving C</books/edit>, this plugin
146             would look for:
147              
148             root/forms/books/edit.fb
149              
150             (The path is configurable.) If no source file is found, then it is assumed
151             you'll be setting up your fields manually. In your controller, you will
152             have to use the C<< $self->formbuilder >> object to create your fields,
153             validation, and so on.
154              
155             Here is an example C<edit.fb> file:
156              
157             # Form config file root/forms/books/edit.fb
158             name: books_edit
159             method: post
160             fields:
161             title:
162             label: Book Title
163             type: text
164             size: 40
165             required: 1
166             author:
167             label: Author's Name
168             type: text
169             size: 80
170             validate: NAME
171             required: 1
172             isbn:
173             label: ISBN#
174             type: text
175             size: 20
176             validate: /^(\d{10}|\d{13})$/
177             required: 1
178             desc:
179             label: Description
180             type: textarea
181             cols: 80
182             rows: 5
183              
184             submit: Save New Book
185              
186             This will automatically create a complete form for you, using the
187             specified fields. Note that the C<root/forms> path is configurable;
188             this path is used by default to integrate with the C<TTSite> helper.
189              
190             Within your controller, you can call any method that you would on a
191             normal C<CGI::FormBuilder> object on the C<< $self->formbuilder >> object.
192             To manipulate the field named C<desc>, simply call the C<field()>
193             method:
194              
195             # Change our desc field dynamically
196             $self->formbuilder->field(
197             name => 'desc',
198             label => 'Book Description',
199             required => 1
200             );
201              
202             To populate field options for C<country>, you might use something like
203             this to iterate through the database:
204              
205             $self->formbuilder->field(
206             name => 'country',
207             options =>
208             [ map { [ $_->id, $_->name ] } $c->model('MyApp::Country')->all ],
209             other => 1, # create "Other:" box
210             );
211              
212             This would create a select list with the last element as "Other:" to allow
213             the addition of more countries. See L<CGI::FormBuilder> for methods
214             available to the form object.
215              
216             The FormBuilder methodolody is to handle both rendering and validation
217             of the form. As such, the form will "loop back" onto the same controller
218             method. Within your controller, you would then use the standard FormBuilder
219             submit/validate check:
220              
221             if ( $self->formbuilder->submitted && $self->formbuilder->validate ) {
222             $c->forward('/books/save');
223             }
224              
225             This would forward to C</books/save> if the form was submitted and
226             passed field validation. Otherwise, it would automatically re-render the
227             form with invalid fields highlighted, leaving the database unchanged.
228              
229             To render the form in your tt2 template for example, you can use C<render>
230             to get a default table-based form:
231              
232             <!-- root/src/books/edit.tt -->
233             [% FormBuilder.render %]
234              
235             You can also get fine-tuned control over your form layout from within
236             your template.
237              
238             =head1 TEMPLATES
239              
240             The simplest way to get your form into HTML is to reference the
241             C<FormBuilder.render> method, as shown above. However, frequently you
242             want more control.
243              
244             Only Template Toolkit, Mason and HTML::Template are currently supported, but
245             if your templating system's stash requirements are identical to one of these,
246             simply choose and define it via the C<template_type> config option. Of course,
247             make sure you have a View to support the template, since this module does not
248             render templates.
249              
250             From within your template, you can reference any of FormBuilder's
251             methods to manipulate form HTML, JavaScript, and so forth. For example,
252             you might want exact control over fields, rendering them in a C<< <div> >>
253             instead of a table. You could do something like this:
254              
255             <!-- root/src/books/edit.tt -->
256             <head>
257             <title>[% formbuilder.title %]</title>
258             [% formbuilder.jshead %]<!-- javascript -->
259             </head>
260             <body>
261             [% formbuilder.start -%]
262             <div id="form">
263             [% FOREACH field IN formbuilder.fields -%]
264             <p>
265             <label>
266             <span [% IF field.required %]class="required"[%END%]>[%field.label%]</span>
267             </label>
268             [% field.field %]
269             [% IF field.invalid -%]
270             <span class="error">
271             Missing or invalid entry, please try again.
272             </span>
273             [% END %]
274             </p>
275             [% END %]
276             <div id="submit">[% formbuilder.submit %]</div>
277             <div id="reset">[% formbuilder.reset %]</div>
278             </div>
279             </div>
280             [% formbuilder.end -%]
281             </body>
282              
283             In this case, you would B<not> call C<FormBuilder.render>, since that would
284             only result in a duplicate form (once using the above expansion, and
285             a second time using FormBuilder's default rendering).
286              
287             Note that the above form could become a generic C<form.tt> template
288             which you simply included in all your files, since there is nothing
289             specific to a given form hardcoded in (that's the idea, after all).
290              
291             You can also get some ideas based on FormBuilder's native Template Toolkit
292             support at L<CGI::FormBuilder::Template::TT2>.
293              
294             =head1 CONFIGURATION
295              
296             You can set defaults for your forms using Catalyst's config method inside
297             your controller.
298              
299             __PACKAGE__->config(
300             'Controller::FormBuilder' => {
301             new => {
302             method => 'post',
303             # stylesheet => 1,
304             messages => '/locale/fr_FR/form_messages.txt',
305             },
306             form_path =>
307             File::Spec->catfile( $c->config->{home}, 'root', 'forms' ),
308             method_name => 'form',
309             template_type => 'HTML::Template',
310             stash_name => 'form',
311             obj_name => 'FormBuilder',
312             form_suffix => 'fb',
313             attr_name => 'Form',
314             source_type => 'CGI::FormBuilder::Source::File',
315             }
316             );
317              
318             =over
319              
320             =item C<new>
321              
322             This accepts the exact same options as FormBuilder's C<new()> method
323             (which is a lot). See L<CGI::FormBuilder> for a full list of options.
324              
325             =item C<form_path>
326              
327             The path to configuration files. This should be set to an absolute
328             path to prevent problems. By default, it is set to:
329              
330             File::Spec->catfile( $c->config->{home}, 'root', 'forms' )
331              
332             This can be a colon-separated list of directories if you want to
333             specify multiple paths (ie, "/templates1:/template2"), or an array
334             ref (ie, [qw/template1 templates2/]).
335              
336             =item C<form_suffix>
337              
338             The suffix that configuration files have. By default, it is C<fb>.
339              
340             =item C<method_name>
341              
342             Accessor method name available in your controller. By default, it is
343             C<formbuilder>.
344              
345             =item C<template_type>
346              
347             Defines the Catalyst View that the stash will be prepared for. Possible
348             values are: HTML::Template, Mason, TT. By default, it is C<TT>.
349              
350             =item C<stash_name>
351              
352             Not applicable for HTML::Template view. By default, it is C<formbuilder>.
353             e.g. $c->stash->{formbuilder} = $formbuilder->prepare.
354              
355             =item C<obj_name>
356              
357             Not applicable for HTML::Template view. By default, it is C<FormBuilder>.
358             e.g. $c->stash->{FormBuilder} = $formbuilder.
359              
360             =item C<attr_name>
361              
362             The attribute name. By default, it is C<Form>.
363             e.g. sub edit : Form { ... }
364              
365             =item C<source_type>
366              
367             The source adapter class name. By default, it is
368             C<CGI::FormBuilder::Source::File>. See L<CGI::FormBuilder::Source>
369              
370             =back
371              
372             In addition, the following FormBuilder options are automatically set for you:
373              
374             =over
375              
376             =item C<action>
377              
378             This is set to the URL for the current action. B<FormBuilder> is designed
379             to handle a full request cycle, meaning both rendering and submission. If
380             you want to override this, simply use the C<< $self->formbuilder >> object:
381              
382             $self->formbuilder->action('/action/url');
383              
384             The default setting is C<< $c->req->path >>.
385              
386             =item C<cookies>
387              
388             Handling these are disabled (use Catalyst).
389              
390             =item C<debug>
391              
392             This is set to correspond with Catalyst's debug setting.
393              
394             =item C<header>
395              
396             This is disabled. Instead, use Catalyst's header routines.
397              
398             =item C<params>
399              
400             This is set to get parameters from Catalyst, using C<< $c->req >>.
401             To override this, use the C<< $self->formbuilder >> object:
402              
403             $self->formbuilder->params(\%param_hashref);
404              
405             Overriding this is not recommended.
406              
407             =item C<source>
408              
409             This determines which source file is loaded, to setup your form. By
410             default, this is set to the name of the action URL, with C<.fb> appended.
411             For example, C<edit_form()> would be associated with an C<edit_form.fb>
412             source file.
413              
414             To override this, include the path as the argument to the method attribute:
415              
416             sub edit : Local Form('/books/myEditForm') { }
417              
418             If no source file is found, then it is assumed you'll be setting up your
419             fields manually. In your controller, you will have to use the
420             C<< $self->formbuilder >> object to create your fields, validation, and so on.
421              
422             =back
423              
424             =head1 SEE ALSO
425              
426             L<CGI::FormBuilder>, L<CGI::FormBuilder::Source::File>,
427             L<CGI::FormBuilder::Template::TT2>, L<Catalyst::Manual>,
428             L<Catalyst::Request>, L<Catalyst::Response>
429              
430             =head1 AUTHOR
431              
432             Copyright (c) 2006 Juan Camacho <formbuilder@suspenda.com>. All Rights Reserved.
433              
434             Thanks to Laurent Dami and Roy-Magne Mo for suggestions.
435              
436             This library is free software, you can redistribute it and/or modify
437             it under the same terms as Perl itself.
438              
439             =cut
440