]> git.decadent.org.uk Git - maypole.git/blobdiff - lib/Maypole/Model/CDBI/AsForm.pm
new updated Maypole::Model::CDBI::AsForm with PJSZ and AJT fixes and changes
[maypole.git] / lib / Maypole / Model / CDBI / AsForm.pm
index e0cd7f21c7919388d7b42a67a3700fc5f23d7873..70a7eb46ff32012b44fb3ea4d40207dd0122400d 100644 (file)
@@ -1,6 +1,15 @@
 package Maypole::Model::CDBI::AsForm;
 
 package Maypole::Model::CDBI::AsForm;
 
-use 5.006;
+#TODO -- 
+# lots of doc
+# _to_select_or_create  -- select input stays
+# _to_create_or_select  -- create input trumps
+# 
+
+# TESTED and Works --
+#  has_many select -- $obj->to_field($has_many_col);   # select one form many
+#                  -- $class->to_field($has_many_col); # foreign inputs  
+#  $class->search_inputs; /
 
 use strict;
 use warnings;
 
 use strict;
 use warnings;
@@ -9,22 +18,21 @@ use base 'Exporter';
 use Data::Dumper;
 use Class::DBI::Plugin::Type ();
 use HTML::Element;
 use Data::Dumper;
 use Class::DBI::Plugin::Type ();
 use HTML::Element;
+use Carp qw/cluck/;
 
 our $OLD_STYLE = 0;
 
 our $OLD_STYLE = 0;
-# pjs  --  Added new methods to @EXPORT 
-our @EXPORT =
-       qw(
-               to_cgi to_field _to_textarea _to_textfield _to_select
+our @EXPORT = 
+       qw( 
+               to_cgi to_field  make_element_foreign search_inputs unselect_element
+               _field_from_how _field_from_relationship _field_from_column
+               _to_textarea _to_textfield _to_select  _select_guts
                _to_foreign_inputs _to_enum_select _to_bool_select
                _to_foreign_inputs _to_enum_select _to_bool_select
-               _to_select_from_many _to_select_from_related _to_select_from_objs 
                _to_hidden _to_link_hidden _rename_foreign_input _to_readonly
                _options_from_objects _options_from_arrays _options_from_hashes 
                _to_hidden _to_link_hidden _rename_foreign_input _to_readonly
                _options_from_objects _options_from_arrays _options_from_hashes 
-               _options_from_scalars
-               _field_from_how _field_from_relationship _field_from_column
-               _select_guts unselect_element  search_inputs make_param_foreign 
+               _options_from_scalars _to_select_or_create
     );
 
     );
 
-our $VERSION = '2.11';
+our $VERSION = '.09';
 
 =head1 NAME
 
 
 =head1 NAME
 
@@ -47,51 +55,33 @@ Maypole::Model:CDBI::AsForm - Produce HTML form elements for database columns
                end_form;
     }
 
                end_form;
     }
 
-       . . . somewhere use to_field($col, $how, $args)
-       package BeerDB::Pint;
-       __PACKAGE__->has_a('drinker', 'BeerDB::Drinker');
-       __PACKAGE__->has_a('beer',    'BeerDB::Beer');
-       package BeerDB::Drinker;
-       __PACKAGE__->has_many('pints', 'BeerDB::Pint');
-       
-       # NEED to do mapping 
-       my $sel = BeerDB::Drinker->to_field('pints', 'select') # multiple
-       my $sel = $Drunk->to_field('pints', 'select'); # Already had beers selected
+    # Example of has_many select
 
 
-package Job;
+    package Job;
+    __PACKAGE__->has_a('job_employer' => 'Employer');
+    __PACKAGE__->has_a('contact'  => 'Contact')
 
 
-__PACKAGE__->has_a('employer' => 'Employer');
-__PACKAGE__->has_a('contact'  => 'Contact')
-
-package Contact;
-
-__PACKAGE__->has_a('employer_also' => 'Employer');
-__PACKAGE__->has_many('jobs'  => 'Job',
-        { join => { employer => 'employer_also' },
+    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",
         }
           constraint => { 'finshed' => 0  },
           order_by   => "created ASC",
         }
-);
+     );
 
 
-package Employer;
-
-__PACKAGE__->has_many('jobs'  => 'Job',);
-__PACKAGE__->has_many('contacts'  => 'Contact',
+    package Employer;
+    __PACKAGE__->has_many('jobs'  => 'Job',);
+    __PACKAGE__->has_many('contacts'  => 'Contact',
             order_by => 'name DESC',
             order_by => 'name DESC',
-);
-
-
-  # Below gives select boxes with the multiple attribute.
-  my $select_jobs_for_new_contact =
-    Contact->to_field('jobs', 'select'); # Uses constraint and order by
-
-  my $edit_jobs_for_existing_contact =
-    $contact->to_field('jobs', 'select');
+    );
 
 
 
 
+   # Choose some jobs to add to a contact (has multiple attribute).
+   my $job_sel = Contact->to_field('jobs'); # Uses constraint and order by
 
 
-       # Random use
-       
+   # Choose a job from $contact->job
+   my $job_sel = $contact->to_field('jobs');
 
 
 =head1 DESCRIPTION
 
 
 =head1 DESCRIPTION
@@ -103,156 +93,240 @@ into textareas, and fields with a has-a relationship to other
 C<Class::DBI> tables are turned into select drop-downs populated with
 objects from the joined class.
 
 C<Class::DBI> tables are turned into select drop-downs populated with
 objects from the joined class.
 
-=head1 METHODS
 
 
-The module is a mix-in which adds two additional methods to your
-C<Class::DBI>-derived class. 
+=head1 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. 
 
 
-=head2 search_inputs
 
 
-Returns hashref of search inputs elements to use in cgi.
+  $beer->to_field($col, $how, $args); 
+  $beer->to_field($col, $args);
 
 
-Uses fields specified in search_fields, makes foreign inputs if necessary.
+Not all _to_* methods pay attention to all arguments. For example, '_to_textfield' does not look in $args->{'items'} at all.
+=item name -- the name the element will have , this trumps the derived name.
 
 
-=cut
+  $beer->to_field('brewery', 'readonly', {
+               name => 'brewery_id'
+  });
+  
+=item value -- the initial value the element will have, trumps derived value
 
 
-# TODO -- use search_columns 
-sub search_inputs {
-  my ($class, $r) = @_;
-  warn "In model search_inputs " if $class->model_debug;
-  $class = ref $class || $class;
-  #my $accssr_class = { $class->accessor_classes };
-  my %cgi;
-  my $sfs = [$class->search_columns];
-
-  foreach my $field ( @$sfs ) {
-    if ( ref $field eq "HASH" ) { # foreign search fields
-      my ($accssr, $cols)  = each %$field;
-      unless (  @$cols ) {
-                               # default to search fields for related 
-                               #$cols =  $accssr_class->{$accssr}->search_columns;
-       die ("$class search_fields error: Must specify at least one column to search in the foreign object named '$accssr'");
-      }
-      my $fcgi  = $class->_to_foreign_inputs($accssr, $cols);
-      # unset the default values for a select box
-      foreach (keys %$fcgi) {
-       $class->unselect_element($fcgi->{$_});
-      }
-      $cgi{$accssr} = $fcgi;
-    } else {  
-      $cgi{$field} = $class->to_field($field);
-      $class->unselect_element($cgi{$field});
-    }
-  }
-  return \%cgi;
-}
+  $beer->to_field('brewery', 'textfield', { 
+               name => 'brewery_id', value => $beer->brewery,
+               # however, no need to set value since $beer is object
+  });
+=item 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') ],
+   });
 
 
-=head2 unselect_element
+  # Make a select for a boolean field
+  $Pub->to_field('open' , { items => [ {'Open' => 1, 'Closed' => 0 } ] }); 
 
 
-Unselects all options in a HTML::Element of type select.
-It does nothing if element is not a select element.
+=item selected -- something representing which item is selected in a select box
 
 
-=cut
+   $beer->to_field('brewery', {
+               selected => $beer->brewery, # again not necessary since caller is obj.
+   });
 
 
-sub unselect_element {
-       my ($self, $el) = @_;
-       #unless (ref $el eq 'HTML::Element') { 
-       #$self->_croak ('Need an HTML::Element to unselect. You gave a ' . Dumper($el)); }
-       if ($el->tag eq 'select') {
-               foreach my $opt ($el->content_list) {
-                       $opt->attr('selected', undef) if $opt->attr('selected');
-               }
-       }
-}
+Can be an simple scalar id, an object, or an array of either
 
 
+=item class -- the class for which the input being made for field pertains to.
 
 
-# make a select box from args
-sub a_select_box {
-       my ($self, $name, $vals, $selected_val, $contents) = @_;
-       die "Usage: Need a name and array ref of values to make a select boxes" unless ($name && $vals);
-       $selected_val ||= "";
-       $contents ||= $vals ;
-
-       my $a = HTML::Element->new('select', 'name' => $name);
-       my $i = 0;
-       my $c;
-       foreach my $v ( @$vals ) {
-               my $opt = HTML::Element->new('option', 'value' => $v);
-               $opt->attr('selected' => 'selected') if $v eq $selected_val;
-               $c = $contents->[$i++] || $v;
-               $opt->push_content($c);
-               $a->push_content($opt);
-       }
-       $a;
-}
+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,
+       });
 
 
+=item column_type -- a string representing column type
+   
+  $pub->to_field('open', 'bool_select', {
+               column_type => "bool('Closed', 'Open'),
+  });
 
 
+=item column_nullable -- flag saying if column is nullable or not
 
 
-=head2 make_param_foreign
+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 });    
 
 
-Makes a new foreign parameter out of parameter and accessor
-Just puts accssr__FOREIGN__ in front of param name 
+=item r or request  -- the mapyole request object 
 
 
-=cut
+=item uri -- uri for a link , used in methods such as _to_link_hidden
 
 
-sub make_param_foreign {
-       my ($self, $r, $p, $accssr) = @_;
-       $r->params->{$accssr . '__FOREIGN__' . $p} = $r->params->{$p};
-}
+ $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
 
 
-=head2 to_cgi
+=item 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'}, 
+         );
+          
+=item no_hidden_constraints -- 
 
 
-This returns a hash mapping all the column names of the class to
-HTML::Element objects representing form widgets.
+Tell AsForm not to make hidden inputs for relationship constraints. It does
+this  sometimes when making foreign inputs . 
 
 
-pjs -- added a columns list argument to specify which columns to make
-inputs for.
+=head2 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']
+                                                                  }
+                                               }
 
 =cut
 
 sub to_cgi {
        my ($class, @columns) = @_; # pjs -- added columns arg
 
 =cut
 
 sub to_cgi {
        my ($class, @columns) = @_; # pjs -- added columns arg
+       my $args = ref $columns[-1] ? pop @columns : {};
+       use Data::Dumper;
+       warn "Args are " . Dumper($args);
        @columns = $class->columns unless (@columns);
        @columns = $class->columns unless (@columns);
-       map { $_ => $class->to_field($_) } @columns;
+       map { $_ => $class->to_field($_, $args->{$_}) } @columns;
 }
 
 }
 
-
-=head2 to_field($field [, $how])
+=head2 to_field($field [, $how][, $args])
 
 This maps an individual column to a form element. The C<how> argument
 
 This maps an individual column to a form element. The C<how> argument
-can be used to force the field type into one of C<textfield>, C<textarea>
-or C<select>; you can use this is you want to avoid the automatic detection
-of has-a relationships.
+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 C<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 C<HOW Methods>. You can also pass this argument in $args->{how}.
 
 
-# pjs 
-   -- added support for enum and bool.   Note for enum and bool you need 
-      a better column_type method than the Plugin::Type ' s as it won't work 
-      if you are using MySQL. I have not tried others.  
-      See those method's docs below.
-   -- Foreign inputs for might_have, must_have, has_own, and has_many(i think).
-   -- Really any relationship except has_a and is_a as has_a gets a select box
-      and is_a are not considered foreign. 
-   -- Note a good column_type sub can be 
-      used to get the correct type for is_a columns.
-   -- More efficient _to_select -- no object creation.
-   -- Attempts to set default value in field for you using a "column_default" 
-      method you write yourself or your CDBI driver like mysql writes.
-   -- _to_hidden 
 
 =cut
 
 sub to_field {
 
 =cut
 
 sub to_field {
-       my ($self, $field, @args) = @_;
-    my $how = shift @args unless ref $args[0];  
-    my $args = shift @args;  # argument hash ref  
-
-       return  $self->_field_from_how($field, $how, $args)   || 
-               $self->_field_from_relationship($field, $args) ||
-                       $self->_field_from_column($field, $args)  ||
-                       $self->_to_textfield($field, $args);
+  my ($self, $field, $how, $args) = @_;
+  if (ref $how)   { $args = $how; }
+  unless ($how)   { $how = $args->{how} || ''; }
+  
+  return $self->_field_from_how($field, $how, $args)   ||
+    $self->_field_from_relationship($field, $args) ||
+      $self->_field_from_column($field, $args)  ||
+       $self->_to_textfield($field, $args);
+}
+
+=head2 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.
+
+=cut
+
+
+sub search_inputs {
+    my ($class, $args) = @_;
+    warn "In new Search Inputs";
+    $class = ref $class || $class;
+    #my $accssr_class = { $class->accessor_classes };
+    my %cgi;
+
+    $args->{columns} ||= $class->can('search_columns') ?[$class->search_columns] : [$class->display_columns];
+
+    foreach my $field ( @{ $args->{columns} } ) {
+               my $base_args = {
+                       no_hidden_constraints => 1,
+                       column_nullable => 1, # empty option on select boxes
+                       value  => '',
+               };
+        if ( ref $field eq "HASH" ) { # foreign search fields
+            my ($accssr, $cols)  = each %$field;
+                       $base_args->{columns} = $cols;
+            unless (  @$cols ) {
+                # default to search fields for related
+                #$cols =  $accssr_class->{$accssr}->search_columns;
+                die ("$class search_fields error: Must specify at least one column to search in the foreign object named '$accssr'");
+            }
+            my $fcgi  = $class->to_field($accssr, 'foreign_inputs', $base_args);
+
+            # unset the default values for a select box
+            foreach (keys %$fcgi) {
+                                       #$class->unselect_element($fcgi->{$_});
+            }
+            $cgi{$accssr} = $fcgi;
+                       delete $base_args->{columns};
+        } else {
+            $cgi{$field} = $class->to_field($field, $base_args); #{no_select => $args->{no_select}{$field} });
+                       #$class->unselect_element($cgi{$field});
+        }
+    }
+    return \%cgi;
+}
+
+
+
+#
+sub unselect_element {
+   my ($self, $el) = @_;
+   #unless (ref $el eq 'HTML::Element') {
+   #$self->_croak ('Need an HTML::Element to unselect. You gave a ' . Dumper($el)); }
+   if ($el->tag eq 'select') {
+       foreach my $opt ($el->content_list) {
+           $opt->attr('selected', undef) if $opt->attr('selected');
+       }
+   }
 }
 
 =head2 _field_from_how($field, $how,$args)
 }
 
 =head2 _field_from_how($field, $how,$args)
@@ -264,11 +338,16 @@ Override at will.
 
 sub _field_from_how {
        my ($self, $field, $how, $args) = @_;
 
 sub _field_from_how {
        my ($self, $field, $how, $args) = @_;
-       if ($how) { 
-               no strict 'refs';
-               my $meth = "_to_$how";
-               return $self->$meth($field, $args) if $self->can($meth);
+       if (ref $how) { $args = $how; $how = undef; }
+       return unless $how;
+       $args ||= {};
+       no strict 'refs';
+       my $meth = "_to_$how";
+       if (not $self->can($meth)) { 
+               warn "Class can not $meth";
+               return;
        }
        }
+       return $self->$meth($field, $args); 
        return;
 }
 
        return;
 }
 
@@ -277,26 +356,61 @@ sub _field_from_how {
 Returns an input based on the relationship associated with the field or nothing.
 Override at will.
 
 Returns an input based on the relationship associated with the field or nothing.
 Override at will.
 
+For has_a it will give select box
+
 =cut
 
 sub _field_from_relationship {
        my ($self, $field, $args) = @_;
 =cut
 
 sub _field_from_relationship {
        my ($self, $field, $args) = @_;
-       my $meta = $self->meta_info;
-       my ($rel_type) = grep{ defined $meta->{$_}{$field} } keys %$meta;
-       $rel_type ||= ''; 
-       my $fclass = $rel_type ? $meta->{$rel_type}{$field}{foreign_class} : '';
-    $args->{class} = $fclass;
+       return unless $field;
+       my $rel_meta = $self->related_meta('r',$field) || return; 
+       my $rel_name = $rel_meta->{name};
+       #my $meta = $self->meta_info;
+       #grep{ defined $meta->{$_}{$field} } keys %$meta;
+       my $fclass = $rel_meta->foreign_class;
        my $fclass_is_cdbi = $fclass ? $fclass->isa('Class::DBI') : 0;
 
        # maybe has_a select 
        my $fclass_is_cdbi = $fclass ? $fclass->isa('Class::DBI') : 0;
 
        # maybe has_a select 
-    return  $self->_to_select($field, $args) 
-               if $rel_type eq 'has_a' and $fclass_is_cdbi;
+       #warn "Dumper of relmeta. " . Dumper($rel_meta);
+       if ($rel_meta->{name} eq 'has_a' and $fclass_is_cdbi) {
+           # This condictions allows for trumping of the has_a args
+               if  (not $rel_meta->{args}{no_select} and not $args->{no_select}) 
+               {
+               $args->{class} = $fclass;
+               return  $self->_to_select($field, $args);
+               }
+               return;
+       }
+       # maybe has many select
+       if ($rel_meta->{name} eq 'has_many' and $fclass_is_cdbi and ref $self) {
+           # This condictions allows for trumping of the has_a args
+               if  (not $rel_meta->{args}{no_select} and not $args->{no_select}) 
+               {
+               $args->{class} = $fclass;
+                       $args->{items} = $self->$field;
+               return  $self->_to_select($field, $args);
+               }
+               return;
+       }
 
 
+               
+       
+       #NOOO!  maybe select from has_many 
+#      if ($rel_type eq 'has_many' and ref $self) {
+#              $args->{items} ||= [$self->$field];
+#              # arg name || fclass pk name || field
+#              if (not $args->{name}) {
+#                      $args->{name} =  eval{$fclass->primary_column->name} || $field; 
+#              }
+#      return  $self->_to_select($field, $args);
+#      }
+#
        # maybe foreign inputs 
        my %local_cols = map { $_ => 1 } $self->columns; # includes is_a cols
        # maybe foreign inputs 
        my %local_cols = map { $_ => 1 } $self->columns; # includes is_a cols
-       if ($fclass_is_cdbi and (not $local_cols{$field} or $rel_type eq 'has_own'))
+       if ($fclass_is_cdbi and (not $local_cols{$field} or $rel_name eq 'has_own'))
        {
        {
-               return $self->_to_foreign_inputs($field, undef, $meta->{$rel_type}{$field});
+               $args->{related_meta} = $rel_meta; # suspect faster to set these args 
+               return $self->_to_foreign_inputs($field, $args);
        }
        return;
 }
        }
        return;
 }
@@ -310,8 +424,9 @@ Override at will.
 
 sub _field_from_column {
   my ($self, $field, $args) = @_;
 
 sub _field_from_column {
   my ($self, $field, $args) = @_;
+  return unless $field;
   my $class = ref $self || $self;
   my $class = ref $self || $self;
-  # Get column type
+  # Get column type    
   unless ($args->{column_type}) { 
     if ($class->can('column_type')) {
       $args->{column_type} = $class->column_type($field);
   unless ($args->{column_type}) { 
     if ($class->can('column_type')) {
       $args->{column_type} = $class->column_type($field);
@@ -323,7 +438,7 @@ sub _field_from_column {
   }
   my $type = $args->{column_type};
 
   }
   my $type = $args->{column_type};
 
-  return $self->_to_textfield($field)
+  return $self->_to_textfield($field, $args)
     if $type  and $type =~ /(VAR)?CHAR/i; #common type
   return $self->_to_textarea($field, $args)
     if $type and $type =~ /^(TEXT|BLOB)$/i;
     if $type  and $type =~ /(VAR)?CHAR/i; #common type
   return $self->_to_textarea($field, $args)
     if $type and $type =~ /^(TEXT|BLOB)$/i;
@@ -366,7 +481,7 @@ sub _to_textarea {
 sub _to_textfield {
     my ($self, $col, $args ) = @_;
     $args ||= {};
 sub _to_textfield {
     my ($self, $col, $args ) = @_;
     $args ||= {};
-    my $val = $args->{value}; 
+    my $val  = $args->{value}; 
     my $name = $args->{name} || $col; 
 
     unless (defined $val) {
     my $name = $args->{name} || $col; 
 
     unless (defined $val) {
@@ -374,18 +489,24 @@ sub _to_textfield {
             # Case where column inflates.
             # Input would get stringification which could be not good.
             #  as in the case of Time::Piece objects
             # Case where column inflates.
             # Input would get stringification which could be not good.
             #  as in the case of Time::Piece objects
-            $val = $self->$col;
+            $val = $self->can($col) ? $self->$col : ''; # in case it is a virtual column
             if (ref $val) {
                                if (my $meta = $self->related_meta('',$col)) {
             if (ref $val) {
                                if (my $meta = $self->related_meta('',$col)) {
-                               if (my $code = $meta->{args}{deflate4edit} ) {
+                               #warn "Meta for $col";
+                               if (my $code = $meta->{args}{deflate4edit} || $meta->{args}{deflate} ) {
                        $val  = ref $code ? &$code($val) : $val->$code;
                                        }
                        $val  = ref $code ? &$code($val) : $val->$code;
                                        }
+                                       elsif ( $val->isa('Class::DBI') ) {
+                                           $val  = $val->id;
+                                       }
                                        else { 
                                        else { 
-                                           $val  = $self->_attr($col);
+                                               #warn "No deflate4edit code defined for $val of type " . 
+                                            #ref $val . ". Using the stringified value in textfield..";
                                        }
                        }
                                else {
                                        }
                        }
                                else {
-                                       $val  = $self->_attr($col);
+                                       #warn "No meta for $col but ref $val.\n";
+                                       $val  = $val->id if $val->isa("Class::DBI"); 
                }
                }
                        
                }
                }
                        
@@ -395,8 +516,9 @@ sub _to_textfield {
                $val = '' unless defined $val;
         }
     }
                $val = '' unless defined $val;
         }
     }
-    my $a = HTML::Element->new("input", type => "text", name => $name);
-    $a->attr("value" => $val);
+    my $a = HTML::Element->new("input", type => "text", name => $name, value =>
+                                                               $val);
+
     $OLD_STYLE && return $a->as_HTML;
     $a;
 }
     $OLD_STYLE && return $a->as_HTML;
     $a;
 }
@@ -480,9 +602,10 @@ sub _to_select {
     my ($self, $col, $args) = @_;
     $args ||= {};
 # Do we have items already ? Go no further. 
     my ($self, $col, $args) = @_;
     $args ||= {};
 # Do we have items already ? Go no further. 
-    if ($args->{items}) {  
+    if ($args->{items} and @{$args->{items}}) {  
                my $a = $self->_select_guts($col,  $args);
        $OLD_STYLE && return $a->as_HTML;
                my $a = $self->_select_guts($col,  $args);
        $OLD_STYLE && return $a->as_HTML;
+               if ($args->{multiple}) { $a->attr('multiple', 'multiple');}
                return $a;
        }
 
                return $a;
        }
 
@@ -490,7 +613,6 @@ sub _to_select {
        # No Column parameter --  means making a select box of args->class or self 
     # Using all rows from class's table
     if (not $col) { 
        # No Column parameter --  means making a select box of args->class or self 
     # Using all rows from class's table
     if (not $col) { 
-        warn "No col. $self";
                unless ($args->{class}) {
                $args->{class} = ref $self || $self;
                        # object selected if called with one
                unless ($args->{class}) {
                $args->{class} = ref $self || $self;
                        # object selected if called with one
@@ -500,26 +622,38 @@ sub _to_select {
         $col = $args->{class}->primary_column;
     }
     # Related Class maybe ? 
         $col = $args->{class}->primary_column;
     }
     # Related Class maybe ? 
-    elsif (my ($rel_type, $rel_meta) =  $self->related_meta('r:)', $col) ) {
+    elsif (my $rel_meta =  $self->related_meta('r:)', $col) ) {
         $args->{class} = $rel_meta->{foreign_class};
         # related objects pre selected if object
         $args->{class} = $rel_meta->{foreign_class};
         # related objects pre selected if object
-               $args->{selected} ||= [ $self->$col ] if  ref $self; 
                                
                                
-               # "Has many" --  we get multiple select 
-               if ($rel_type =~ /has_many/i) {
-                       $args->{attr}{multiple}  = 'multiple';
-                       # TODO -- handle mapping 
+               # "Has many" -- Issues:
+               # 1) want to select one from list if self is an object
+               # Thats about all we can do really, 
+               # 2) except for mapping which is TODO and  would 
+               # do something like add to and take away from list of permissions for
+               # example.
+
+               # Hasmany select one from list if ref self
+               if ($rel_meta->{name} =~ /has_many/i and ref $self) {
+                       $args->{items} = [ $self->$col ];
+                       my $a = $self->_select_guts($col,  $args);
+                   $OLD_STYLE && return $a->as_HTML;
+                   return $a;
                }
                }
-               my $c = $rel_meta->{args}{constraint} || {};
-               my $j = $rel_meta->{args}{join} || {};
-               my @join ; 
-               if (ref $self) {
-                       @join   =  map { $_ ." = ". $self->_attr($_) } keys %$j; 
+               else {
+                       $args->{selected} ||= [ $self->$col ] if  ref $self; 
+                       #warn "selected is " . Dumper($args->{selected});
+                       my $c = $rel_meta->{args}{constraint} || {};
+                       my $j = $rel_meta->{args}{join} || {};
+                       my @join ; 
+                       if (ref $self) {
+                               @join   =  map { $_ ." = ". $self->_attr($_) } keys %$j; 
+                       }
+                       my @constr= map { "$_ = '$c->{$_}'"} keys %$c; 
+                       $args->{where}    ||= join (' AND ', (@join, @constr));
+                       $args->{order_by} ||= $rel_meta->{args}{order_by};
+                       $args->{limit}    ||= $rel_meta->{args}{limit};
                }
                }
-               my @constr= map { "$_ = '$c->{$_}'"} keys %$c; 
-               $args->{where}    ||= join (' AND ', (@join, @constr));
-               $args->{order_by} ||= $rel_meta->{args}{order_by};
-               $args->{limit}    ||= $rel_meta->{args}{limit};
                        
     }
     # We could say :Col is name and we are selecting  out of class arg.
                        
     }
     # We could say :Col is name and we are selecting  out of class arg.
@@ -531,25 +665,39 @@ sub _to_select {
     }
                
     # Set arguments 
     }
                
     # Set arguments 
-       if ( $self->can('column_nullable') ) { 
-               $args->{nullable} ||= $self->column_nullable($col);
+       unless ( defined  $args->{column_nullable} ) {
+           $args->{column_nullable} = $self->can('column_nullable') ?
+                        $self->column_nullable($col) : 1;
        }
 
        # Get items to select from
     $args->{items} = _select_items($args);
        }
 
        # Get items to select from
     $args->{items} = _select_items($args);
-use Data::Dumper;
-warn "Just got items. They are  " . Dumper($args->{items});
+    #warn "Items selecting from are " . Dumper($args->{items});
+#use Data::Dumper;
+#warn "Just got items. They are  " . Dumper($args->{items});
 
        # Make select HTML element
        $a = $self->_select_guts($col, $args);
 
 
        # Make select HTML element
        $a = $self->_select_guts($col, $args);
 
+       if ($args->{multiple}) {$a->attr('multiple', 'multiple');}
+
        # Return 
     $OLD_STYLE && return $a->as_HTML;
     $a;
 
 }
 
        # Return 
     $OLD_STYLE && return $a->as_HTML;
     $a;
 
 }
 
-       
+
+##############
+# Function # 
+# #############
+# returns the intersection of list refs a and b
+sub _list_intersect {
+       my ($a, $b) = @_;
+       my %isect; my %union;
+    foreach my $e (@$a, @$b) { $union{$e}++ && $isect{$e}++ }
+       return  %isect;
+}
 ############
 # FUNCTION #
 ############
 ############
 # FUNCTION #
 ############
@@ -557,16 +705,22 @@ warn "Just got items. They are  " . Dumper($args->{items});
 sub _select_items { 
        my $args = shift;
        my $fclass = $args->{class};
 sub _select_items { 
        my $args = shift;
        my $fclass = $args->{class};
-    my @select_box_cols;
-    @select_box_cols = $fclass->columns('SelectBox');
-    @select_box_cols = $fclass->columns('Stringify')
-                                            unless @select_box_cols;
-    @select_box_cols = $fclass->_essential
-                                            unless @select_box_cols;
-    unshift @select_box_cols, $fclass->columns('Primary')
-        unless $select_box_cols[0] eq $fclass->columns('Primary');
-
-    my $sql = "SELECT " . join( ', ', @select_box_cols) . 
+    my @disp_cols = @{$args->{columns} || []};
+    @disp_cols = $fclass->columns('SelectBox') unless @disp_cols;
+    @disp_cols = $fclass->columns('Stringify')unless @disp_cols;
+    @disp_cols = $fclass->_essential unless @disp_cols;
+       unshift @disp_cols,  $fclass->columns('Primary');
+       #my %isect = _list_intersect(\@pks, \@disp_cols);
+       #foreach (@pks) { push @sel_cols, $_ unless $isect{$_}; } 
+    #push @sel_cols, @disp_cols;               
+
+       warn "in select items. args are : " . Dumper($args);
+       my $distinct = '';
+       if ($args->{'distinct'}) {
+       $distinct = 'DISTINCT ';
+       }
+
+    my $sql = "SELECT $distinct" . join( ', ', @disp_cols) . 
                  " FROM " . $fclass->table;
 
        $sql .= " WHERE " . $args->{where}   if $args->{where};
                  " FROM " . $fclass->table;
 
        $sql .= " WHERE " . $args->{where}   if $args->{where};
@@ -646,21 +800,39 @@ TODO -- test without bool string.
 
 =cut
 
 
 =cut
 
+# TCODO fix this mess with args
 sub _to_bool_select {
 sub _to_bool_select {
-    my ($self, $col, $type) = @_;
+    my ($self, $col, $args) = @_;
+       warn "In to_bool select";
+       my $type = $args->{column_type};
        my @bool_text = ('No', 'Yes');  
        if ($type =~ /BOOL\((.+?)\)/i) {
                (my $bool = $1) =~ s/'//g;
                @bool_text = split /,/, $bool;
        }
        my @bool_text = ('No', 'Yes');  
        if ($type =~ /BOOL\((.+?)\)/i) {
                (my $bool = $1) =~ s/'//g;
                @bool_text = split /,/, $bool;
        }
-       my $one= ref $self ? eval {$self->$col;} : $self->column_default($col);
+
+       # get selectedod 
+       
+       my $selected = $args->{value} if defined $args->{value};
+       $selected = $args->{selected} unless defined $selected;
+       $selected =  ref $self ? eval {$self->$col;} : $self->column_default($col)
+               unless (defined $selected);
+
     my $a = HTML::Element->new("select", name => $col);
     my $a = HTML::Element->new("select", name => $col);
+    if ($args->{column_nullable} || $args->{value} eq '') {
+               my $null =  HTML::Element->new("option");
+               $null->attr('selected', 'selected') if  $args->{value} eq '';
+           $a->push_content( $null ); 
+       }
+          
     my ($opt0, $opt1) = ( HTML::Element->new("option", value => 0),
                                                  HTML::Element->new("option", value => 1) ); 
     my ($opt0, $opt1) = ( HTML::Element->new("option", value => 0),
                                                  HTML::Element->new("option", value => 1) ); 
-    $opt0->attr("selected" => "selected") if not $one; 
     $opt0->push_content($bool_text[0]); 
     $opt0->push_content($bool_text[0]); 
-    $opt1->attr("selected" => "selected") if $one; 
     $opt1->push_content($bool_text[1]); 
     $opt1->push_content($bool_text[1]); 
+       unless ($selected eq '') { 
+       $opt0->attr("selected" => "selected") if not $selected; 
+       $opt1->attr("selected" => "selected") if $selected; 
+       }
     $a->push_content($opt0, $opt1);
     $OLD_STYLE && return $a->as_HTML;
     $a;
     $a->push_content($opt0, $opt1);
     $OLD_STYLE && return $a->as_HTML;
     $a;
@@ -706,22 +878,27 @@ Name defaults to the objects primary key. The object defaults to self.
 
 sub _to_link_hidden {
     my ($self, $accessor, $args) = @_;
 
 sub _to_link_hidden {
     my ($self, $accessor, $args) = @_;
-    my $r = $args->{r} || '';
-    my $url = $args->{url} || '';
-    
-    $self->_croak("_to_link_hidden called without Maypole Request object (\$r) and url. Need one or other.")
+    my $r =  eval {$self->controller} || $args->{r} || '';
+    my $uri = $args->{uri} || '';
+   use Data::Dumper;
+    $self->_croak("_to_link_hidden cant get uri. No  Maypole Request class (\$r) or uri arg. Need one or other.")
         unless $r;
     my ($obj, $name);
     if (ref $self) { # hidding linking self
          $obj  = $self;
          $name = $args->{name} || $obj->primary_column->name;
     }
         unless $r;
     my ($obj, $name);
     if (ref $self) { # hidding linking self
          $obj  = $self;
          $name = $args->{name} || $obj->primary_column->name;
     }
+    elsif ($obj = $args->{items}->[0]) {
+       # cool) 
+        $name = $args->{name} || $obj->primary_column->name; # TODO make use meta data
+    }
+       
     else {           # hiding linking related object with id in args
         $obj  = $self->related_class($r, $accessor)->retrieve($args->{id});
         $name = $args->{name} || $obj->primary_column->name; # TODO make use meta data
     }
     $self->_croak("_to_link_hidden has no object") unless ref $obj;
     else {           # hiding linking related object with id in args
         $obj  = $self->related_class($r, $accessor)->retrieve($args->{id});
         $name = $args->{name} || $obj->primary_column->name; # TODO make use meta data
     }
     $self->_croak("_to_link_hidden has no object") unless ref $obj;
-    my $href =  $url || $r->config->{uri_base} . "/". $obj->table."/view/".$obj->id;
+    my $href =  $uri || $r->config->{uri_base} . "/". $obj->table."/view/".$obj->id;
     my $a = HTML::Element->new('a', 'href' => $href);
     $a->push_content("$obj");
     $a->push_content($self->_to_hidden($name, $obj->id));
     my $a = HTML::Element->new('a', 'href' => $href);
     $a->push_content("$obj");
     $a->push_content($self->_to_hidden($name, $obj->id));
@@ -745,19 +922,22 @@ 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.
 
 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 
+
 =cut
 
 sub _to_foreign_inputs {
 =cut
 
 sub _to_foreign_inputs {
-       my ($self, $accssr, $fields, $accssr_meta) = @_;
-       if (!$accssr_meta) {
-               my $class_meta = $self->meta_info;
-               my ($rel_type) = grep { defined $class_meta->{$_}->{$accssr} }
-                       keys %$class_meta;
-               $self->_croak( "No relationship for accessor $accssr") if not $rel_type;
-               $accssr_meta = $class_meta->{$rel_type}->{$accssr};
+       my ($self, $accssr, $args) = @_;
+       my $rel_meta = $args->{related_meta} || $self->related_meta('r',$accssr); 
+       my $fields              = $args->{columns};
+       if (!$rel_meta) {
+               $self->_croak( "No relationship for accessor $accssr");
        }
 
        }
 
-       my $classORobj = ref $self && ref $self->$accssr ? $self->$accssr : $accssr_meta->{foreign_class};
+       my $rel_type = $rel_meta->{name};
+       my $classORobj = ref $self && ref $self->$accssr ? $self->$accssr : $rel_meta->{foreign_class};
        
        unless ($fields) {      
                $fields = $classORobj->can('display_columns') ? 
        
        unless ($fields) {      
                $fields = $classORobj->can('display_columns') ? 
@@ -765,8 +945,8 @@ sub _to_foreign_inputs {
        }
        
        # Ignore our fkey in them to  prevent infinite recursion 
        }
        
        # Ignore our fkey in them to  prevent infinite recursion 
-       my $me          = eval {$accssr_meta->{args}{foreign_column}} || '';  
-       my $constrained = $accssr_meta->{args}{constraint}; 
+       my $me          = eval {$rel_meta->{args}{foreign_column}} || '';  
+       my $constrained = $rel_meta->{args}{constraint}; 
        my %inputs;
        foreach ( @$fields ) {
                next if $constrained->{$_} || ($_ eq $me); # don't display constrained
        my %inputs;
        foreach ( @$fields ) {
                next if $constrained->{$_} || ($_ eq $me); # don't display constrained
@@ -775,7 +955,7 @@ sub _to_foreign_inputs {
 
        # Make hidden inputs for constrained columns unless we are editing object
        # TODO -- is this right thing to do?
 
        # Make hidden inputs for constrained columns unless we are editing object
        # TODO -- is this right thing to do?
-       unless (ref $classORobj) {
+       unless (ref $classORobj || $args->{no_hidden_constraints}) {
                $inputs{$_} = $classORobj->_to_hidden($_, $constrained->{$_}) 
                        foreach ( keys %$constrained );  
        }
                $inputs{$_} = $classORobj->_to_hidden($_, $constrained->{$_}) 
                        foreach ( keys %$constrained );  
        }
@@ -804,8 +984,9 @@ Below handles these formats for the "selected" slot in the arguments hash:
 ############
 sub _hash_selected {
        my ($args) = shift;
 ############
 sub _hash_selected {
        my ($args) = shift;
-       my $selected = $args->{selected};
+       my $selected = $args->{value} || $args->{selected};
     return $selected unless $selected and ref $selected ne 'HASH'; 
     return $selected unless $selected and ref $selected ne 'HASH'; 
+       warn "Selected dump : " . Dumper($selected);
        my $type = ref $selected;
        # Single Object 
     if ($type and $type ne 'ARRAY') {
        my $type = ref $selected;
        # Single Object 
     if ($type and $type ne 'ARRAY') {
@@ -815,6 +996,7 @@ sub _hash_selected {
        elsif (not $type) {
                return { $selected => 1}; 
        }
        elsif (not $type) {
                return { $selected => 1}; 
        }
+       
 
        # Array of objs, arrays, hashes, or just scalalrs. 
        elsif ($type eq 'ARRAY') {
 
        # Array of objs, arrays, hashes, or just scalalrs. 
        elsif ($type eq 'ARRAY') {
@@ -840,12 +1022,9 @@ sub _hash_selected {
                return \%hashed;
        }
        else { warn "AsForm Could not hash the selected argument: $selected"; }
                return \%hashed;
        }
        else { warn "AsForm Could not hash the selected argument: $selected"; }
-} 
-               
-
-
+}
 
 
-=head2 _select_guts 
+=head2 _select_guts
 
 Internal api  method to make the actual select box form elements.
 
 
 Internal api  method to make the actual select box form elements.
 
@@ -853,6 +1032,7 @@ Internal api  method to make the actual select box form elements.
   Array of CDBI objects.
   Array of scalars , 
   Array or  Array refs with cols from class.
   Array of CDBI objects.
   Array of scalars , 
   Array or  Array refs with cols from class.
+
 =cut
 
 
 =cut
 
 
@@ -860,17 +1040,16 @@ Internal api  method to make the actual select box form elements.
 sub _select_guts {
     my ($self, $col, $args) = @_; #$nullable, $selected_id, $values) = @_;
 
 sub _select_guts {
     my ($self, $col, $args) = @_; #$nullable, $selected_id, $values) = @_;
 
-    $args->{stringify} ||=  'stringify_selectbox';
-    $args->{selected} = _hash_selected($args);
+    #$args->{stringify} ||=  'stringify_selectbox';
+    $args->{selected} = _hash_selected($args) if defined $args->{selected};
        my $name = $args->{name} || $col;
     my $a = HTML::Element->new('select', name => $name);
        $a->attr( %{$args->{attr}} ) if $args->{attr};
     
        my $name = $args->{name} || $col;
     my $a = HTML::Element->new('select', name => $name);
        $a->attr( %{$args->{attr}} ) if $args->{attr};
     
-    if ($args->{nullable}) {
-               my $null_element = HTML::Element->new('option');
+    if ($args->{column_nullable}) {
+               my $null_element = HTML::Element->new('option', value => '');
         $null_element->attr(selected => 'selected')
         $null_element->attr(selected => 'selected')
-               if $args->{selected}{'null'};
-               $null_element->push_content('-- choose or type --');
+               if ($args->{selected}{'null'});
         $a->push_content($null_element);
     }
 
         $a->push_content($null_element);
     }
 
@@ -879,7 +1058,10 @@ sub _select_guts {
     my $type  = ref $proto || '';
 
     # Objects 
     my $type  = ref $proto || '';
 
     # Objects 
-    if ($type and  $type !~ /ARRAY|HASH/i) {
+    if (not $type) {
+               $a->push_content($self->_options_from_scalars($items, $args));
+       }
+       elsif($type !~ /ARRAY|HASH/i) {
                # make select  of objects
                $a->push_content($self->_options_from_objects($items, $args));
        }
                # make select  of objects
                $a->push_content($self->_options_from_objects($items, $args));
        }
@@ -890,7 +1072,7 @@ sub _select_guts {
                $a->push_content($self->_options_from_hashes($items, $args));
     }
     else { 
                $a->push_content($self->_options_from_hashes($items, $args));
     }
     else { 
-               $a->push_content($self->_options_from_scalars($items, $args));
+               die "You passed a weird type of data structure to me. Here it is: $type";
     }
 
     return $a;
     }
 
     return $a;
@@ -916,7 +1098,7 @@ sub _options_from_objects {
        for (@$items) {
                my $opt = HTML::Element->new("option", value => $_->id);
                $opt->attr(selected => "selected") if $selected->{$_->id}; 
        for (@$items) {
                my $opt = HTML::Element->new("option", value => $_->id);
                $opt->attr(selected => "selected") if $selected->{$_->id}; 
-               my $content = $stringify ? $_->$stringify : "$_";
+               my $content = $stringify ? $_->stringify :  "$_";
                $opt->push_content($content);
                push @res, $opt; 
        }
                $opt->push_content($content);
                push @res, $opt; 
        }
@@ -927,19 +1109,19 @@ sub _options_from_arrays {
     my ($self, $items, $args) = @_;
        my $selected = $args->{selected} || {};
     my @res;
     my ($self, $items, $args) = @_;
        my $selected = $args->{selected} || {};
     my @res;
-       my $fclass = $args->{class} || '';
+       my $class = $args->{class} || '';
        my $stringify = $args->{stringify} || '';
        my $stringify = $args->{stringify} || '';
-       for (@$items) {
-               my $id = $_->[0];
+       for my $item (@$items) {
+           my @pks; # for future multiple key support
+           push @pks, shift @$item foreach $class->columns('Primary');
+               my $id = $pks[0];
+               $id =~ ~ s/^0+//;  # In case zerofill is on .
                my $opt = HTML::Element->new("option", value => $id );
                my $opt = HTML::Element->new("option", value => $id );
-               #$opt->attr(selected => "selected") if $selected =~/^$id$/;
                $opt->attr(selected => "selected") if $selected->{$id};
                $opt->attr(selected => "selected") if $selected->{$id};
-               
-               my $content = ($fclass and $stringify and $fclass->can($stringify)) ? 
-                             $fclass->$stringify($_) : 
-                                 join('/', @{$_});
-use Data::Dumper;
-warn "Content is $content";
+
+               my $content = ($class and $stringify and $class->can($stringify)) ? 
+                             $class->$stringify($_) : 
+                                 join( '/', map { $_ if $_; }@{$item} );
                $opt->push_content( $content );
         push @res, $opt; 
     }
                $opt->push_content( $content );
         push @res, $opt; 
     }
@@ -967,17 +1149,29 @@ sub _options_from_hashes {
        my $fclass = $args->{class} || '';
        my $stringify = $args->{stringify} || '';
        my @res;
        my $fclass = $args->{class} || '';
        my $stringify = $args->{stringify} || '';
        my @res;
-       for my $item (@$items) {
-               my $val = $item->{$pk};
+       for (@$items) {
+               my $val = $_->{$pk};
                my $opt = HTML::Element->new("option", value => $val );
                $opt->attr(selected => "selected") if $selected->{$val};
                my $opt = HTML::Element->new("option", value => $val );
                $opt->attr(selected => "selected") if $selected->{$val};
-               my $content = ( $fclass && $stringify && $fclass->can($stringify)) ? $fclass->$stringify($item) : join(' ', @$item);
+               my $content = ($fclass and $stringify and $fclass->can($stringify)) ? 
+                             $fclass->$stringify($_) :  join(' ', @$_);
                $opt->push_content( $content );
                $opt->push_content( $content );
-        push @res, $opt;
+        push @res, $opt; 
     }
     }
-    return @res;
+       return @res;
 }
 }
-       
+
+sub _to_select_or_create {
+       my ($self, $col, $args) = @_;
+       $args->{name} ||= $col;
+       my $select = $self->to_field($col, 'select', $args);
+       $args->{name} = "create_" . $args->{name};
+       my $create = $self->to_field($col, 'foreign_inputs', $args);
+       $create->{'__select_or_create__'} = 
+               $self->to_field('__select_or_create__',{ name => '__select_or_create__' , value => 1 } );
+       return ($select, $create);
+}
+
 # 
 # checkboxes: if no data in hand (ie called as class method), replace
 # with a radio button, in order to allow this field to be left
 # 
 # checkboxes: if no data in hand (ie called as class method), replace
 # with a radio button, in order to allow this field to be left
@@ -1028,14 +1222,15 @@ sub _to_radio {
 
 _rename_foreign_input($html_el_or_hash_of_them); # changes made by reference
 
 
 _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 
+Recursively renames the foreign inputs made by _to_foreign_inputs so they 
 can be processed generically.  The format is "accessor__AsForeign_colname". 
 
 can be processed generically.  The format is "accessor__AsForeign_colname". 
 
-So if an Employee is a Person who has own  Address and you call 
+So if an Employee is a Person who has_own  Address and you call 
 
   Employee->to_field("person")  
   
 
   Employee->to_field("person")  
   
-then you will get inputs for Address named like this: 
+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__street
   person__AsForeign__address__AsForeign__city
@@ -1043,20 +1238,35 @@ then you will get inputs for Address named like this:
   person__AsForeign__address__AsForeign__zip  
 
 And the processor would know to create this address, put the address id in
   person__AsForeign__address__AsForeign__zip  
 
 And the processor would know to create this address, put the address id in
-person address slot, create the person and put the address id in the employee
-before creating the employee. 
+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.
+
+=head2 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 :) )
 
 =cut
 
 
 =cut
 
+sub make_element_foreign {
+       my ($self, $accssr, $element)  = @_;
+       $element->attr( name => $accssr . "__AsForeign__" . $element->attr('name'));
+}
+
+
+
 sub _rename_foreign_input {
 sub _rename_foreign_input {
-       my ($self, $accssr, $input) = @_;
-       if ( ref $input ne 'HASH' ) {
+       my ($self, $accssr, $element) = @_;
+       if ( ref $element ne 'HASH' ) {
        #       my $new_name = $accssr . "__AsForeign__" . $input->attr('name');
        #       my $new_name = $accssr . "__AsForeign__" . $input->attr('name');
-               $input->attr( name => $accssr . "__AsForeign__" . $input->attr('name'));
+               $self->make_element_foreign($accssr, $element);
        }
        else {
        }
        else {
-               $self->_rename_foreign_input($accssr, $input->{$_}) 
-                       foreach (keys %$input);
+               $self->_rename_foreign_input($accssr, $element->{$_}) 
+                       foreach (keys %$element);
        }
 }
 =head2 _box($value) 
        }
 }
 =head2 _box($value) 
@@ -1092,16 +1302,20 @@ sub _box
 
 1;
 
 
 1;
 
-
 =head1 CHANGES
 
 =head1 CHANGES
 
-=head1 MAINTAINER 
+
+=head1 MAINTAINER
 
 Maypole Developers
 
 
 Maypole Developers
 
-=head1 ORIGINAL AUTHOR
+=head1 AUTHORS
+
+Peter Speltz, Aaron Trevena
 
 
-Peter Speltz, Aaron Trevena 
+=head1 AUTHORS EMERITUS
+
+Simon Cozens, Tony Bowden
 
 =head1 TODO
 
 
 =head1 TODO
 
@@ -1117,11 +1331,12 @@ Peter Speltz, Aaron Trevena
 =head1 BUGS and QUERIES
 
 Please direct all correspondence regarding this module to:
 =head1 BUGS and QUERIES
 
 Please direct all correspondence regarding this module to:
- Maypole list. 
+ Maypole list.
 
 =head1 COPYRIGHT AND LICENSE
 
 
 =head1 COPYRIGHT AND LICENSE
 
-Copyright 2003-2004 by Simon Cozens / Tony Bowden
+Copyright 2003-2004 by Simon Cozens and Tony Bowden
+Copyright 2005-2006 by Aaron Trevena and Peter Speltz
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
 
 This library is free software; you can redistribute it and/or modify
 it under the same terms as Perl itself.
@@ -1131,7 +1346,3 @@ it under the same terms as Perl itself.
 L<Class::DBI>, L<Class::DBI::FromCGI>, L<HTML::Element>.
 
 =cut
 L<Class::DBI>, L<Class::DBI::FromCGI>, L<HTML::Element>.
 
 =cut
-
-\r
-\r
-\r