NAME
Maypole::Model:CDBI::AsForm - Produce HTML form elements for database columns
SYNOPSIS
package Music::CD;
use Maypole::Model::CDBI::AsForm;
use base 'Class::DBI';
use CGI;
...
sub create_or_edit {
my $self = shift;
my %cgi_field = $self->to_cgi;
return start_form,
(map { "<b>$_</b>: ". $cgi_field{$_}->as_HTML." <br>" }
$class->Columns),
end_form;
}
# Example of has_many select package Job; __PACKAGE__->has_a('job_employer' => 'Employer'); __PACKAGE__->has_a('contact' => 'Contact')
package Contact; __PACKAGE__->has_a('cont_employer' => 'Employer'); __PACKAGE__->has_many('jobs' => 'Job', { join => { job_employer => 'cont_employer' }, constraint => { 'finshed' => 0 }, order_by => "created ASC", } );
package Employer; __PACKAGE__->has_many('jobs' => 'Job',); __PACKAGE__->has_many('contacts' => 'Contact', order_by => 'name DESC', );
# Choose some jobs to add to a contact (has multiple attribute).
my $job_sel = Contact->to_field('jobs'); # Uses constraint and order by
# Choose a job from $contact->jobs
my $job_sel = $contact->to_field('jobs');
DESCRIPTION
This module helps to generate HTML forms for creating new database rows or editing existing rows. It maps column names in a database table to HTML form elements which fit the schema. Large text fields are turned into textareas, and fields with a has-a relationship to other Class::DBI
tables are turned into select drop-downs populated with objects from the joined class.
ARGUMENTS HASH
This provides a convenient way to tweak AsForm's behavior in exceptional or not so exceptional instances. Below describes the arguments hash and example usages.
$beer->to_field($col, $how, $args);
$beer->to_field($col, $args);
Not all _to_* methods pay attention to all arguments. For example, '_to_textfield' does not look in $args->{'items'} at all.
- name -- the name the element will have , this trumps the derived name.
-
$beer->to_field('brewery', 'readonly', { name => 'brewery_id' });
- value -- the initial value the element will have, trumps derived value
-
$beer->to_field('brewery', 'textfield', { name => 'brewery_id', value => $beer->brewery, # however, no need to set value since $beer is object });
- items -- array of items generally used to make select box options
-
Can be array of objects, hashes, arrays, or strings, or just a hash.
# Rate a beer $beer->to_field(rating => select => { items => [1 , 2, 3, 4, 5], }); # Select a Brewery to visit in the UK Brewery->to_field(brewery_id => { items => [ Brewery->search_like(location => 'UK') ], }); # Make a select for a boolean field $Pub->to_field('open' , { items => [ {'Open' => 1, 'Closed' => 0 } ] });
- selected -- something representing which item is selected in a select box
-
$beer->to_field('brewery', { selected => $beer->brewery, # again not necessary since caller is obj. });
Can be an simple scalar id, an object, or an array of either
- class -- the class for which the input being made for field pertains to.
-
This in almost always derived in cases where it may be difficult to derive, -- # Select beers to serve on handpump Pub->to_field(handpumps => select => { class => 'Beer', order_by => 'name ASC', multiple => 1, });
- column_type -- a string representing column type
-
$pub->to_field('open', 'bool_select', { column_type => "bool('Closed', 'Open'), });
- column_nullable -- flag saying if column is nullable or not
-
Generally this can be set to get or not get a null/empty option added to a select box. AsForm attempts to call "$class->column_nullable" to set this and it defaults to true if there is no shuch method.
$beer->to_field('brewery', { column_nullable => 1 });
- r or request -- the mapyole request object
-
$beer->to_field('brewery', 'link_hidden', {r => $r, uri => 'www.maypole.perl.org/brewery/view/'.$beer->brewery}); # an html link that is also a hidden input to the object. R is required to # make the uri unless you pass a uri
- order_by, constraint, join
-
These are used in making select boxes. order_by is a simple order by clause and constraint and join are hashes used to limit the rows selected. The difference is that join uses methods of the object and constraint uses static values. You can also specify these in the relationship arguments.
BeerDB::LondonBeer->has_a('brewery', 'BeerDB::Brewery', order_by => 'brewery_name ASC', constraint => {location => 'London'}, 'join' => {'brewery_tablecolumn => 'beer_obj_column'}, );
-
Tell AsForm not to make hidden inputs for relationship constraints. It does this sometimes when making foreign inputs .
to_cgi
$self->to_cgi([@columns, $args]);
This returns a hash mapping all the column names to HTML::Element objects representing form widgets. It takes two opitonal arguments -- a list of columns and a hashref of hashes of arguments for each column. If called with an object like for editing, the inputs will have the object's values.
$self->to_cgi(); # uses $self->columns; # most used
$self->to_cgi(qw/brewery style rating/); # sometimes
# and on rare occassions this is desireable if you have a lot of fields
# and dont want to call to_field a bunch of times just to tweak one or
# two of them.
$self->to_cgi(@cols, {brewery => {
how => 'textfield' # too big for select
},
style => {
column_nullable => 0,
how => 'select',
items => ['Ale', 'Lager']
}
}
to_field($field [, $how][, $args])
This maps an individual column to a form element. The how
argument can be used to force the field type into any you want. It tells AsForm how to make the input ie-- forces it to use the method "_to_$how". If how
is specified but the class cannot call the method it maps to, then AsForm will issue a warning and the default input will be made. You can write your own "_to_$how" methods and AsForm comes with many. See HOW Methods
. You can also pass this argument in $args->{how}.
search_inputs
my $cgi = $class->search_inputs ([$args]); # optional $args
Returns hash or hashref of search inputs elements for a class making sure the inputs are empty of any initial values. You can specify what columns you want inputs for in $args->{columns} or by the method "search_columns". The default is "display_columns". If you want to te search on columns in related classes you can do that by specifying a one element hashref in place of the column name where the key is the related "column" (has_a or has_many method for example) and the value is a list ref of columns to search on in the related class.
Example: sub BeerDB::Beer::search_columns { return ( 'name' , 'rating', { brewery => [ 'name', 'location'] } ); }
# Now foreign inputs are made for Brewery name and location and the
# there will be no name clashing and processing can be automated.
unselect_element
unselect any selected elements in a HTML::Element select list widget
_field_from_how($field, $how,$args)
Returns an input element based the "how" parameter or nothing at all. Override at will.
_field_from_relationship($field, $args)
Returns an input based on the relationship associated with the field or nothing. Override at will.
For has_a it will give select box
_field_from_column($field, $args)
Returns an input based on the column's characteristics, namely type, or nothing. Override at will.
recognized arguments
selected => $object|$id,
name => $name,
value => $value,
where => SQL 'WHERE' clause,
order_by => SQL 'ORDER BY' clause,
limit => SQL 'LIMIT' clause,
items => [ @items_of_same_type_to_select_from ],
class => $class_we_are_selecting_from
stringify => $stringify_coderef|$method_name
# select box requirements # 1. a select box for objecs of a has_a related class -- DONE =head2 1. a select box out of a has_a or has_many related class. # For has_a the default behavior is to make a select box of every element in # related class and you choose one. #Or explicitly you can create one and pass options like where and order BeerDB::Beer->to_field('brewery','select', {where => "location = 'Germany'");
# For has_many the default is to get a multiple select box with all objects.
# If called as an object method, the objects existing ones will be selected.
Brewery::BeerDB->to_field('beers','select', {where => "rating > 5"});
2. a select box for objects of arbitrary class -- say BeerDB::Beer for fun. # general BeerDB::Beer->to_field('', 'select', $options)
BeerDB::Beer->to_field('', 'select'); # Select box of all the rows in class
# with PK as ID, $Class->to_field() same.
BeerDB::Beer->to_field('','select',{ where => "rating > 3 AND class like 'Ale'", order_by => 'rating DESC, beer_id ASC' , limit => 10});
# specify exact where clause
3. If you already have a list of objects to select from --
BeerDB:;Beer->to_field($col, 'select' , {items => $objects});
# 3. a select box for arbitrary set of objects # Pass array ref of objects as first arg rather than field $any_class_or_obj->to_field([BeerDB::Beer->search(favorite => 1)], 'select',);
_to_enum_select
$sel_box = $self->_to_enum_select($column, "ENUM('Val1','Val2','Val3')");
Returns an enum select box given a column name and an enum string. NOTE: The Plugin::Type does not return an enum string for mysql enum columns. This will not work unless you write your own column_type method in your model.
_to_bool_select
my $sel = $self->_to_bool_select($column, $bool_string);
This makes select input for boolean column. You can provide a bool string of form: Bool('zero','one') and those are used for option content. Onthervise No and Yes are used. TODO -- test without bool string.
_to_hidden($col, $args)
This makes a hidden html element. Give it a name and value or if name is a ref it will use the PK name and value of the object.
_to_link_hidden($col, $args)
Makes a link with a hidden input with the id of $obj as the value and name. Name defaults to the objects primary key. The object defaults to self.
_to_foreign_inputs
$html_els = $class_or_obj->_to_foreign_inputs($accssr, [$fields, $accssr_meta]);
Get inputs for the accessor's class. Pass an array ref of fields to get inputs for only those fields. Otherwise display_columns or all columns is used. If you have the meta info handy for the accessor you can pass that too.
TODO make AsForm know more about the request like what action we are doing so it can use edit columns or search_columns
NOTE , this names the foreign inputs is a particular way so they can be processed with a general routine and so there are not name clashes.
args - related_meta -- if you have this, great, othervise it will determine or die columns -- list of columns to make inputs for
_hash_selected
Method to make sense out of the "selected" argument which can be in a number of formats perhaps. It returns a hashref with the the values of options to be as the keys.
Below handles these formats for the "selected" slot in the arguments hash: Object (with id method) Scalar (assumes it is value) Array ref *OF* objects, arrays of data (0 elmnt used), hashes of data (id key used), and simple scalars.
_select_guts
Internal api method to make the actual select box form elements.
3 types of lists making for -- Hash, Array, Array of CDBI objects. Array of scalars , Array or Array refs with cols from class, Array of hashes
_options_from_objects ( $objects, $args);
Private method to makes a options out of objects. It attempts to call each objects stringify method specified in $args->{stringify} as the content. Otherwise the default stringification prevails.
_rename_foreign_input
_rename_foreign_input($html_el_or_hash_of_them); # changes made by reference
Recursively renames the foreign inputs made by _to_foreign_inputs so they can be processed generically. The format is "accessor__AsForeign_colname".
So if an Employee is a Person who has_own Address and you call
Employee->to_field("person")
then you will get inputs for the Person as well as their Address (by default, override _field_from_relationship to change logic) named like this:
person__AsForeign__address__AsForeign__street
person__AsForeign__address__AsForeign__city
person__AsForeign__address__AsForeign__state
person__AsForeign__address__AsForeign__zip
And the processor would know to create this address, put the address id in person->address data slot, create the person and put the person id in the employee->person data slot and then create the employee with that data.
Overriede make_element_foreign to change how you want a foreign param labeled.
make_element_foreign
$class->make_element_foreign($accessor, $element);
Makes an HTML::Element type object foreign elemen representing the class's accessor. (IE this in an input element for $class->accessor :) )
_box($value)
This functions computes the dimensions of a textarea based on the value or the defaults.
CHANGES
MAINTAINER
Maypole Developers
AUTHORS
Peter Speltz, Aaron Trevena
AUTHORS EMERITUS
Simon Cozens, Tony Bowden
TODO
Documenting
Testing - lots
chekbox generalization
radio generalization
select work
Make link_hidden use standard make_url stuff when it gets in Maypole
How do you tell AF --" I want a has_many select box for this every time so,
when you call "to_field($this_hasmany)" you get a select box
BUGS and QUERIES
Please direct all correspondence regarding this module to: Maypole list.
COPYRIGHT AND LICENSE
Copyright 2003-2004 by Simon Cozens / Tony Bowden
This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.