File Coverage

blib/lib/HTML/FormFu/Model/DBIC.pm
Criterion Covered Total %
statement 484 505 95.8
branch 251 318 78.9
condition 127 184 69.0
subroutine 34 34 100.0
pod 4 5 80.0
total 900 1046 86.0


line stmt bran cond sub pod time code
1             package HTML::FormFu::Model::DBIC;
2              
3 90     90   202720955 use strict;
  90         251  
  90         2892  
4 90     90   486 use warnings;
  90         251  
  90         2779  
5 90     90   482 use base 'HTML::FormFu::Model';
  90         201  
  90         36612  
6              
7             our $VERSION = '2.02'; # VERSION
8              
9 90     90   1409874 use HTML::FormFu::Util qw( _merge_hashes );
  90         243  
  90         4936  
10 90     90   622 use List::MoreUtils qw( none notall );
  90         206  
  90         1024  
11 90     90   54654 use List::Util qw( first );
  90         231  
  90         5114  
12 90     90   553 use Scalar::Util qw( blessed );
  90         197  
  90         3640  
13 90     90   529 use Storable qw( dclone );
  90         219  
  90         3851  
14 90     90   597 use Carp qw( croak );
  90         220  
  90         403750  
15              
16             sub options_from_model {
17 25     25 1 325583 my ( $self, $base, $attrs ) = @_;
18              
19 25         143 my $form = $base->form;
20 25         381 my $resultset = _get_resultset( $base, $form, $attrs );
21 25         9381 my $source = $resultset->result_source;
22              
23 25         72 my $id_col = $attrs->{id_column};
24 25         64 my $label_col = $attrs->{label_column};
25 25         69 my $condition = $attrs->{condition};
26 25   50     189 my $attributes = $attrs->{attributes} || {};
27              
28             my $enum_col =
29             first {
30 1     1   10 lc( $base->name ) eq lc($_);
31             }
32             grep {
33 25         228 my $data_type = $source->column_info($_)->{data_type};
  87         519  
34 87 50       1314 defined $data_type && $data_type =~ /enum/i
35             } $source->columns;
36              
37 25 100       158 if ( defined $enum_col ) {
38             return map {
39 3         22 [ $_, $_ ]
40 1         17 } @{ $source->column_info($enum_col)->{extra}{list} };
  1         4  
41             }
42              
43 24 50       128 if ( !defined $id_col ) {
44 24         303 ($id_col) = $source->primary_columns;
45             }
46              
47 24 50       250 if ( !defined $label_col ) {
48              
49             # use first text column
50             ($label_col) = grep {
51 24         87 my $data_type = $source->column_info($_)->{data_type};
  73         349  
52 73 50       985 defined $data_type && $data_type =~ /text|varchar/i
53             } $source->columns;
54             }
55 24 50       105 $label_col = $id_col if !defined $label_col;
56              
57 24 100       104 if ( defined( my $from_stash = $attrs->{condition_from_stash} ) ) {
58             $condition
59             = $condition
60 6 50       22 ? { %{$condition} }
  0         0  
61             : {}; # avoid overwriting attrs->{condition}
62 6         25 for my $name ( keys %$from_stash ) {
63 6 50       23 croak "config value must not be a reference" if ref $from_stash->{$name};
64 6         26 my $value = $form->stash->{ $from_stash->{$name} };
65 6         80 $condition->{$name} = $value;
66             }
67             }
68              
69             # save the expanded condition for later use
70 24 100       90 $attrs->{'-condition'} = $condition if ($condition);
71              
72 24         87 $attributes->{'-columns'} = [ $id_col, $label_col ];
73              
74 24         154 my $result = $resultset->search( $condition, $attributes );
75              
76 24         7208 my @defaults = $result->all;
77 24         139054 my $has_column = $source->has_column($label_col);
78              
79 24 100       259 if ( $attrs->{localize_label} ) {
80             @defaults = map {
81 1 50       3 { value => $_->get_column($id_col),
  2         33  
82             label_loc => $has_column ? $_->get_column($label_col) : $_->$label_col,
83             }
84             } @defaults;
85             }
86             else {
87 23         62 @defaults = map { [
88 72 50       1027 $_->get_column($id_col),
89             $has_column ? $_->get_column($label_col) : $_->$label_col,
90             ]
91             } @defaults;
92             }
93              
94 24         1495 return @defaults;
95             }
96              
97             sub _get_resultset {
98 25     25   82 my ( $base, $form, $attrs ) = @_;
99              
100 25         132 my $schema = $form->stash->{schema};
101 25         281 my $context = $form->stash->{context};
102              
103 25 100 33     259 if ( defined $schema ) {
    50          
    0          
104 22   66     138 my $rs_name = $attrs->{resultset} || ucfirst $base->name;
105              
106 22         213 return $schema->resultset($rs_name);
107             }
108             elsif ( defined $context && defined $attrs->{model} ) {
109              
110 3         24 my $model = $context->model( $attrs->{model} );
111              
112 3 50       35 if ( defined( my $rs = $attrs->{resultset} ) ) {
113 0         0 $model = $model->resultset($rs);
114             }
115              
116 3         8 return $model;
117             }
118             elsif ( defined $context ) {
119 0         0 my $model = $context->model;
120              
121 0 0       0 return $model if defined $model;
122             }
123              
124 0         0 croak "need a schema or context";
125             }
126              
127             sub default_values {
128 65     65 1 401661 my ( $self, $dbic, $attrs ) = @_;
129              
130 65         410 my $form = $self->form;
131 65 100       846 my $base = defined $attrs->{base} ? delete $attrs->{base} : $form;
132              
133             $base = $form->get_all_element( { nested_name => $attrs->{nested_base} } )
134             if defined $attrs->{nested_base}
135             && ( !defined $base->nested_name
136 65 50 33     431 || $base->nested_name ne $attrs->{nested_base} );
      66        
137              
138 65         9213 _fill_in_fields( $base, $dbic );
139 65         621 _fill_nested( $self, $base, $dbic );
140              
141 65         676 return $form;
142             }
143              
144             # returns 0 if there is a node with nested_name set on the path from $field to $base
145             sub is_direct_child {
146 747     747 0 1539 my ( $base, $field ) = @_;
147              
148 747         2627 while ( defined $field->parent ) {
149 1054         11365 $field = $field->parent;
150              
151 1054 100       7413 return 1 if $base == $field;
152 498 100       15920 return 0 if defined $field->nested_name;
153             }
154             }
155              
156             # fills in values for all direct children fields of $base
157             sub _fill_in_fields {
158 65     65   177 my ( $base, $dbic ) = @_;
159 65         140 for my $field ( @{ $base->get_fields } ) {
  65         378  
160 242         22648 my $name = $field->name;
161 242         2543 my $config = $field->model_config;
162              
163 242 50 66     3486 next if not defined $name || $config->{accessor};
164 241 100       607 next if not is_direct_child( $base, $field );
165              
166 197 100       7591 $name = $field->original_name if $field->original_name;
167              
168 197         3378 my $accessor = $config->{accessor};
169              
170 197 100       2786 if ( defined $accessor ) {
    100          
171 2         12 $field->default( $dbic->$accessor );
172             }
173             elsif ( $dbic->can($name) ) {
174 147         866 my $has_col = $dbic->result_source->has_column($name);
175 147         2316 my $has_rel = $dbic->result_source->has_relationship($name);
176              
177 147 50 66     2440 if ( $has_col && $has_rel ) {
    100 33        
    100 66        
178              
179             # can't use direct accessor, if there's a rel of the same name
180 0         0 $field->default( $dbic->get_column($name) );
181             }
182             elsif ($has_col) {
183 134         2614 $field->default( $dbic->$name );
184             }
185             elsif (
186             $field->multi_value
187             && ($config->{default_column}
188             || ( ref( $dbic->$name )
189             && $dbic->$name->can('result_source') ) ) )
190             {
191              
192             my ($col) = $config->{default_column}
193 9   33     36494 || $dbic->$name->result_source->primary_columns;
194              
195 9         9804 my $info = $dbic->result_source->relationship_info($name);
196              
197 9 100 100     278 if ( !defined $info or $info->{attrs}{accessor} eq 'multi' ) {
198 7         64 my @defaults = $dbic->$name->get_column($col)->all;
199 7         70059 $field->default( \@defaults );
200             }
201             else {
202              
203             # has_one/might_have
204 2         9 my ($pk) = $dbic->result_source->primary_columns;
205 2         70 $field->default( $dbic->$name->$pk );
206             }
207             }
208             else {
209              
210             # This field is a method expected to return the value
211 4         89 $field->default( $dbic->$name );
212             }
213             }
214              
215             # handle {label}
216              
217 197 100       469636 if ( defined( my $label = $config->{label} ) ) {
218 3         11 my $has_rel = $dbic->result_source->has_relationship($label);
219              
220 3 50       32 if ($has_rel) {
221              
222             # can't use direct accessor, if there's a rel of the same name
223 0         0 $field->label( $dbic->get_column($label) );
224             }
225             else {
226 3         54 $field->label( $dbic->$label );
227             }
228             }
229             }
230             }
231              
232             # loop over all child blocks with nested_name that is a method on the DBIC row
233             # and recurse
234             sub _fill_nested {
235 65     65   199 my ( $self, $base, $dbic ) = @_;
236              
237 65         152 for my $block ( @{ $base->get_all_elements } ) {
  65         332  
238 284 100 100     24747 next if $block->is_field && !$block->is_block;
239 49 50       904 next if !$block->can('nested_name');
240              
241 49         295 my $config = $block->model_config;
242              
243             # first handle {label}
244              
245 49 100 66     808 if ( defined( my $label = $config->{label} ) && $block->can('label') ) {
246 1         4 my $has_rel = $dbic->result_source->has_relationship($label);
247              
248 1 50       12 if ($has_rel) {
249              
250             # can't use direct accessor, if there's a rel of the same name
251 0         0 $block->label( $dbic->get_column($label) );
252             }
253             else {
254 1         23 $block->label( $dbic->$label );
255             }
256             }
257              
258 49         1234 my $rel = $block->nested_name;
259 49 100       1192 next if !defined $rel;
260              
261 26   66     140 my $has_rel = $dbic->result_source->relationship_info($rel)
262             || ( $dbic->can($rel) && $dbic->can( 'add_to_' . $rel ) )
263             ; # many_to_many
264              
265             # recursing only when $rel is a relation or non-column accessor on $dbic
266             next
267 26 100 100     749 unless $has_rel
      66        
268             || ( $dbic->can($rel)
269             && !$dbic->result_source->has_column($rel) );
270              
271 20 100 66     612 if ( $block->is_repeatable && $block->increment_field_names ) {
272              
273             # check there's a field name matching the PK
274 13         879 my ($pk) = $dbic->$rel->result_source->primary_columns;
275              
276             next
277             unless grep {
278 15 100       4299 $pk eq
279             ( defined $_->original_name ? $_->original_name : $_->name )
280 13 50       36114 } @{ $block->get_fields( { type => 'Hidden' } ) };
  13         290  
281              
282 13         534 my @rows = $dbic->$rel->all;
283              
284             my $count
285             = $config->{empty_rows}
286             ? scalar @rows + $config->{empty_rows}
287 13 100       104265 : scalar @rows;
288              
289 13         717 my $blocks = $block->repeat($count);
290              
291 13         162819 $block->process;
292              
293 13         17871 for my $rep ( 0 .. $#rows ) {
294 26         165 default_values( $self, $rows[$rep],
295             { base => $blocks->[$rep] } );
296             }
297              
298             # set the counter field to the number of rows
299              
300 13 50       393 if ( defined( my $param_name = $block->counter_name ) ) {
301             my ($field) = grep {
302 124 100       17054 $param_name eq (
303             defined $_->original_name
304             ? $_->original_name
305             : $_->name )
306 13         147 } @{ $base->get_fields };
  13         67  
307              
308 13 50       342 $field->default($count)
309             if defined $field;
310             }
311              
312             # remove 'delete' checkbox from the last repetition ?
313              
314 13 100       350 if ( $config->{empty_rows} ) {
315              
316             my $new_row_count
317             = $config->{empty_rows}
318             ? $config->{empty_rows}
319 3 50       15 : 1;
320              
321 3         7 my @reps = reverse @{ $block->get_elements };
  3         22  
322              
323 3         156 for my $i ( 0 .. ( $new_row_count - 1 ) ) {
324              
325 5         212 my $rep = $reps[$i];
326              
327             my ($del_field)
328 12         852 = grep { $_->model_config->{delete_if_true} }
329 5         10 @{ $rep->get_fields };
  5         29  
330              
331 5 100       93 if ( defined $del_field ) {
332 2         8 $del_field->parent->remove_element($del_field);
333             }
334             }
335             }
336             }
337             else {
338 7 100       141 if ( defined( my $row = $dbic->$rel ) ) {
339 6         21615 default_values( $self, $row, { base => $block } );
340             }
341             }
342             }
343 65         2377 return;
344             }
345              
346             sub create {
347 3     3 1 373055 my ( $self, $attrs ) = @_;
348              
349 3 50       17 croak "invalid arguments" if @_ > 2;
350              
351 3         21 my $form = $self->form;
352 3 50       42 my $base = defined $attrs->{base} ? delete $attrs->{base} : $form;
353              
354             my $schema = $form->stash->{schema}
355 3 50       19 or croak 'schema required on form stash, if no row object provided';
356              
357             my $resultset
358             = $attrs->{resultset}
359             || $base->model_config->{resultset}
360             || $form->model_config->{resultset}
361 3 50 33     74 or croak 'could not find resultset name';
362              
363 3         90 $resultset = $schema->resultset($resultset);
364              
365 3         1318 my $dbic = $resultset->new_result( {} );
366              
367 3         620 return $self->update( $dbic, { %$attrs, base => $base } );
368             }
369              
370             sub update {
371 107     107 1 970656 my ( $self, $dbic, $attrs ) = @_;
372              
373 107 50       479 croak "row object missing" if !defined $dbic;
374              
375 107         625 my $form = $self->form;
376 107 100       1349 my $base = defined $attrs->{base} ? delete $attrs->{base} : $form;
377              
378             $base = $form->get_all_element( { nested_name => $attrs->{nested_base} } )
379             if defined $attrs->{nested_base}
380             && ( !defined $base->nested_name
381 107 100 66     718 || $base->nested_name ne $attrs->{nested_base} );
      66        
382              
383 107         8093 my $rs = $dbic->result_source;
384 107         1272 my @rels = $rs->relationships;
385 107         1390 my @cols = $rs->columns;
386              
387             # check for belongs_to relationships with a required foreign key
388 107         1322 my (@belongs_to_rels, @other_rels);
389              
390 107         290 foreach my $rel (@rels) {
391             # 'fk_columns' is set for belong_to rels in DBIx::Class::Relationship::BelongsTo
392 333         605 my @fk_columns = keys %{ $dbic->relationship_info($rel)->{attrs}{fk_columns} };
  333         7874  
393              
394 333 100       16660 if (@fk_columns) {
395 55         160 push @belongs_to_rels, $rel;
396             } else {
397 278         757 push @other_rels, $rel;
398             }
399             }
400              
401             # add belongs_to rels before insert
402 107 100       520 if (@belongs_to_rels) {
403             # tell _save_relationships not to update $dbic yet, just add the rels
404 28         128 my %attrs = ( %$attrs, no_update => 1 );
405 28         141 _save_relationships( $self, $base, $dbic, $form, $rs, \%attrs, \@belongs_to_rels );
406             }
407              
408              
409 107 100       5085 _save_columns( $base, $dbic, $form ) or return;
410              
411 106         1650 $dbic->update_or_insert;
412              
413 106         218168 _save_relationships( $self, $base, $dbic, $form, $rs, $attrs, \@other_rels );
414              
415 106         13209 _save_multi_value_fields_many_to_many( $base, $dbic, $form, $attrs, \@rels,
416             \@cols );
417              
418 106         28773 _save_repeatable_many_to_many( $self, $base, $dbic, $form, $attrs, \@rels,
419             \@cols );
420              
421             # handle non-rel, non-column, nested_base accessors.
422             # - this highlights a failing of the approach of iterating over
423             # db cols + rels - we should maybe refactor to iterate over
424             # form blocks and fields instead ?
425              
426 106         246 for my $block ( @{ $base->get_all_elements } ) {
  106         399  
427 626 100       28773 next if $block->is_field;
428 121 50       1258 next if !$block->can('nested_name');
429              
430 121         2902 my $rel = $block->nested_name;
431 121 100       1004 next if !defined $rel;
432              
433 80 100       1354 next unless $dbic->can($rel);
434              
435 27 100       92 next if grep { $rel eq $_ } @cols;
  185         414  
436 26 100       79 next if grep { $rel eq $_ } @rels;
  106         359  
437              
438 4 100       45 next if $dbic->can( "add_to_" . $rel ); # many-to-many
439              
440 1 50       6 if ( defined( my $row = $dbic->$rel ) ) {
441 1         5065 update( $self, $row, { base => $block } );
442             }
443             }
444              
445 106         1769 return $dbic;
446             }
447              
448             sub _save_relationships {
449 134     134   487 my ( $self, $base, $dbic, $form, $rs, $attrs, $rels ) = @_;
450              
451 134 50       716 return if $attrs->{no_follow};
452              
453 134         395 for my $rel (@$rels) {
454              
455             # don't follow rels to where we came from
456             next
457             if defined $attrs->{from}
458 332 100 100     10144 && $attrs->{from} eq $rs->related_source($rel)->result_class;
459              
460 298         5417 my @elements = @{ $base->get_all_elements( { nested_name => $rel } ) };
  298         1520  
461              
462 298         471102 my ($block) = grep { !$_->is_field } @elements;
  32         730  
463 298 100       826 my ($multi_value) = grep { $_->is_field && $_->multi_value } @elements;
  32         688  
464 298         1072 my ($combo) = grep { $_->isa('HTML::FormFu::Element::ComboBox') } @elements;
  32         319  
465              
466 298 100 66     1645 next if !defined $block && !defined $multi_value;
467 30 50       166 next if !$form->valid($rel);
468              
469 30         82125 my $params = $form->param($rel);
470              
471 30 100 100     83898 if ( defined $block && $block->is_repeatable ) {
    100 66        
    100          
    50          
472              
473             # Handle has_many
474              
475 15         218 _save_has_many( $self, $dbic, $form, $rs, $block, $rel, $attrs );
476              
477             }
478             elsif ( defined $combo ) {
479              
480 3         15 _save_combobox( $self, $base, $dbic, $form, $rs, $combo, $rel, $attrs );
481             }
482             elsif ( defined $block && ref $params eq 'HASH' ) {
483             # It seems that $dbic->$rel must be called otherwise the following
484             # find_related() can fail.
485             # However, this can die - so we're just wrapping it in an eval
486 8 100       140 eval {
487 8         66 $dbic->$rel;
488             } or $dbic->discard_changes;
489              
490 8         64338 my $target = $dbic->find_related( $rel, {} );
491              
492 8 100 66     23213 if ( !defined $target && grep { length $_ } values %$params ) {
  7         153  
493 6         82 $target = $dbic->new_related( $rel, {} );
494             }
495              
496 8 50       4627 next if !defined $target;
497              
498 8         264 update(
499             $self, $target,
500             { %$attrs,
501             base => $block,
502             nested_base => $rel,
503             from => $dbic->result_class,
504             } );
505 8 100       169 unless ( $dbic->$rel ) {
506 2         2317 $dbic->$rel($target);
507 2 100       989 $dbic->update unless $attrs->{no_update};
508             }
509             }
510             elsif ( defined $multi_value ) {
511              
512             # belongs_to, has_one or might_have relationship
513              
514 4         17 my $info = $dbic->result_source->relationship_info($rel);
515              
516 4         78 my @fpkey = $dbic->related_resultset($rel)
517             ->result_source->primary_columns;
518              
519 4         5139 my @cond = ( %{ $info->{cond} } );
  4         16  
520              
521             # make sure $rel is a has_one or might_have rel
522             # stolen from SQL/Translator/Parser/DBIx/Class
523              
524 4         10 my $fk_constraint;
525              
526             # Get the key information, mapping off the foreign/self markers
527 4         12 my @refkeys = map {/^\w+\.(\w+)$/} @cond;
  8         44  
528 4         21 my @keys = map { $info->{cond}{$_} =~ /^\w+\.(\w+)$/ }
529 4         12 grep { exists $info->{cond}{$_} } @cond;
  8         21  
530              
531             #first it can be specified explicitly
532 4 100 33     48 if ( exists $info->{attrs}{is_foreign_key_constraint} ) {
    50          
533 2         7 $fk_constraint = $info->{attrs}{is_foreign_key_constraint};
534             }
535              
536             # it can not be multi
537             elsif ($info->{attrs}{accessor}
538             && $info->{attrs}{accessor} eq 'multi' )
539             {
540 0         0 $fk_constraint = 0;
541             }
542              
543             # if indeed single, check if all self.columns are our primary keys.
544             # this is supposed to indicate a has_one/might_have...
545             # where's the introspection!!?? :)
546             else {
547 2         10 $fk_constraint
548             = not _compare_relationship_keys( \@keys, \@fpkey );
549             }
550              
551 4 100       23 next if ($fk_constraint);
552              
553 2         5 my $fpkey = shift @fpkey;
554 2         4 my ( $fkey, $skey ) = @cond;
555 2         9 $fkey =~ s/^foreign\.//;
556 2         36 $skey =~ s/^self\.//;
557              
558 2         6 my $fclass = $info->{class};
559              
560 2 50       7 croak
561             'The primary key and the foreign key may not be the same column in class '
562             . $fclass
563             if $fpkey eq $fkey;
564              
565 2 50       7 croak
566             'multiple primary keys are not supported for has_one/might_have relationships'
567             if ( @fpkey > 1 );
568              
569 2         9 my $schema = $dbic->result_source->schema;
570              
571             # use transactions if supported by storage
572             $schema->txn_do(
573             sub {
574              
575             # reset any previous items which were related to $dbic
576 2     2   787 $rs->schema->resultset($fclass)
577             ->search( { $fkey => $dbic->$skey } )
578             ->update( { $fkey => undef } );
579              
580             # set new related item
581 2         3714 my $updated
582             = $rs->schema->resultset($fclass)
583             ->search( { $fpkey => $params } )
584             ->update( { $fkey => $dbic->$skey } );
585              
586 2 100       3869 $schema->txn_rollback
587             if $updated != 1;
588              
589 2         40 } );
590             }
591             }
592             }
593              
594             sub _save_combobox {
595 3     3   13 my ( $self, $base, $dbic, $form, $rs, $combo, $rel, $attrs ) = @_;
596              
597 3         25 my $select = $combo->get_field({ type => 'Select' });
598 3         951 my $text = $combo->get_field({ type => 'Text' });
599              
600 3         805 my $select_value = $form->param( $select->nested_name );
601 3         1008 my $text_value = $form->param( $text->nested_name );
602              
603 3         2785 my $target_rs = $dbic->result_source->related_source( $rel )->resultset;
604 3         1499 my $target;
605              
606 3 100 66     36 if ( defined $select_value && length $select_value ) {
607 2         14 my $pk_name = $combo->model_config->{select_column};
608              
609 2         44 $target = $target_rs->find(
610             {
611             $pk_name => $select_value,
612             },
613             );
614             }
615             else {
616 1         6 my $column_name = $combo->model_config->{text_column};
617              
618 1         21 $target = $target_rs->create(
619             {
620             $column_name => $text_value,
621             },
622             );
623             }
624              
625 3         9688 $dbic->set_from_related( $rel, $target );
626 3         2514 $dbic->update;
627             }
628              
629             # Copied from DBIx::Class::ResultSource
630             sub _compare_relationship_keys {
631 2     2   6 my ( $keys1, $keys2 ) = @_;
632              
633             # Make sure every keys1 is in keys2
634 2         6 my $found;
635 2         6 foreach my $key (@$keys1) {
636 2         5 $found = 0;
637 2         6 foreach my $prim (@$keys2) {
638 2 50       7 if ( $prim eq $key ) {
639 2         6 $found = 1;
640 2         4 last;
641             }
642             }
643 2 50       8 last unless $found;
644             }
645              
646             # Make sure every key2 is in key1
647 2 50       8 if ($found) {
648 2         19 foreach my $prim (@$keys2) {
649 2         5 $found = 0;
650 2         4 foreach my $key (@$keys1) {
651 2 50       8 if ( $prim eq $key ) {
652 2         3 $found = 1;
653 2         6 last;
654             }
655             }
656 2 50       5 last unless $found;
657             }
658             }
659              
660 2         6 return $found;
661             }
662              
663             sub _save_has_many {
664 15     15   63 my ( $self, $dbic, $form, $rs, $block, $rel, $attrs ) = @_;
665              
666 15 50       456 return unless $block->increment_field_names;
667              
668             # check there's a field name matching the PK
669              
670 15         287 my ($pk) = $rs->related_source($rel)->primary_columns;
671              
672             return
673 41         11026 unless grep { $_->original_name eq $pk }
674 15 50       2670 @{ $block->get_fields( { type => 'Hidden' } ) };
  15         92  
675              
676 15         164 my @blocks = @{ $block->get_elements };
  15         148  
677 15         750 my $max = $#blocks;
678 15         106 my $config = $block->model_config;
679              
680 15   100     392 my $new_rows_max = $config->{new_rows_max} || $config->{empty_rows} || 0;
681 15         42 my $new_rows_counter = 0;
682              
683             # iterate over blocks, not rows
684             # new rows might have been created in the meantime
685              
686 15         70 for my $i ( 0 .. $max ) {
687 36         465 my $rep = $blocks[$i];
688              
689             # find PK field
690              
691             my ($pk_field)
692 41         9907 = grep { $_->original_name eq $pk }
693 36         72 @{ $rep->get_fields( { type => 'Hidden' } ) };
  36         187  
694              
695 36 50       403 next if !defined $pk_field;
696              
697 36         160 my $value = $form->param_value( $pk_field->nested_name );
698 36         37232 my $row;
699              
700 36 100 100     541 if (( !defined $value || $value eq '' )
    100 66        
      66        
      66        
701             && ( $new_rows_max
702             && ( ++$new_rows_counter <= $new_rows_max ) ) )
703             {
704              
705             # insert a new row
706 11         49 $row = _insert_has_many( $dbic, $form, $config, $rep, $rel,
707             $pk_field );
708              
709 11 100       237 next if !defined $row;
710             }
711             elsif ( !defined $value || $value eq '' ) {
712 3         14 next;
713             }
714             else {
715 22         344 $row = $dbic->find_related( $rel, $value );
716             }
717 30 50       90933 next if !defined $row;
718              
719             # should we delete the row?
720              
721 30 100       458 next if _delete_has_many( $form, $row, $rep );
722              
723 28         4665 update(
724             $self, $row,
725             { %$attrs,
726             base => $rep,
727             repeat_base => $rel,
728             from => $dbic->result_class,
729             } );
730             }
731             }
732              
733             sub _insert_has_many {
734 11     11   41 my ( $dbic, $form, $config, $repetition, $rel, $pk_field ) = @_;
735              
736             return
737 11 100       47 if !_can_insert_new_row( $dbic, $form, $config, $repetition, $rel,
738             $pk_field );
739              
740 8         98 my $row = $dbic->new_related( $rel, {} );
741              
742 8         7175 return $row;
743             }
744              
745             sub _can_insert_new_row {
746 12     12   36 my ( $dbic, $form, $config, $repetition, $rel, $pk_field ) = @_;
747              
748 12         26 my @rep_fields = @{ $repetition->get_fields };
  12         53  
749              
750 12         1817 my $pk_name = $pk_field->nested_name;
751              
752 2         72 my @constraints = grep { $_->when->{field} eq $pk_name }
753 2         299 grep { defined $_->when }
754 12         3964 map { @{ $_->get_constraints( { type => 'Required' } ) } } @rep_fields;
  24         902  
  24         125  
755              
756 12         568 my @required_fields;
757              
758 12 100       44 if (@constraints) {
759              
760             # if there are any Required constraints whose 'when' clause points to
761             # the PK field - check that all these fields are filled in - as
762             # the PK value is missing on new reps, so the constraint won't have run
763              
764             return
765 2 100   2   5805 if notall { defined && length }
766 2         19 map { $form->param_value( $_->nested_name ) }
767 2 100       12 map { $_->parent } @constraints;
  2         8  
768             }
769             else {
770              
771             # otherwise, just check at least 1 field that matches either a column
772             # name or an accessor, is filled in
773              
774 10         98 my $result_source = $dbic->$rel->result_source;
775              
776             # only create a new record if (read from bottom)...
777              
778             return
779 20 100   20   8455 if none { defined && length }
780 20         8562 map { $form->param_value( $_->nested_name ) }
781             grep {
782 20 50       706 $result_source->has_column( $_->original_name )
783             || $result_source->can( $_->original_name )
784             }
785 10 100       10322 grep { defined $_->original_name } @rep_fields;
  20         834  
786             }
787              
788 9         85 return 1;
789             }
790              
791             sub _delete_has_many {
792 30     30   92 my ( $form, $row, $rep ) = @_;
793              
794             my ($del_field)
795 30         60 = grep { $_->model_config->{delete_if_true} } @{ $rep->get_fields };
  72         6357  
  30         140  
796              
797 30 100       442 return if !defined $del_field;
798              
799 3         11 my $nested_name = $del_field->nested_name;
800              
801             return
802 3 100 66     965 unless $form->valid($nested_name)
803             && $form->param_value($nested_name);
804              
805 2 50       420 $row->delete if ( $row->in_storage );
806              
807 2         2605 return 1;
808             }
809              
810             sub _fix_value {
811 249     249   654 my ( $dbic, $col, $value, $field, ) = @_;
812              
813 249         5252 my $col_info = $dbic->column_info($col);
814 249   100     13151 my $is_nullable = $col_info->{is_nullable} || 0;
815 249   50     795 my $data_type = $col_info->{data_type} || '';
816              
817 249 100       689 if ( defined $value ) {
818 222 100 66     1676 if ( ( ( $is_nullable
      66        
      100        
819             && $data_type =~ m/^timestamp|date|int|float|numeric/i
820             ) or $field->model_config->{null_if_empty} )
821              
822             # comparing to '' does not work for inflated objects
823             && !ref $value
824             && $value eq ''
825             )
826             {
827 1         20 $value = undef;
828             }
829             }
830              
831 249 100 66     3866 if ( !defined $value
      100        
      100        
832             && defined $field
833             && $field->isa('HTML::FormFu::Element::Checkbox')
834             && !$is_nullable )
835             {
836 3         9 $value = 0;
837             }
838              
839 249         661 return $value;
840             }
841              
842             sub _save_columns {
843 107     107   299 my ( $base, $dbic, $form ) = @_;
844              
845 107         355 for my $field ( @{ $base->get_fields }, ) {
  107         566  
846 506 100       79089 next if not is_direct_child( $base, $field );
847              
848 359         4765 my $config = $field->model_config;
849 359 100       5244 next if $config->{delete_if_true};
850 358 100       1015 next if $config->{read_only};
851              
852 356         1225 my $name = $field->name;
853 356 100       12432 $name = $field->original_name if $field->original_name;
854              
855 356   66     6220 my $accessor = $config->{accessor} || $name;
856 356 50       1005 next if not defined $accessor;
857              
858             my $value = ( $dbic->result_source->has_column($accessor)
859             and exists $dbic->result_source->column_info($accessor)->{is_array} )
860 356 100 66     1176 ? $form->param_array( $field->nested_name )
861             : $form->param_value( $field->nested_name ) ;
862              
863             next
864             if $config->{ignore_if_empty}
865 356 100 66     335741 && ( !defined $value || $value eq "" );
      66        
866              
867 355         1350 my ($pk) = $dbic->result_source->primary_columns;
868              
869             # don't set primary key to null or '' - for Pg SERIALs
870 355 100 100     5590 next if ( $name eq $pk ) && !( defined $value && length $value );
      100        
871              
872 338 100 33     1205 if ( $config->{delete_if_empty}
      66        
873             && ( !defined $value || !length $value ) )
874             {
875 1 50       13 $dbic->discard_changes if $dbic->is_changed;
876 1 50       17 $dbic->delete if $dbic->in_storage;
877 1         1541 return;
878             }
879 337 100       876 if ( $dbic->result_source->has_column($accessor) ) {
    100          
880 249         2980 $value = _fix_value( $dbic, $accessor, $value, $field );
881             }
882             elsif ( $field->isa('HTML::FormFu::Element::Checkbox') ) {
883              
884             # We are a checkbox.
885 2 100       29 unless ( defined $value ) {
886 1         3 $value = 0;
887             }
888             }
889              
890 337 100 100     2879 if ( !$config->{accessor}
    100 100        
      100        
      100        
891             and $dbic->result_source->has_relationship($accessor)
892             and $dbic->result_source->has_column($accessor) )
893             {
894 4         93 $dbic->set_column( $accessor, $value );
895             }
896             elsif (
897             $dbic->can($accessor)
898              
899             # and $accessor is not a has_one or might_have rel where the foreign key is on the foreign table
900             and !$dbic->result_source->relationship_info($accessor)
901             and !$dbic->can( 'add_to_' . $accessor ) )
902             {
903 253         14741 $dbic->$accessor($value);
904             }
905             else {
906              
907             # We should just ignore
908             #croak "cannot call $accessor on $dbic";
909             }
910             }
911              
912             # for values inserted by add_valid - and not correlated to any field in the form
913 106         11355 my $parent = $base;
914 106         241 do {
915 106 100       2705 return 1 if defined $parent->nested_name;
916 60         674 $parent = $parent->parent;
917             } until ( !defined $parent );
918              
919 60         632 for my $valid ( $form->valid ) {
920 273 100       95144 next if @{ $base->get_fields( name => $valid ) };
  273         913  
921 101 100       99354 next if not $dbic->can($valid);
922              
923 1         6 my $value = $form->param_value($valid);
924 1         143 $dbic->$valid($value);
925             }
926              
927 60         18904 return 1;
928             }
929              
930             sub _save_multi_value_fields_many_to_many {
931 106     106   342 my ( $base, $dbic, $form, $attrs, $rels, $cols ) = @_;
932              
933             my @fields = grep {
934             ( defined $attrs->{nested_base} && defined $_->parent->nested_name )
935             ? $_->parent->nested_name eq $attrs->{nested_base}
936 63 100 66     4351 : !$_->nested
937             }
938 505         15251 grep { $_->multi_value }
939 106         265 grep { defined $_->name } @{ $base->get_fields };
  505         40825  
  106         513  
940              
941 106         3272 for my $field (@fields) {
942 46         155 my $name = $field->name;
943              
944 46 100       329 next if grep { $name eq $_ } @$rels, @$cols;
  778         1425  
945              
946 8 50       69 if ( $dbic->can($name) ) {
947 8         47 my $related = $dbic->$name;
948              
949 8 100 66     22261 next if !blessed($related) || !$related->can('result_source');
950              
951 6         34 my $nested_name = $field->nested_name;
952              
953 6 50       1132 next if $form->has_errors($nested_name);
954              
955 6         7527 my @values = $form->param_list($nested_name);
956 6         2807 my @rows;
957              
958 6         38 my $config = $field->model_config;
959              
960 6 100       120 next if $config->{read_only};
961              
962             my ($pk) = $config->{default_column}
963 5   33     58 || $related->result_source->primary_columns;
964              
965 5 100       126 if (@values) {
966              
967 3 50       21 $pk = "me.$pk" unless $pk =~ /\./;
968              
969             @rows = $related->result_source->resultset->search( {
970 3 100       23 %{ $config->{condition} || {} },
  3         866  
971             $pk => { -in => \@values } } )->all;
972             }
973              
974 5 50       19536 if ( $config->{additive} ) {
975 0         0 $pk =~ s/^.*\.//;
976              
977 0         0 my $set_method = "add_to_$name";
978 0         0 my $remove_method = "remove_from_$name";
979              
980 0         0 foreach my $row (@rows) {
981 0         0 $dbic->$remove_method($row);
982 0         0 $dbic->$set_method( $row, $config->{link_values} );
983             }
984             }
985             else {
986              
987             # check if there is a restricting condition on here
988             # if so life is more complex
989 5         242 my $condition = $config->{'-condition'};
990 5 100       19 if ($condition) {
991 1         3 my $set_method = "add_to_$name";
992 1         2 my $remove_method = "remove_from_$name";
993 1         5 foreach ( $dbic->$name->search($condition)->all ) {
994 1         7344 $dbic->$remove_method($_);
995             }
996 1         2982 foreach my $row (@rows) {
997 1         64 $dbic->$set_method( $row, $config->{link_values} );
998             }
999             }
1000             else {
1001 4         17 my $set_method = "set_$name";
1002 4         38 $dbic->$set_method( \@rows, $config->{link_values} );
1003             }
1004             }
1005             }
1006             }
1007             }
1008              
1009             sub _save_repeatable_many_to_many {
1010 106     106   350 my ( $self, $base, $dbic, $form, $attrs, $rels, $cols ) = @_;
1011              
1012             my @blocks
1013 626 100 100     33437 = grep { !$_->is_field && $_->is_repeatable && $_->increment_field_names }
1014 106         218 @{ $base->get_all_elements };
  106         466  
1015              
1016 106         1038 for my $block (@blocks) {
1017 22         831 my $rel = $block->nested_name;
1018              
1019 22 50       218 next if !defined $rel;
1020 22 100       74 next if grep { $rel eq $_ } @$rels, @$cols;
  209         522  
1021              
1022 7 100       137 if ( $dbic->can($rel) ) {
1023              
1024             # check there's a field name matching the PK
1025              
1026 3         22 my ($pk) = $dbic->$rel->result_source->primary_columns;
1027              
1028 3         11911 my @blocks = @{ $block->get_elements };
  3         74  
1029 3         191 my $max = $#blocks;
1030              
1031             # iterate over blocks, not rows
1032             # new rows might have been created in the meantime
1033              
1034 3         11 for my $i ( 0 .. $max ) {
1035 7         127 my $rep = $blocks[$i];
1036              
1037             # find PK field
1038              
1039             my ($pk_field)
1040 12         2627 = grep { $_->original_name eq $pk }
1041 7         16 @{ $rep->get_fields( { type => 'Hidden' } ) };
  7         41  
1042              
1043 7 50       78 next if !defined $pk_field;
1044              
1045 7         30 my $value = $form->param_value( $pk_field->nested_name );
1046 7         3585 my $row;
1047             my $is_new;
1048              
1049 7         50 my $config = $block->model_config;
1050             my $new_rows_max
1051             = $config->{new_rows_max}
1052             || $config->{empty_rows}
1053 7   50     148 || 0;
1054 7         16 my $new_rows_counter = 0;
1055              
1056 7 100 66     107 if (( !defined $value || $value eq '' )
    50 33        
      66        
      33        
1057             && ( $new_rows_max
1058             && ( ++$new_rows_counter <= $new_rows_max ) ) )
1059             {
1060              
1061             # insert a new row
1062 1         7 $row = _insert_many_to_many( $dbic, $form, $config, $rep,
1063             $rel, $pk_field );
1064              
1065 1 50       24 next if !defined $row;
1066              
1067 1         2 $is_new = 1;
1068             }
1069             elsif ( !defined $value || $value eq '' ) {
1070 0         0 next;
1071             }
1072             else {
1073 6         37 $row = $dbic->$rel->find($value);
1074             }
1075 7 50       52618 next if !defined $row;
1076              
1077             # should we delete the row?
1078              
1079 7 50       143 next if _delete_many_to_many( $form, $dbic, $row, $rel, $rep );
1080              
1081 7         192 update(
1082             $self, $row,
1083             { %$attrs,
1084             base => $rep,
1085             repeat_base => $rel,
1086             from => $dbic->result_class,
1087             } );
1088              
1089 7 100       93 if ($is_new) {
1090              
1091             # new rows need to be related
1092 1         5 my $add_method = "add_to_$rel";
1093              
1094 1         6 $dbic->$add_method($row);
1095             }
1096             }
1097             }
1098             }
1099 106         3516 return;
1100             }
1101              
1102             sub _insert_many_to_many {
1103 1     1   5 my ( $dbic, $form, $config, $repetition, $rel, $pk_field ) = @_;
1104              
1105             return
1106 1 50       5 if !_can_insert_new_row( $dbic, $form, $config, $repetition, $rel,
1107             $pk_field );
1108              
1109 1         6 my $row = $dbic->$rel->new( {} );
1110              
1111             # add_to_* will be called later, after update is called on this row
1112              
1113 1         2240 return $row;
1114             }
1115              
1116             sub _delete_many_to_many {
1117 7     7   26 my ( $form, $dbic, $row, $rel, $rep ) = @_;
1118              
1119             my ($del_field)
1120 7         15 = grep { $_->model_config->{delete_if_true} } @{ $rep->get_fields };
  22         2104  
  7         40  
1121              
1122 7 50       108 return if !defined $del_field;
1123              
1124 0           my $nested_name = $del_field->nested_name;
1125              
1126             return
1127 0 0 0       unless $form->valid($nested_name)
1128             && $form->param_value($nested_name);
1129              
1130 0           my $remove = "remove_from_$rel";
1131              
1132 0           $dbic->$remove($row);
1133              
1134 0           return 1;
1135             }
1136              
1137             1;
1138              
1139             __END__
1140              
1141             =head1 NAME
1142              
1143             HTML::FormFu::Model::DBIC - Integrate HTML::FormFu with DBIx::Class
1144              
1145             =head1 VERSION
1146              
1147             version 2.02
1148              
1149             =head1 SYNOPSIS
1150              
1151             Example of typical use in a Catalyst controller:
1152              
1153             sub edit : Chained {
1154             my ( $self, $c ) = @_;
1155              
1156             my $form = $c->stash->{form};
1157             my $book = $c->stash->{book};
1158              
1159             if ( $form->submitted_and_valid ) {
1160              
1161             # update dbic row with submitted values from form
1162              
1163             $form->model->update( $book );
1164              
1165             $c->response->redirect( $c->uri_for('view', $book->id) );
1166             return;
1167             }
1168             elsif ( !$form->submitted ) {
1169              
1170             # use dbic row to set form's default values
1171              
1172             $form->model->default_values( $book );
1173             }
1174              
1175             return;
1176             }
1177              
1178             =head1 SETUP
1179              
1180             For the form object to be able to access your L<DBIx::Class> schema, it needs
1181             to be placed on the form stash, with the name C<schema>.
1182              
1183             This is easy if you're using L<Catalyst-Controller-HTML-FormFu>, as you can
1184             set this up to happen in your Catalyst app's config file.
1185              
1186             For example, if your model is named C<MyApp::Model::Corp>, you would set this
1187             (in L<Config::General> format):
1188              
1189             <Controller::HTML::FormFu>
1190             <model_stash>
1191             schema Corp
1192             </model_stash>
1193             </Controller::HTML::FormFu>
1194              
1195             Or if your app's config file is in L<YAML> format:
1196              
1197             'Controller::HTML::FormFu':
1198             model_stash:
1199             schema: Corp
1200              
1201             =head1 METHODS
1202              
1203             =head2 default_values
1204              
1205             Arguments: $dbic_row, [\%config]
1206              
1207             Return Value: $form
1208              
1209             $form->model->default_values( $dbic_row );
1210              
1211             Set a form's default values from the database, to allow a user to edit them.
1212              
1213             =head2 update
1214              
1215             Arguments: [$dbic_row], [\%config]
1216              
1217             Return Value: $dbic_row
1218              
1219             $form->model->update( $dbic_row );
1220              
1221             Update the database with the submitted form values.
1222              
1223             =head2 create
1224              
1225             Arguments: [\%config]
1226              
1227             Return Value: $dbic_row
1228              
1229             my $dbic_row = $form->model->create( {resultset => 'Book'} );
1230              
1231             Like L</update>, but doesn't require a C<$dbic_row> argument.
1232              
1233             You need to ensure the DBIC schema is available on the form stash - see
1234             L</SYNOPSIS> for an example config.
1235              
1236             The C<resultset> must be set either in the method arguments, or the form or
1237             block's C<model_config>.
1238              
1239             An example of setting the ResultSet name on a Form:
1240              
1241             ---
1242             model_config:
1243             resultset: FooTable
1244              
1245             elements:
1246             # [snip]
1247              
1248             =head2 options_from_model
1249              
1250             Populates a multi-valued field with values from the database.
1251              
1252             This method should not be called directly, but is called for you during
1253             C<< $form->process >> by fields that inherit from
1254             L<HTML::FormFu::Element::_Group>. This includes:
1255              
1256             =over
1257              
1258             =item L<HTML::FormFu::Element::Select>
1259              
1260             =item L<HTML::FormFu::Element::Checkboxgroup>
1261              
1262             =item L<HTML::FormFu::Element::Radiogroup>
1263              
1264             =item L<HTML::FormFu::Element::ComboBox>
1265              
1266             =back
1267              
1268             To use you must set the appropriate C<resultset> on the element C<model_config>:
1269              
1270             element:
1271             - type: Select
1272             name: foo
1273             model_config:
1274             resultset: TableClass
1275              
1276             =head1 BUILDING FORMS
1277              
1278             =head2 single table
1279              
1280             To edit the values in a row with no related rows, the field names simply have
1281             to correspond to the database column names.
1282              
1283             For the following DBIx::Class schema:
1284              
1285             package MySchema::Book;
1286             use base 'DBIx::Class';
1287              
1288             __PACKAGE__->load_components(qw/ Core /);
1289              
1290             __PACKAGE__->table("book");
1291              
1292             __PACKAGE__->add_columns(
1293             id => { data_type => "INTEGER" },
1294             title => { data_type => "TEXT" },
1295             author => { data_type => "TEXT" },
1296             blurb => { data_type => "TEXT" },
1297             );
1298              
1299             __PACKAGE__->set_primary_key("id");
1300              
1301             1;
1302              
1303             A suitable form for this might be:
1304              
1305             elements:
1306             - type: Text
1307             name: title
1308              
1309             - type: Text
1310             name: author
1311              
1312             - type: Textarea
1313             name: blurb
1314              
1315             =head2 might_have and has_one relationships
1316              
1317             Set field values from a related row with a C<might_have> or C<has_one>
1318             relationship by placing the fields within a
1319             L<Block|HTML::FormFu::Element::Block> (or any element that inherits from
1320             Block, such as L<Fieldset|HTML::FormFu::Element::Fieldset>) with its
1321             L<HTML::FormFu/nested_name> set to the relationship name.
1322              
1323             For the following DBIx::Class schemas:
1324              
1325             package MySchema::Book;
1326             use base 'DBIx::Class';
1327              
1328             __PACKAGE__->load_components(qw/ Core /);
1329              
1330             __PACKAGE__->table("book");
1331              
1332             __PACKAGE__->add_columns(
1333             id => { data_type => "INTEGER" },
1334             title => { data_type => "TEXT" },
1335             );
1336              
1337             __PACKAGE__->set_primary_key("id");
1338              
1339             __PACKAGE__->might_have( review => 'MySchema::Review', 'book' );
1340              
1341             1;
1342              
1343              
1344             package MySchema::Review;
1345             use base 'DBIx::Class';
1346              
1347             __PACKAGE__->load_components(qw/ Core /);
1348              
1349             __PACKAGE__->table("review");
1350              
1351             __PACKAGE__->add_columns(
1352             id => { data_type => "INTEGER" },
1353             book => { data_type => "INTEGER", is_nullable => 1 },
1354             review_text => { data_type => "TEXT" },
1355             );
1356              
1357             __PACKAGE__->set_primary_key("book");
1358              
1359             __PACKAGE__->belongs_to( book => 'MySchema::Book' );
1360              
1361             1;
1362              
1363             A suitable form for this would be:
1364              
1365             elements:
1366             - type: Text
1367             name: title
1368              
1369             - type: Block
1370             nested_name: review
1371             elements:
1372             - type: Textarea
1373             name: review_text
1374              
1375             For C<might_have> and C<has_one> relationships, you generally shouldn't need
1376             to have a field for the related table's primary key, as DBIx::Class will
1377             handle retrieving the correct row automatically.
1378              
1379             You can also set a C<has_one> or C<might_have> relationship using a multi value
1380             field like L<Select|HTML::FormFu::Element::Select>.
1381              
1382             elements:
1383             - type: Text
1384             name: title
1385              
1386             - type: Select
1387             nested: review
1388             model_config:
1389             resultset: Review
1390              
1391             This will load all reviews into the select field. If you select a review from
1392             that list, a current relationship to a review is removed and the new one is
1393             added. This requires that the primary key of the C<Review> table and the
1394             foreign key do not match.
1395              
1396             =head2 has_many and many_to_many relationships
1397              
1398             The general principle is the same as for C<might_have> and C<has_one> above,
1399             except you should use a L<Repeatable|HTML::FormFu::Element::Repeatable>
1400             element instead of a Block, and it needs to contain a
1401             L<Hidden|HTML::FormFu::Element::Hidden> field corresponding to the primary key
1402             of the related table.
1403              
1404             The Repeatable block's
1405             L<nested_name|HTML::FormFu::Element::Repeatable/nested_name> must be set to the
1406             name of the relationship.
1407              
1408             The Repeable block's
1409             L<increment_field_names|HTML::FormFu::Element::Repeatable/increment_field_names>
1410             must be true (which is the default value).
1411              
1412             The Repeable block's
1413             L<counter_name|HTML::FormFu::Element::Repeatable/counter_name> must be set to
1414             the name of a L<Hidden|HTML::FormFu::Element::Hidden> field, which is placed
1415             outside of the Repeatable block.
1416             This field is used to store a count of the number of repetitions of the
1417             Repeatable block were created.
1418             When the form is submitted, this value is used during C<< $form->process >>
1419             to ensure the form is rebuilt with the correct number of repetitions.
1420              
1421             To allow the user to add new related rows, either C<empty_rows> or
1422             C<new_rows_max> must be set - see L</"Config options for Repeatable blocks">
1423             below.
1424              
1425             For the following DBIx::Class schemas:
1426              
1427             package MySchema::Book;
1428             use base 'DBIx::Class';
1429              
1430             __PACKAGE__->load_components(qw/ Core /);
1431              
1432             __PACKAGE__->table("book");
1433              
1434             __PACKAGE__->add_columns(
1435             id => { data_type => "INTEGER" },
1436             title => { data_type => "TEXT" },
1437             );
1438              
1439             __PACKAGE__->set_primary_key("id");
1440              
1441             __PACKAGE__->has_many( review => 'MySchema::Review', 'book' );
1442              
1443             1;
1444              
1445              
1446             package MySchema::Review;
1447             use base 'DBIx::Class';
1448              
1449             __PACKAGE__->load_components(qw/ Core /);
1450              
1451             __PACKAGE__->table("review");
1452              
1453             __PACKAGE__->add_columns(
1454             book => { data_type => "INTEGER" },
1455             review_text => { data_type => "TEXT" },
1456             );
1457              
1458             __PACKAGE__->set_primary_key("book");
1459              
1460             __PACKAGE__->belongs_to( book => 'MySchema::Book' );
1461              
1462             1;
1463              
1464             A suitable form for this might be:
1465              
1466             elements:
1467             - type: Text
1468             name: title
1469              
1470             - type: Hidden
1471             name: review_count
1472              
1473             - type: Repeatable
1474             nested_name: review
1475             counter_name: review_count
1476             model_config:
1477             empty_rows: 1
1478             elements:
1479             - type: Hidden
1480             name: book
1481              
1482             - type: Textarea
1483             name: review_text
1484              
1485             =head2 belongs_to relationships
1486              
1487             Belongs-to relationships can be edited / created with a ComboBox element.
1488             If the user selects a value with the Select field, the belongs-to will be set
1489             to an already-existing row in the related table.
1490             If the user enters a value into the Text field, the belongs-to will be set
1491             using a newly-created row in the related table.
1492              
1493             elements:
1494             - type: ComboBox
1495             name: author
1496             model_config:
1497             resultset: Author
1498             select_column: id
1499             text_column: name
1500              
1501             The element name should match the relationship name.
1502             C<< $field->model_config->{select_column} >> should match the related primary
1503             column.
1504             C<< $field->model_config->{text_column} >> should match the related text
1505             column.
1506              
1507             =head2 many_to_many selection
1508              
1509             To select / deselect rows from a C<many_to_many> relationship, you must use
1510             a multi-valued element, such as a
1511             L<Checkboxgroup|HTML::FormFu::Element::Checkboxgroup> or a
1512             L<Select|HTML::FormFu::Element::Select> with
1513             L<multiple|HTML::FormFu::Element::Select/multiple> set.
1514              
1515             The field's L<name|HTML::FormFu::Element::_Field/name> must be set to the
1516             name of the C<many_to_many> relationship.
1517              
1518             =head3 default_column
1519              
1520             If you want to search / associate the related table by a column other it's
1521             primary key, set C<< $field->model_config->{default_column} >>.
1522              
1523             ---
1524             element:
1525             - type: Checkboxgroup
1526             name: authors
1527             model_config:
1528             default_column: foo
1529              
1530             =head3 link_values
1531              
1532             If you want to set columns on the link table you can do so if you add a
1533             C<link_values> attribute to C<model_config>:
1534              
1535             ---
1536             element:
1537             - type: Checkboxgroup
1538             name: authors
1539             model_config:
1540             link_values:
1541             foo: bar
1542              
1543             =head3 additive
1544              
1545             The default implementation will first remove all related objects and set the
1546             new ones (see L<http://search.cpan.org/perldoc?DBIx::Class::Relationship::Base#set_$rel>).
1547             If you want to add the selected objects to the current set of objects
1548             set C<additive> in the C<model_config>.
1549              
1550             ---
1551             element:
1552             - type: Checkboxgroup
1553             name: authors
1554             model_config:
1555             additive: 1
1556             options_from_model: 0
1557              
1558             L</options_from_model> is set to C<0> because it will try to fetch
1559             all objects from the result class C<Authors> if C<model_config> is specified
1560             without a C<resultset> attribute.)
1561              
1562             =head1 COMMON ARGUMENTS
1563              
1564             The following items are supported in the optional C<config> hash-ref argument
1565             to the methods L<default_values>, L<update> and L<create>.
1566              
1567             =over
1568              
1569             =item base
1570              
1571             If you want the method to process a particular Block element, rather than the
1572             whole form, you can pass the element as a C<base> argument.
1573              
1574             $form->default_values(
1575             $row,
1576             {
1577             base => $formfu_element,
1578             },
1579             );
1580              
1581             =item nested_base
1582              
1583             If you want the method to process a particular Block element by
1584             L<name|HTML::FormFu::Element/name>, you can pass the name as an argument.
1585              
1586             $form->default_values(
1587             $row,
1588             {
1589             nested_base => 'foo',
1590             }'
1591             );
1592              
1593             =back
1594              
1595             =head1 CONFIGURATION
1596              
1597             =head2 Config options for fields
1598              
1599             The following items are supported as C<model_config> options on form fields.
1600              
1601             =over
1602              
1603             =item accessor
1604              
1605             If set, C<accessor> will be used as a method-name accessor on the
1606             C<DBIx::Class> row object, instead of using the field name.
1607              
1608             =item ignore_if_empty
1609              
1610             If the submitted value is blank, no attempt will be made to save it to the database.
1611              
1612             =item null_if_empty
1613              
1614             If the submitted value is blank, save it as NULL to the database. Normally an empty string is saved as NULL when its corresponding field is numeric, and as an empty string when its corresponding field is a text field. This option is useful for changing the default behavior for text fields.
1615              
1616             =item delete_if_empty
1617              
1618             Useful for editing a "might_have" related row containing only one field.
1619              
1620             If the submitted value is blank, the related row is deleted.
1621              
1622             For the following DBIx::Class schemas:
1623              
1624             package MySchema::Book;
1625             use base 'DBIx::Class';
1626              
1627             __PACKAGE__->load_components(qw/ Core /);
1628              
1629             __PACKAGE__->table("book");
1630              
1631             __PACKAGE__->add_columns(
1632             id => { data_type => "INTEGER" },
1633             title => { data_type => "TEXT" },
1634             );
1635              
1636             __PACKAGE__->set_primary_key("id");
1637              
1638             __PACKAGE__->might_have( review => 'MySchema::Review', 'book' );
1639              
1640             1;
1641              
1642              
1643             package MySchema::Review;
1644             use base 'DBIx::Class';
1645              
1646             __PACKAGE__->load_components(qw/ Core /);
1647              
1648             __PACKAGE__->table("review");
1649              
1650             __PACKAGE__->add_columns(
1651             book => { data_type => "INTEGER" },
1652             review_text => { data_type => "TEXT" },
1653             );
1654              
1655             __PACKAGE__->set_primary_key("book");
1656              
1657             __PACKAGE__->belongs_to( book => 'MySchema::Book' );
1658              
1659             1;
1660              
1661             A suitable form for this would be:
1662              
1663             elements:
1664             - type: Text
1665             name: title
1666              
1667             - type: Block
1668             nested_name: review
1669             elements:
1670             - type: Text
1671             name: review_text
1672             model_config:
1673             delete_if_empty: 1
1674              
1675             =item label
1676              
1677             To use a column value for a form field's
1678             L<label|HTML::FormFu::Element::_Field/label>.
1679              
1680             =back
1681              
1682             =head2 Config options for fields within a Repeatable block
1683              
1684             =over
1685              
1686             =item delete_if_true
1687              
1688             Intended for use on a L<Checkbox|HTML::FormFu::Element::Checkbox> field.
1689              
1690             If the checkbox is checked, the following occurs: for a has-many relationship,
1691             the related row is deleted; for a many-to-many relationship, the relationship
1692             link is removed.
1693              
1694             An example of use might be:
1695              
1696             elements:
1697             - type: Text
1698             name: title
1699              
1700             - type: Hidden
1701             name: review_count
1702              
1703             - type: Repeatable
1704             nested_name: review
1705             counter_name: review_count
1706             elements:
1707             - type: Hidden
1708             name: book
1709              
1710             - type: Textarea
1711             name: review_text
1712              
1713             - type: Checkbox
1714             name: delete_review
1715             label: 'Delete Review?'
1716             model_config:
1717             delete_if_true: 1
1718              
1719             Note: make sure the name of this field does not clash with one of your
1720             L<DBIx::Class::Row> method names (e.g. "delete") - see L</CAVEATS>.
1721              
1722             =back
1723              
1724             =head2 Config options for Repeatable blocks
1725              
1726             =over
1727              
1728             =item empty_rows
1729              
1730             For a Repeatable block corresponding to a has-many or many-to-many
1731             relationship, to allow the user to insert new rows, set C<empty_rows> to
1732             the number of extra repetitions you wish added to the end of the Repeatable
1733             block.
1734              
1735             =item new_rows_max
1736              
1737             Set to the maximum number of new rows that a Repeatable block is allowed to
1738             add.
1739              
1740             If not set, it will fallback to the value of C<empty_rows>.
1741              
1742             =back
1743              
1744             =head2 Config options for options_from_model
1745              
1746             The column used for the element values is set with the C<model_config>
1747             value C<id_column> - or if not set, the table's primary column is used.
1748              
1749             element:
1750             - type: Select
1751             name: foo
1752             model_config:
1753             resultset: TableClass
1754             id_column: pk_col
1755              
1756             The column used for the element labels is set with the C<model_config>
1757             value C<label_column> - or if not set, the first text/varchar column found
1758             in the table is used - or if one is not found, the C<id_column> is used
1759             instead.
1760              
1761             element:
1762             - type: Select
1763             name: foo
1764             model_config:
1765             resultset: TableClass
1766             label_column: label_col
1767              
1768             To pass the database label values via the form's localization object, set
1769             C<localize_label>
1770              
1771             element:
1772             - type: Select
1773             name: foo
1774             model_config:
1775             localize_label: 1
1776              
1777             You can set a C<condition>, which will be passed as the 1st argument to
1778             L<DBIx::Class::ResultSet/search>.
1779              
1780             element:
1781             - type: Select
1782             name: foo
1783             model_config:
1784             resultset: TableClass
1785             condition:
1786             type: is_foo
1787              
1788             You can set a C<condition_from_stash>, which will be passed as the 1st argument to
1789             L<DBIx::Class::ResultSet/search>.
1790              
1791             C<key> is the column-name to be passed to
1792             L<search|DBIx::Class::ResultSet/search>,
1793             and C<stash_key> is the name of a key on the form L<stash|HTML::FormFu/stash>
1794             from which the value to be passed to L<search|DBIx::Class::ResultSet/search>
1795             is found.
1796              
1797             element:
1798             - type: Select
1799             name: foo
1800             model_config:
1801             resultset: TableClass
1802             condition_from_stash:
1803             key: stash_key
1804              
1805             Is comparable to:
1806              
1807             $form->element({
1808             type => 'Select',
1809             name => 'foo',
1810             model_config => {
1811             resultset => 'TableClass',
1812             condition => {
1813             key => $form->stash->{stash_key}
1814             }
1815             }
1816             })
1817              
1818             You can set C<attributes>, which will be passed as the 2nd argument to
1819             L<DBIx::Class::ResultSet/search>.
1820              
1821             =head3 ENUM Column Type
1822              
1823             If the field name matches (case-insensitive) a column name with type 'ENUM'
1824             and the Schema contains enum values in
1825             C<< $resultset->column_info($name)->{extra}{list} >>, the field's options
1826             will be populated with the enum values.
1827              
1828             =head1 FAQ
1829              
1830             =head2 Add extra values not in the form
1831              
1832             To update values to the database which weren't submitted to the form,
1833             you can first add them to the form with L<add_valid|HTML::FormFu/add_valid>.
1834              
1835             my $passwd = generate_passwd();
1836              
1837             $form->add_valid( passwd => $passwd );
1838              
1839             $form->model->update( $row );
1840              
1841             C<add_valid> works for fieldnames that don't exist in the form.
1842              
1843             =head2 Set a field read only
1844              
1845             You can make a field read only. The value of such fields cannot be changed by
1846             the user even if they submit a value for it.
1847              
1848             $field->model_config->{read_only} = 1;
1849              
1850             - Name: field
1851             model_config:
1852             read_only: 1
1853              
1854             See L<HTML::FormFu::Element::Label>.
1855              
1856             =head1 CAVEATS
1857              
1858             To ensure your column's inflators and deflators are called, we have to
1859             get / set values using their named methods, and not with C<get_column> /
1860             C<set_column>.
1861              
1862             Because of this, beware of having column names which clash with DBIx::Class
1863             built-in method-names, such as C<delete>. - It will have obviously
1864             undesirable results!
1865              
1866             =head1 REMOVED METHODS
1867              
1868             =head2 new_empty_row
1869              
1870             See C<empty_rows> in L</"Config options for Repeatable blocks"> instead.
1871              
1872             =head2 new_empty_row_multi
1873              
1874             See C<new_rows_max> in L</"Config options for Repeatable blocks"> instead.
1875              
1876             =head2 Range constraint
1877              
1878             See C<empty_rows> in L</"Config options for Repeatable blocks"> instead.
1879              
1880             =head1 SUPPORT
1881              
1882             Project Page:
1883              
1884             L<http://code.google.com/p/html-formfu/>
1885              
1886             Mailing list:
1887              
1888             L<http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/html-formfu>
1889              
1890             Mailing list archives:
1891              
1892             L<http://lists.scsys.co.uk/pipermail/html-formfu/>
1893              
1894             =head1 BUGS
1895              
1896             Please submit bugs / feature requests to
1897             L<http://code.google.com/p/html-formfu/issues/list> (preferred) or
1898             L<http://rt.perl.org>.
1899              
1900             =head1 GITHUB REPOSITORY
1901              
1902             This module's sourcecode is maintained in a git repository at
1903             L<git://github.com/fireartist/HTML-FormFu-Model-DBIC.git>
1904              
1905             The project page is L<https://github.com/fireartist/HTML-FormFu-Model-DBIC>
1906              
1907             =head1 SEE ALSO
1908              
1909             L<HTML::FormFu>, L<DBIx::Class>, L<Catalyst::Controller::HTML::FormFu>
1910              
1911             =head1 AUTHOR
1912              
1913             Carl Franks
1914              
1915             =head1 CONTRIBUTORS
1916              
1917             Based on the code of C<DBIx::Class::HTML::FormFu>, which was contributed to
1918             by:
1919              
1920             Adam Herzog
1921              
1922             Daisuke Maki
1923              
1924             Mario Minati
1925              
1926             =head1 COPYRIGHT AND LICENSE
1927              
1928             Copyright (C) 2007 by Carl Franks
1929              
1930             Based on the original source code of L<DBIx::Class::HTMLWidget>, copyright
1931             Thomas Klausner.
1932              
1933             This library is free software; you can redistribute it and/or modify
1934             it under the same terms as Perl itself, either Perl version 5.8.8 or,
1935             at your option, any later version of Perl 5 you may have available.
1936              
1937              
1938             =cut