File Coverage

lib/CallBackery/GuiPlugin/AbstractForm.pm
Criterion Covered Total %
statement 24 106 22.6
branch 0 40 0.0
condition 0 10 0.0
subroutine 8 18 44.4
pod 6 6 100.0
total 38 180 21.1


line stmt bran cond sub pod time code
1             package CallBackery::GuiPlugin::AbstractForm;
2 1     1   574 use Carp qw(carp croak);
  1         3  
  1         60  
3 1     1   8 use CallBackery::Translate qw(trm);
  1         2  
  1         42  
4 1     1   6 use CallBackery::Exception qw(mkerror);
  1         2  
  1         35  
5 1     1   19 use Mojo::Promise;
  1         3  
  1         8  
6 1     1   36 use Mojo::JSON qw(encode_json);
  1         3  
  1         52  
7 1     1   8 use Mojo::Util qw(dumper);
  1         1  
  1         53  
8 1     1   7 use Time::HiRes;
  1         2  
  1         6  
9              
10             =head1 NAME
11              
12             CallBackery::GuiPlugin::AbstractForm - form base class
13              
14             =head1 SYNOPSIS
15              
16             use Mojo::Base 'CallBackery::GuiPlugin::AbstractForm';
17              
18             =head1 DESCRIPTION
19              
20             The base class for gui forms.
21              
22             =cut
23              
24 1     1   101 use Mojo::Base 'CallBackery::GuiPlugin::AbstractAction', -signatures;
  1         3  
  1         7  
25              
26             =head1 ATTRIBUTES
27              
28             The attributes of the L class plus:
29              
30             =head2 screenCfg
31              
32             Returns a configuration structure for the form. The output from this
33             method is fed to the callbackery.ui.form.Auto object to build the
34             Qooxdoo form.
35              
36             =cut
37              
38             has screenCfg => sub {
39             my $self = shift;
40             my $cfg = $self->SUPER::screenCfg;
41             $cfg->{type} = 'form';
42             $cfg->{form} = $self->formCfg;
43             return $cfg;
44             };
45              
46             =head2 formCfg
47              
48             Returns the content of the form.
49              
50             =cut
51              
52             has formCfg => sub {
53             [];
54             };
55              
56             =head2 formCfg
57              
58             TODOC
59              
60             =cut
61              
62             has formCfgMap => sub {
63             my $self = shift;
64             my %map;
65             for my $row (@{$self->formCfg}){
66             next unless $row->{key};
67             $map{$row->{key}} = $row;
68             }
69             return \%map;
70             };
71              
72              
73             =head1 METHODS
74              
75             All the methods of L plus:
76              
77             =cut
78              
79             =head2 validateData(fieldName,formData)
80              
81             If the given value is valid for the field, return undef else return
82             an error message.
83              
84             =cut
85              
86             sub validateData {
87 0     0 1   my $self = shift;
88 0           my $fieldName = shift;
89 0   0       my $formData = shift || {};
90 0           my $entry = $self->formCfgMap->{$fieldName};
91 0 0         if (not ref $entry){
92 0           die mkerror(4095,trm("sorry, don't know the field you are talking about"));
93             }
94 0 0 0       return if not $entry->{set}{required} and (not defined $formData->{$fieldName} or length($formData->{$fieldName}) == 0);
      0        
95 0 0         if ($entry->{validator}){
96 0           my $start = time;
97 0           my $data = $entry->{validator}->($formData->{$fieldName},$fieldName,$formData);
98 0           $self->log->debug(sprintf("validator %s: %0.2fs",$fieldName,time-$start));
99 0           return $data;
100             }
101 0           return;
102             }
103              
104             =head2 processData($args)
105              
106             The default behavior of the method is to validate all the form fields
107             and then store the data into the config database.
108              
109             =cut
110              
111             sub processData {
112 0     0 1   my $self = shift;
113 0           my $args = shift;
114 0 0         $self->args($args) if $args;
115 0           my $form = $self->formCfgMap;
116 0           my $formData = $args->{formData};
117             # this is only to be sure ... data should be pre-validated
118 0           for my $key (keys %$form){
119 0 0         if (my $error = $self->validateData($key,$formData)){
120 0           die mkerror(7492,$error);
121             }
122             }
123 0 0         if ($args->{key}){
124 0           my $handler = $self->actionCfgMap->{$args->{key}}{actionHandler};
125 0 0         if (ref $handler eq 'CODE'){
126 0           return $handler->($self,$formData);
127             }
128 0           $handler = $self->actionCfgMap->{$args->{key}}{handler};
129 0 0         if (ref $handler eq 'CODE'){
130 0           $self->log->warn("Using handler properties in actionCfg is deprecated. Use actionHandler instead.");
131 0           return $handler->($formData);
132             }
133 0           $self->log->error('Plugin instance '.$self->name." action $args->{key} has a broken handler");
134 0           die mkerror(7623,'Plugin instance '.$self->name." action $args->{key} has a broken handler");
135             }
136             }
137              
138              
139             =head2 saveFormDataToConfig(data)
140              
141             Save all the form fields for which is available to the config
142             database. Keys will be prefixed by the plugin instance name
143             (C).
144              
145             =cut
146              
147             sub saveFormDataToConfig {
148 0     0 1   my $self = shift;
149 0           my $formData = shift;
150 0           my $form = $self->formCfgMap;
151 0           for my $key (keys %$form){
152 0 0         next if not exists $formData->{$key};
153 0           $self->setConfigValue($self->name.'::'.$key,$formData->{$key});
154             }
155             }
156              
157             =head2 getFieldValue(field)
158              
159             Fetch the current value of the field. This will either use the getter
160             method supplied in the form config or try to fetch the value from the
161             config database.
162              
163             =cut
164              
165             sub getFieldValue {
166 0     0 1   my $self = shift;
167 0           my $field = shift;
168 0           my $entry = $self->formCfgMap->{$field};
169 0 0         return undef unless ref $entry eq 'HASH';
170 0 0         if ($entry->{getter}){
171 0 0         if (ref $entry->{getter} eq 'CODE'){
172 0           my $start = time;
173 0           my $data = $entry->{getter}->($self);
174 0 0         if (eval { blessed $data && $data->isa('Mojo::Promise')}){
  0 0          
175 0     0     $data = $data->then(sub ($value) {
  0            
  0            
176 0           $self->log->debug(sprintf("async getter %s: %0.2fs",$field,time-$start));
177 0           return $value;
178 0           });
179             }
180             else {
181 0           $self->log->debug(sprintf("getter %s: %0.2fs",$field,time-$start));
182             }
183 0           return $data;
184             }
185             else {
186 0           $self->log->warn('Plugin instance'.$self->name." field $field has a broken getter\n");
187             }
188             }
189 0           return $self->getConfigValue($self->name.'::'.$field);
190             }
191              
192             =head2 getAllFieldValues
193              
194             Return all field values of the form.
195              
196             =cut
197              
198             sub getAllFieldValues {
199 0     0 1   my $self = shift;
200 0           my $parentForm = shift;
201 0           my $currentForm = shift;
202 0           my %map;
203             my @promises;
204 0 0         $self->args($currentForm) if $currentForm;
205 0           for my $key (keys %{$self->formCfgMap}){
  0            
206 0           my $value = $self->getFieldValue($key);
207 0 0         if (eval { blessed $value && $value->isa('Mojo::Promise')}){
  0 0          
208 0           push @promises, $value;
209             $value->then(
210             sub{
211 0     0     $map{$key} = shift;
212             },
213             sub {
214 0     0     die shift;
215             }
216 0           );
217             }
218             else {
219 0           $map{$key} = $self->getFieldValue($key);
220             }
221             }
222 0 0         if (@promises){
223             return Mojo::Promise->new->all(@promises)->then(sub {
224 0     0     return \%map;
225 0           });
226             }
227 0           return \%map;
228             }
229              
230             =head2 getData (type,field)
231              
232             Return the value of the given field. If no field name is specified
233             return a hash with all the current data known to the plugin.
234              
235             =cut
236              
237             sub getData {
238 0     0 1   my $self = shift;
239 0           my $type = shift;
240 0 0         if ($type eq 'field'){
    0          
241 0           return $self->getFieldValue(@_);
242             }
243             elsif ($type eq 'allFields') {
244 0           return $self->getAllFieldValues(@_);
245             }
246             else {
247 0   0       die mkerror(38334, 'Requested unknown data type ' . ($type // 'unknown'));
248             }
249             }
250              
251             1;
252             __END__