File Coverage

blib/lib/Form/Maker.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::Maker;
2 14     14   366135 use Form::Field;
  0            
  0            
3             use Form::Buttons;
4             use overload '""' => \&render;
5             Form::Field->plugins;
6              
7             our $VERSION = "0.03";
8              
9             =head1 NAME
10              
11             Form::Maker - Framework for web forms
12              
13             =head1 SYNOPSIS
14              
15             use Form::Maker;
16             # Please see Form::Maker::Introduction
17              
18             =head1 DESCRIPTION
19              
20             =cut
21              
22             use base qw(Form::Base Class::Accessor);
23             use UNIVERSAL::require;
24             use Carp;
25             use strict;
26             use warnings;
27              
28             Form::Maker->mk_attributes(qw/_renderer decorators field_hash fields/);
29             Form::Maker->mk_accessors(qw/buttons/);
30             Form::Maker->add_decorators(
31             qw/Form::Decorator::PredefinedFields Form::Decorator::DefaultButtons/);
32             Form::Maker->renderer("Form::Renderer::HTML");
33             Form::Maker->field_hash({});
34             Form::Maker->fields([]);
35              
36             sub _load_and_run {
37             my ($self, $class, $method, @args) = @_;
38             if (!$class->require) {
39             if ($method) {
40             $class->can($method) or croak "Can't load class $class";
41             } else {
42             # Maybe it's inline?
43             no strict 'refs';
44             return if keys %{$class."::"};
45             croak "Can't load class $class";
46             }
47             }
48             $class->$method(@args) if $method;
49             }
50              
51             =head1 METHODS
52              
53             =head2 make
54              
55             my $form = Form::Maker->make();
56             my $form = Form::Maker->make("Form::Outline::Login");
57              
58             Creates a new form. If a package name is given, this is used as an
59             outline for the form, and any fields defined in the outline are added to
60             the new form.
61              
62             =cut
63              
64             sub make {
65             my ($class, $spec) = @_;
66             my $obj = $class->new({
67             fields => [],
68             field_hash => {},
69             buttons => Form::Buttons->new()
70             });
71             $class->_load_and_run($spec => fill_outline => $obj) if $spec;
72             return $obj;
73             }
74              
75             =head2 add_fields
76              
77             $form->add_fields(qw/username password/);
78              
79             $form->add_fields(
80             Form::Field::Text->new({ name => "username" }),
81             Form::Field::Password->new({ name => "password" }),
82             );
83              
84             Adds fields to a form; the arguments may either be
85             C-derived objects, or names of fields. If the argument is a
86             plain string, then a C object is created; this may
87             later be changed to a different kind of field by the default
88             C.
89              
90             =cut
91              
92             sub add_fields {
93             my ($self, @fields) = @_;
94             for my $field (@fields) {
95             if (UNIVERSAL::isa($field, "Form::Field")) {
96             if ($self->field_hash->{$field->name}) {
97             croak "We already have a field called ".$field->name;
98             }
99             $self->field_hash->{$field->name} = $field;
100             $self->_add_fields($field);
101             $field->_form($self);
102             } else {
103             $self->add_named_field($field);
104             }
105             }
106             return $self;
107             }
108              
109             sub add_named_field {
110             my ($self, $name) = @_;
111             $self->add_fields(Form::Field::Text->new({ name => $name }));
112             }
113              
114             =head2 remove_fields
115              
116             $self->remove_fields(qw/password/);
117              
118             Removes the named fields from the form.
119              
120             =cut
121              
122             sub remove_fields {
123             my ($self, @fields) = @_;
124             if (ref $self) { delete @{$self->{field_hash}}{@fields} }
125             my %names = map {$_ => 1 } @fields;
126             $self->fields(
127             [
128             grep {!exists $names{$_->name}}
129             @{$self->fields}
130             ]
131             );
132             }
133              
134             =head2 add_button
135              
136             $self->add_button("submit");
137             $self->add_button( Form::Button->new("whatever") );
138              
139             Adds a button to the form. If no buttons are explicitly added by the
140             time the form is rendered, the C decorator will add a
141             submit and reset button.
142              
143             =cut
144              
145             sub add_button {
146             my ($self, $button) = @_;
147             return $self->add_button(Form::Button->new($button))
148             unless ref $button;
149              
150             croak "We already have a field called ".$button->name
151             if $self->field_hash->{$button->name};
152             $self->field_hash->{$button->name} = $button;
153             push @{$self->buttons}, $button;
154             }
155              
156             =head2 add_validation
157              
158             $self->add_validation(
159             username => qr/^[a-z]+$/,
160             phone => "Form::Validation::PhoneNumber",
161             email => {
162             perl => qr/$RE{email}/,
163             javascript =>
164             '/^[\w\-\+\._]+\@[a-zA-Z0-9][-a-zA-Z0-9\.]*\.[a-zA-Z]+$/'
165             }
166             );
167              
168             Sets the validation method for a given field; the value for each field
169             can be a regular expression, to be used for all validation contexts, a
170             hash mapping validation contexts to regular expressions, or the name of
171             a class which will provide such a hash.
172              
173             =cut
174              
175             sub add_validation {
176             my $self = shift;
177             while (my ($fieldname, $validation) = splice @_, 0, 2) {
178             my $field = $self->field_hash->{$fieldname};
179             croak "Can't add validation to non-existant field $fieldname" unless $field;
180             $field->add_validation($validation);
181             }
182             $self;
183             }
184              
185             =head2 renderer
186              
187             $form->renderer("Form::Renderer::TT");
188              
189             Gets or sets the form's renderer
190              
191             =cut
192              
193             sub renderer {
194             my ($self, $renderer) = @_;
195             if ($renderer) {
196             $self->_load_and_run($renderer);
197             $self->_renderer($renderer);
198             }
199             $self->_renderer;
200             }
201              
202             =head2 render
203              
204             print $form->render;
205             print $form;
206              
207             This uses the form's renderer to turn the form into a string; this
208             stringification is also done automatically when the form object is used
209             in a string context.
210              
211             =cut
212              
213              
214             sub render {
215             my $self = shift;
216             $self->decorate;
217             $self->renderer->render($self);
218             }
219              
220             sub decorate {
221             my $self = shift;
222             return if $self->{decorated}++;
223             for my $decorator (@{$self->decorators}) {
224             $self->_load_and_run($decorator);
225             $decorator->decorate($self);
226             }
227             }
228              
229             sub add_decorator { goto &add_decorators }
230              
231             =head1 Form elements
232              
233             These methods return rendered parts of the form
234              
235             =head2 start
236              
237             =head2 end
238              
239             Return the surrounding tags of the form, as plain text.
240              
241             =head2 fieldset_start
242              
243             =head2 fieldset_end
244              
245             Return the surrounding tags of the field section of the form, as plain
246             text.
247              
248             =cut
249              
250             for my $method (qw(start end fieldset_start fieldset_end)) {
251             no strict 'refs';
252             *$method = sub {
253             my $self = shift; $self->decorate; $self->renderer->$method;
254             };
255             }
256              
257             =head2 fieldset
258              
259             Returns the rendered fieldset portion of the form.
260              
261             =cut
262              
263             sub fieldset {
264             my $self = shift;
265             $self->decorate;
266             join ("", $self->fieldset_start, @{$self->fields}, $self->fieldset_end);
267             }
268              
269             =head2 fields
270              
271             Returns the individual fields as C elements.
272              
273             =cut
274              
275             sub fields {
276             my $self = shift;
277             if (ref $self) {
278             $self->decorate
279             }
280             $self->_att_fields(@_);
281             }
282              
283             1;
284              
285             =head1 AUTHOR
286              
287             Programmed by Simon Cozens, from a specification by Tony Bowden
288             (C) and Marty Pauley, and with the generous support
289             of Kasei.
290              
291             =head1 COPYRIGHT AND LICENSE
292              
293             Copyright (C) 2004 by Simon Cozens and Kasei.
294              
295             This library is free software; you can redistribute it and/or modify
296             it under the same terms as Perl itself, either Perl version 5.8.4 or,
297             at your option, any later version of Perl 5 you may have available.
298              
299              
300             =cut