File Coverage

lib/Form/Sensible.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 Form::Sensible;
2              
3 15     15   709869 use Moose;
  0            
  0            
4             use namespace::autoclean;
5             use Class::MOP;
6             use Form::Sensible::Form;
7             use Form::Sensible::Field;
8             use Form::Sensible::Field::DateTime;
9             use Form::Sensible::Field::Number;
10             use Form::Sensible::Field::Select;
11             use Form::Sensible::Field::Text;
12             use Form::Sensible::Field::LongText;
13             use Form::Sensible::Field::Toggle;
14             use Form::Sensible::Field::Trigger;
15             use Form::Sensible::Field::SubForm;
16             use Form::Sensible::Validator;
17             use Form::Sensible::Validator::Result;
18             use Form::Sensible::DelegateConnection;
19              
20             our $VERSION = "0.20023";
21              
22             Moose::Exporter->setup_import_methods(
23             also => [ 'Form::Sensible::DelegateConnection' ]
24             );
25              
26             around BUILDARGS => sub {
27             my $orig = shift;
28             my $class = shift;
29            
30             ## this is somewhat odd, but it's a lot easier to track down with this error
31             ## than getting back an empty Form::Sensible object.
32            
33             if ($#_ == 0 && ref($_[0]) && exists($_[0]->{'fields'})) {
34             die "Invalid call to Form::Sensible->new() !! Form::Sensible is not meant to be instantiated. You probably meant to call create_form()";
35             } else {
36             return $class->$orig(@_);
37             }
38             };
39              
40             ## This module is a simple factory class which will load and create the various
41             ## types of modules required when working with Form::Sensible
42              
43             sub create_form {
44             my ($class, $template) = @_;
45            
46             my $formhash = { %{$template} };
47             delete($formhash->{'fields'});
48             delete($formhash->{'field_order'});
49            
50             my $form = Form::Sensible::Form->new(%{$formhash});
51            
52             if (ref($template->{'fields'}) eq 'ARRAY') {
53             foreach my $field (@{$template->{'fields'}}) {
54             $form->add_field($field, $field->{name});
55             #Form::Sensible::Field->create_from_flattened($field);
56             #$form->add_field($newfield, $newfield->name);
57             }
58             } else {
59             my @field_order;
60             if (exists($template->{'field_order'})) {
61             push @field_order, @{$template->{'field_order'}};
62             } else {
63             push @field_order, keys %{$template->{'fields'}};
64             }
65             foreach my $fieldname (@field_order) {
66             $form->add_field($template->{'fields'}{$fieldname}, $fieldname);
67            
68             #my $newfield = Form::Sensible::Field->create_from_flattened($template->{'fields'}{$fieldname});
69             #$form->add_field($newfield, $fieldname);
70             }
71             }
72             return $form;
73             }
74              
75             sub get_renderer {
76             my ($class, $type, $options) = @_;
77              
78             my $class_to_load;
79             if ($type =~ /^\+(.*)$/) {
80             $class_to_load = $1;
81             } else {
82             $class_to_load = 'Form::Sensible::Renderer::' . $type;
83             }
84             Class::MOP::load_class($class_to_load);
85             if (!$options) {
86             $options = {};
87             }
88            
89             return $class_to_load->new($options);
90             }
91              
92             sub get_validator {
93             my ($class, $type, $options) = @_;
94            
95             my $class_to_load;
96             if (!defined($type)) {
97             $type = "+Form::Sensible::Validator";
98             }
99             if ($type =~ /^\+(.*)$/) {
100             $class_to_load = $1;
101             } else {
102             $class_to_load = 'Form::Sensible::Validator::' . $type;
103             }
104             Class::MOP::load_class($class_to_load);
105            
106             return $class_to_load->new($options);
107             }
108              
109              
110              
111             __PACKAGE__->meta->make_immutable;
112             1;
113              
114             __END__
115              
116             =head1 NAME
117              
118             Form::Sensible - A sensible way to handle form based user interface
119              
120             =head1 SYNOPSIS
121              
122             use Form::Sensible;
123            
124             my $form = Form::Sensible->create_form( { ... } );
125              
126             my $renderer = Form::Sensible->get_renderer('HTML', { tt_config => { INCLUDE_PATH => [ '/path/to/templates' ] }});
127              
128             my $output = $renderer->render($form)->complete;
129            
130             ## Form Validation:
131            
132             my $validation_result = $form->validate();
133            
134             if ($validation_result->is_valid()) {
135             ## do form was valid stuff
136             } else {
137             my $output_with_messages = $renderer->render($form)->complete;
138             }
139              
140             =head1 DESCRIPTION
141              
142             Form::Sensible is a different kind of form library. Form::Sensible is not just
143             another HTML form creator, or a form validator, though it can do both.
144             Form::Sensible, instead, focuses on what forms are: a method to relay
145             information to and from a user interface.
146              
147             Form::Sensible forms are primarily tied to the data they represent.
148             Form::Sensible is not tied to HTML in any way. You could render Form::Sensible
149             forms using any presentation system you like, whether that's HTML, console
150             prompts, WxPerl or voice prompts. (* currently only an HTML renderer is
151             provided with Form::Sensible, but work is already under way to produce
152             others.)
153              
154             =head2 FEATURES
155              
156             =over 8
157             =item * Easy form creation
158              
159             =item * Easy form validation
160              
161             =item * Ability to easily save created forms for future use
162              
163             =item * Define form once, render any number of ways
164              
165             =item * Flexible built-in form validator
166              
167             =item * Easily extended to produce new renderers, field types and validation
168              
169             =item * HTML renderer produces sane html that can be easily styled via CSS
170              
171             =item * HTML renderer allows for custom templates to control all aspects of form rendering.
172              
173             =item * HTML output not tied to any javascript library.
174              
175             =back
176              
177              
178             =head2 Form::Sensible form lifecycle
179              
180             The Form::Sensible form lifecycle works as follows:
181              
182             =head3 Phase 1 - Show a form
183              
184             =over 8
185              
186             =item 1. Create form object
187              
188             =item 2. Create or get a renderer
189              
190             =item 3. Use renderer to render form
191              
192             =back
193              
194             =head3 Phase 2 - Validate input
195              
196             =over 8
197              
198             =item 1. Create form object
199              
200             =item 2. Retrieve user input and place it into form
201              
202             =item 3. Validate form
203              
204             =item 4. If form data is invalid, re-render the form with messages
205              
206             =back
207              
208             One of the most important features of Form::Sensible is that Forms, once
209             created, are easily stored for re-generation later. A form's definition and
210             state are easily converted to a hashref data structure ready for serializing.
211             Likewise, the data structure can be used to create a complete Form::Sensible
212             form object ready for use. This makes re-use of forms extremely easy and
213             provides for dynamic creation and processing of forms.
214              
215             =head1 EXAMPLES
216              
217             =head3 Form creation from simple data structure
218              
219             use Form::Sensible;
220            
221             my $form = Form::Sensible->create_form( {
222             name => 'test',
223             fields => [
224             {
225             field_class => 'Text',
226             name => 'username',
227             validation => { regex => '^[0-9a-z]*' }
228             },
229             {
230             field_class => 'Text',
231             name => 'password',
232             render_hints => {
233             'HTML' => {
234             field_type => 'password'
235             }
236             },
237             },
238             {
239             field_class => 'Trigger',
240             name => 'submit'
241             }
242             ],
243             } );
244              
245             This example creates a form from a simple hash structure. This example creates
246             a simple (and all too familiar) login form.
247              
248             =head3 Creating a form programmatically
249              
250             use Form::Sensible;
251            
252             my $form = Form::Sensible::Form->new(name=>'test');
253              
254             my $username_field = Form::Sensible::Field::Text->new(
255             name=>'username',
256             validation => { regex => qr/^[0-9a-z]*$/ }
257             );
258              
259             $form->add_field($username_field);
260              
261             my $password_field = Form::Sensible::Field::Text->new(
262             name=>'password',
263             render_hints => {
264             'HTML' => {
265             field_type => 'password'
266             },
267             },
268             );
269             $form->add_field($password_field);
270              
271             my $submit_button = Form::Sensible::Field::Trigger->new( name => 'submit' );
272              
273             $form->add_field($submit_button);
274              
275             This example creates the exact same form as the first example. This time,
276             however, it is done by creating each field object individually, and then
277             adding each in turn to the form.
278              
279             Both of these methods will produce the exact same results when rendered.
280              
281             =head3 Form validation
282              
283             ## set_values takes a hash of name->value pairs
284             $form->set_values($c->req->params);
285            
286             my $validation_result = $form->validate();
287            
288             if ($validation_result->is_valid) {
289            
290             #... do stuff if form submission is ok.
291            
292             } else {
293            
294             my $renderer = Form::Sensible->get_renderer('HTML');
295             my $output = $renderer->render($form)->complete;
296             }
297              
298             Here we fill in the values provided to us via C<< $c->req->params >> and then run validation
299             on the form. Validation follows the rules provided in the B<validation> definitions for
300             each field. Whole-form validation is can also be done if provided. When validation
301             is run using this process, the messages are automatically available during rendering.
302              
303              
304             =head1 METHODS
305              
306             All methods in the Form::Sensible package are class methods. Note that by
307             C<use>ing the Form::Sensible module, the L<Form::Sensible::Form> and
308             L<Form::Sensible::Field::*|Form::Sensible::Field/DESCRIPTION> classes are also C<use>d.
309              
310             =over 8
311              
312             =item C<create_form($formhash)>
313              
314             This method creates a form from the given hash structure. The hash structure
315             accepts all the same attributes that L<Form::Sensible::Form>'s new method
316             accepts. Field definitions are provided as an array under the C<field> key.
317             Returns the created L<Form::Sensible::Form> object.
318              
319             =item C<get_renderer($render_class, $options)>
320              
321             Creates a renderer of the given class using the C<$options> provided. The
322             format of the class name follows the convention of a bare name being appended
323             to C<Form::Sensible::Renderer::>. In other words if you call
324             C<<Form::Sensible->get_renderer('HTML', { 'foo' => 'bar' })>> Form::Sensible
325             will ensure the L<Form::Sensible::Renderer::HTML> class is loaded and will create
326             an object by passing the hashref provided to the C<new> method. If you wish to
327             provide a class outside of the C<Form::Sensible::Renderer::> namespace,
328             prepend the string with a C<+>. For example, to load the class
329             C<MyRenderer::ProprietaryUI> you would pass C<'+MyRenderer::ProprietaryUI'>.
330              
331             =item C<get_validator($validator_class, $options)>
332              
333             Creates a validator of the given class using the C<$options> provided. Follows
334             the same convention for class name passing as the get_renderer method.
335              
336             =back
337              
338              
339             =head1 AUTHORS
340              
341             Jay Kuri - E<lt>jayk@cpan.orgE<gt>
342              
343             Luke Saunders - E<lt>luke.saunders@gmail.comE<gt>
344              
345             Devin Austin - E<lt>dhoss@cpan.orgE<gt>
346              
347             Alan Rafagudinov - E<lt>alan.rafagudinov@ionzero.comE<gt>
348              
349             Andrew Moore - E<lt>amoore@cpan.orgE<gt>
350              
351             =head1 SPONSORED BY
352              
353             Ionzero LLC. L<http://ionzero.com/>
354              
355             =head1 SEE ALSO
356              
357             Form::Sensible Wiki: L<http://wiki.catalyzed.org/cpan-modules/form-sensible>
358              
359             Form::Sensible Discussion: L<http://groups.google.com/group/formsensible>
360              
361             Form::Sensible Github: L<https://github.com/jayk/Form-Sensible>
362              
363             L<Form::Sensible>
364              
365              
366             =head1 LICENSE
367              
368             Copyright 2009 by Jay Kuri E<lt>jayk@cpan.orgE<gt>
369              
370             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
371              
372              
373             =cut
374