line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package RapidApp::Module::StorCmp; |
2
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
# ABSTRACT: Base class for modules with a Ext.data.Store |
4
|
|
|
|
|
|
|
|
5
|
5
|
|
|
5
|
|
3623
|
use strict; |
|
5
|
|
|
|
|
15
|
|
|
5
|
|
|
|
|
159
|
|
6
|
5
|
|
|
5
|
|
30
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
132
|
|
7
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
28
|
use Moose; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
32
|
|
9
|
|
|
|
|
|
|
extends 'RapidApp::Module::ExtComponent'; |
10
|
|
|
|
|
|
|
|
11
|
5
|
|
|
5
|
|
32642
|
use RapidApp::Util qw(:all); |
|
5
|
|
|
|
|
14
|
|
|
5
|
|
|
|
|
2454
|
|
12
|
5
|
|
|
5
|
|
41
|
use Clone qw(clone); |
|
5
|
|
|
|
|
12
|
|
|
5
|
|
|
|
|
267
|
|
13
|
|
|
|
|
|
|
|
14
|
5
|
|
|
5
|
|
2954
|
use RapidApp::Module::DatStor; |
|
5
|
|
|
|
|
22
|
|
|
5
|
|
|
|
|
6157
|
|
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
has 'no_datastore_plus_plugin', is => 'ro', isa => 'Bool', lazy => 1, default => 0; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has 'TableSpec' => ( is => 'ro', isa => 'Maybe[RapidApp::TableSpec]', lazy_build => 1 ); |
19
|
11
|
|
|
11
|
|
332
|
sub _build_TableSpec { undef; } |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
has 'TableSpec_applied' => ( is => 'rw', isa => 'Bool', default => 0 ); |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
has 'record_pk' => ( is => 'ro', default => 'id' ); |
24
|
|
|
|
|
|
|
has 'DataStore_class' => ( is => 'ro', default => 'RapidApp::Module::DatStor' ); |
25
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
has 'max_pagesize' => ( is => 'ro', isa => 'Maybe[Int]', default => undef ); |
27
|
|
|
|
|
|
|
|
28
|
|
|
|
|
|
|
has 'persist_all_immediately' => ( is => 'ro', isa => 'Bool', default => 0 ); |
29
|
|
|
|
|
|
|
has 'persist_immediately' => ( is => 'ro', isa => 'HashRef', default => sub{{ |
30
|
|
|
|
|
|
|
create => \0, |
31
|
|
|
|
|
|
|
update => \0, |
32
|
|
|
|
|
|
|
destroy => \0 |
33
|
|
|
|
|
|
|
}}); |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
# New option added in GitHub Issue #85 |
36
|
|
|
|
|
|
|
has 'dedicated_add_form_enabled', is => 'ro', isa => 'Bool', default => 1; |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
# use_add_form/use_edit_form: 'tab', 'window' or undef |
39
|
|
|
|
|
|
|
has 'use_add_form', is => 'ro', isa => 'Maybe[Str]', lazy => 1, default => undef; |
40
|
|
|
|
|
|
|
has 'use_edit_form', is => 'ro', isa => 'Maybe[Str]', lazy => 1, default => undef; |
41
|
|
|
|
|
|
|
has 'autoload_added_record', default => sub { |
42
|
|
|
|
|
|
|
my $self = shift; |
43
|
|
|
|
|
|
|
# Default to the same value as 'use_add_form' |
44
|
|
|
|
|
|
|
return $self->use_add_form ? 1 : 0; |
45
|
|
|
|
|
|
|
}, is => 'ro', isa => 'Bool', lazy => 1; |
46
|
|
|
|
|
|
|
|
47
|
|
|
|
|
|
|
has 'allow_batch_update', is => 'ro', isa => 'Bool', default => 1; |
48
|
|
|
|
|
|
|
has 'batch_update_max_rows', is => 'ro', isa => 'Int', default => 500; |
49
|
|
|
|
|
|
|
has 'confirm_on_destroy', is => 'ro', isa => 'Bool', default => 1; |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
# not implimented yet: |
52
|
|
|
|
|
|
|
#has 'batch_update_warn_rows', is => 'ro', isa => 'Int', default => 100; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# If cache_total_count is true the total count query will be skipped and the value supplied |
55
|
|
|
|
|
|
|
# by the client (if defined) will be returned instead. The code and logic to do the actual |
56
|
|
|
|
|
|
|
# caching is in JavaScript, and utilization of this feature currently is only implemented |
57
|
|
|
|
|
|
|
# within DbicLink2: |
58
|
|
|
|
|
|
|
has 'cache_total_count', is => 'ro', isa => 'Bool', default => 1; |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
has 'DataStore' => ( |
61
|
|
|
|
|
|
|
is => 'rw', |
62
|
|
|
|
|
|
|
isa => 'RapidApp::Module::DatStor', |
63
|
|
|
|
|
|
|
handles => { |
64
|
|
|
|
|
|
|
JsonStore => 'JsonStore', |
65
|
|
|
|
|
|
|
# store_read => 'store_read', |
66
|
|
|
|
|
|
|
# store_read_raw => 'store_read_raw', |
67
|
|
|
|
|
|
|
columns => 'columns', |
68
|
|
|
|
|
|
|
column_order => 'column_order', |
69
|
|
|
|
|
|
|
multisort_enabled => 'multisort_enabled', |
70
|
|
|
|
|
|
|
sorters => 'sorters', |
71
|
|
|
|
|
|
|
include_columns => 'include_columns', |
72
|
|
|
|
|
|
|
exclude_columns => 'exclude_columns', |
73
|
|
|
|
|
|
|
include_columns_hash => 'include_columns_hash', |
74
|
|
|
|
|
|
|
exclude_columns_hash => 'exclude_columns_hash', |
75
|
|
|
|
|
|
|
apply_columns => 'apply_columns', |
76
|
|
|
|
|
|
|
column_list => 'column_list', |
77
|
|
|
|
|
|
|
apply_to_all_columns => 'apply_to_all_columns', |
78
|
|
|
|
|
|
|
applyIf_to_all_columns => 'applyIf_to_all_columns', |
79
|
|
|
|
|
|
|
apply_columns_list => 'apply_columns_list', |
80
|
|
|
|
|
|
|
set_sort => 'set_sort', |
81
|
|
|
|
|
|
|
batch_apply_opts => 'batch_apply_opts', |
82
|
|
|
|
|
|
|
set_columns_order => 'set_columns_order', |
83
|
|
|
|
|
|
|
# record_pk => 'record_pk', |
84
|
|
|
|
|
|
|
getStore => 'getStore', |
85
|
|
|
|
|
|
|
getStore_code => 'getStore_code', |
86
|
|
|
|
|
|
|
getStore_func => 'getStore_func', |
87
|
|
|
|
|
|
|
store_load_code => 'store_load_code', |
88
|
|
|
|
|
|
|
store_listeners => 'listeners', |
89
|
|
|
|
|
|
|
apply_store_listeners => 'apply_listeners', |
90
|
|
|
|
|
|
|
apply_store_config => 'apply_extconfig', |
91
|
|
|
|
|
|
|
valid_colname => 'valid_colname', |
92
|
|
|
|
|
|
|
apply_columns_ordered => 'apply_columns_ordered', |
93
|
|
|
|
|
|
|
batch_apply_opts_existing => 'batch_apply_opts_existing', |
94
|
|
|
|
|
|
|
delete_columns => 'delete_columns', |
95
|
|
|
|
|
|
|
has_column => 'has_column', |
96
|
|
|
|
|
|
|
get_column => 'get_column', |
97
|
|
|
|
|
|
|
deleted_column_names => 'deleted_column_names', |
98
|
|
|
|
|
|
|
column_name_list => 'column_name_list', |
99
|
|
|
|
|
|
|
get_columns_wildcards => 'get_columns_wildcards', |
100
|
|
|
|
|
|
|
apply_coderef_columns => 'apply_coderef_columns' |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
} |
103
|
|
|
|
|
|
|
); |
104
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
has 'DataStore_build_params' => ( is => 'ro', default => undef, isa => 'Maybe[HashRef]' ); |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
has 'defer_to_store_module' => ( is => 'ro', isa => 'Maybe[Object]', lazy => 1, default => undef ); |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
around 'columns' => \&defer_store_around_modifier; |
111
|
|
|
|
|
|
|
around 'column_order' => \&defer_store_around_modifier; |
112
|
|
|
|
|
|
|
around 'has_column' => \&defer_store_around_modifier; |
113
|
|
|
|
|
|
|
around 'get_column' => \&defer_store_around_modifier; |
114
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
sub defer_store_around_modifier { |
116
|
253
|
|
|
253
|
|
3155
|
my $orig = shift; |
117
|
253
|
|
|
|
|
409
|
my $self = shift; |
118
|
253
|
50
|
|
|
|
7785
|
return $self->$orig(@_) unless (defined $self->defer_to_store_module); |
119
|
0
|
|
|
|
|
0
|
return $self->defer_to_store_module->$orig(@_); |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
# We are doing it this way so we can hook into this exact spot with method modifiers in other places: |
124
|
|
|
|
|
|
|
sub BUILD {} |
125
|
|
|
|
|
|
|
before 'BUILD' => sub { (shift)->DataStore2_BUILD }; |
126
|
|
|
|
|
|
|
sub DataStore2_BUILD { |
127
|
103
|
|
|
103
|
0
|
1084
|
my $self = shift; |
128
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# New for #85: |
130
|
103
|
50
|
|
|
|
3663
|
$self->apply_actions( add => 'dedicated_add_form' ) if ($self->dedicated_add_form_enabled); |
131
|
|
|
|
|
|
|
|
132
|
103
|
|
|
|
|
3309
|
my $store_params = { |
133
|
|
|
|
|
|
|
record_pk => $self->record_pk, |
134
|
|
|
|
|
|
|
max_pagesize => $self->max_pagesize |
135
|
|
|
|
|
|
|
}; |
136
|
|
|
|
|
|
|
|
137
|
103
|
50
|
|
|
|
926
|
if ($self->can('create_records')) { |
138
|
0
|
0
|
|
|
|
0
|
$self->apply_flags( can_create => 1 ) unless ($self->flag_defined('can_create')); |
139
|
0
|
0
|
|
|
|
0
|
$store_params->{create_handler} = RapidApp::Handler->new( scope => $self, method => 'create_records' ) if ($self->has_flag('can_create')); |
140
|
|
|
|
|
|
|
} |
141
|
|
|
|
|
|
|
|
142
|
103
|
50
|
|
|
|
658
|
if ($self->can('read_records')) { |
143
|
103
|
50
|
|
|
|
3831
|
$self->apply_flags( can_read => 1 ) unless ($self->flag_defined('can_read')); |
144
|
103
|
50
|
|
|
|
3706
|
$store_params->{read_handler} = RapidApp::Handler->new( scope => $self, method => 'read_records' ) if ($self->has_flag('can_read')); |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
|
147
|
103
|
50
|
|
|
|
1618
|
if ($self->can('update_records')) { |
148
|
0
|
0
|
|
|
|
0
|
$self->apply_flags( can_update => 1 ) unless ($self->flag_defined('can_update')); |
149
|
0
|
0
|
|
|
|
0
|
$store_params->{update_handler} = RapidApp::Handler->new( scope => $self, method => 'update_records' ) if ($self->has_flag('can_update')); |
150
|
|
|
|
|
|
|
} |
151
|
|
|
|
|
|
|
|
152
|
103
|
50
|
|
|
|
650
|
if ($self->can('destroy_records')) { |
153
|
0
|
0
|
|
|
|
0
|
$self->apply_flags( can_destroy => 1 ) unless ($self->flag_defined('can_destroy')); |
154
|
0
|
0
|
|
|
|
0
|
$store_params->{destroy_handler} = RapidApp::Handler->new( scope => $self, method => 'destroy_records' ) if ($self->has_flag('can_destroy')); |
155
|
|
|
|
|
|
|
} |
156
|
|
|
|
|
|
|
|
157
|
|
|
|
|
|
|
$store_params = { |
158
|
|
|
|
|
|
|
%$store_params, |
159
|
103
|
100
|
|
|
|
3422
|
%{ $self->DataStore_build_params } |
|
97
|
|
|
|
|
3036
|
|
160
|
|
|
|
|
|
|
} if (defined $self->DataStore_build_params); |
161
|
|
|
|
|
|
|
|
162
|
103
|
|
|
|
|
3367
|
$self->apply_modules( store => { |
163
|
|
|
|
|
|
|
class => $self->DataStore_class, |
164
|
|
|
|
|
|
|
params => $store_params |
165
|
|
|
|
|
|
|
}); |
166
|
103
|
|
|
|
|
785
|
$self->DataStore($self->Module('store',1)); |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
#init the store with all of our flags: |
169
|
103
|
|
|
|
|
2929
|
$self->DataStore->apply_flags($self->all_flags); |
170
|
|
|
|
|
|
|
|
171
|
103
|
|
|
|
|
672
|
$self->add_ONREQUEST_calls('store_init_onrequest'); |
172
|
103
|
|
|
|
|
763
|
$self->add_ONREQUEST_calls_late('apply_store_to_extconfig'); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Init (but don't apply) TableSpec early |
175
|
103
|
|
|
|
|
3480
|
$self->TableSpec; |
176
|
|
|
|
|
|
|
} |
177
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
after 'BUILD' => sub { |
180
|
|
|
|
|
|
|
my $self = shift; |
181
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
$self->apply_extconfig( |
183
|
|
|
|
|
|
|
persist_all_immediately => \scalar($self->persist_all_immediately), |
184
|
|
|
|
|
|
|
persist_immediately => $self->persist_immediately, |
185
|
|
|
|
|
|
|
use_add_form => $self->use_add_form, |
186
|
|
|
|
|
|
|
use_edit_form => $self->use_edit_form, |
187
|
|
|
|
|
|
|
autoload_added_record => $self->autoload_added_record ? \1 : \0, |
188
|
|
|
|
|
|
|
cache_total_count => $self->cache_total_count ? \1 : \0, |
189
|
|
|
|
|
|
|
confirm_on_destroy => $self->confirm_on_destroy ? \1 : \0 |
190
|
|
|
|
|
|
|
); |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
## Apply the TableSpec if its defined ## |
193
|
|
|
|
|
|
|
$self->apply_TableSpec_config; |
194
|
|
|
|
|
|
|
|
195
|
|
|
|
|
|
|
if(defined $self->Module('store',1)->create_handler) { |
196
|
|
|
|
|
|
|
$self->apply_actions( add_form => 'get_add_form' ); |
197
|
|
|
|
|
|
|
$self->apply_extconfig( add_form_url => $self->suburl('add_form') ); |
198
|
|
|
|
|
|
|
} |
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
if($self->allow_batch_update && defined $self->Module('store',1)->update_handler) { |
201
|
|
|
|
|
|
|
$self->apply_actions( edit_form => 'get_edit_form' ); |
202
|
|
|
|
|
|
|
$self->apply_extconfig( edit_form_url => $self->suburl('edit_form') ); |
203
|
|
|
|
|
|
|
|
204
|
|
|
|
|
|
|
$self->apply_actions( batch_update => 'batch_update' ); |
205
|
|
|
|
|
|
|
$self->apply_extconfig( batch_update_url => $self->suburl('batch_update') ); |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
$self->add_plugin( 'datastore-plus' ) unless ($self->no_datastore_plus_plugin); |
209
|
|
|
|
|
|
|
}; |
210
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
sub apply_TableSpec_config { |
213
|
103
|
|
|
103
|
0
|
234
|
my $self = shift; |
214
|
103
|
100
|
|
|
|
3187
|
$self->TableSpec or return; |
215
|
92
|
50
|
|
|
|
2884
|
$self->TableSpec_applied and return; |
216
|
|
|
|
|
|
|
|
217
|
92
|
|
|
|
|
1135
|
my $prop_names = [ @RapidApp::Module::DatStor::Column::attrs ]; |
218
|
92
|
|
|
|
|
2738
|
my $columns = $self->TableSpec->columns_properties_limited($prop_names); |
219
|
|
|
|
|
|
|
|
220
|
92
|
|
|
|
|
2137
|
$self->apply_columns($columns); |
221
|
92
|
|
|
|
|
3233
|
$self->set_columns_order(0,$self->TableSpec->column_names_ordered); |
222
|
|
|
|
|
|
|
|
223
|
92
|
50
|
|
|
|
3062
|
$self->DataStore->add_onrequest_columns_mungers( |
224
|
|
|
|
|
|
|
$self->TableSpec->all_onrequest_columns_mungers |
225
|
|
|
|
|
|
|
) unless ($self->TableSpec->has_no_onrequest_columns_mungers); |
226
|
|
|
|
|
|
|
|
227
|
92
|
|
|
|
|
2896
|
$self->TableSpec_applied(1); |
228
|
|
|
|
|
|
|
} |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
sub defer_DataStore { |
232
|
66
|
|
|
66
|
0
|
135
|
my $self = shift; |
233
|
66
|
50
|
|
|
|
2013
|
return $self->DataStore unless (defined $self->defer_to_store_module); |
234
|
0
|
0
|
|
|
|
0
|
return $self->defer_to_store_module->defer_DataStore if ($self->defer_to_store_module->can('defer_DataStore')); |
235
|
0
|
|
|
|
|
0
|
return $self->defer_to_store_module; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
sub store_init_onrequest { |
239
|
33
|
|
|
33
|
0
|
1970
|
my $self = shift; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Simulate direct ONREQUEST: |
242
|
33
|
|
|
|
|
175
|
$self->Module('store'); |
243
|
|
|
|
|
|
|
|
244
|
33
|
|
|
|
|
261
|
$self->apply_extconfig( columns => $self->defer_DataStore->column_list ); |
245
|
33
|
|
|
|
|
411
|
$self->apply_extconfig( sort => $self->defer_DataStore->get_extconfig_param('sort_spec') ); |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
|
249
|
|
|
|
|
|
|
# ---- |
250
|
|
|
|
|
|
|
# NEW: use Tie::IxHash to setup the extconfig hash to be ordered with the 'store' |
251
|
|
|
|
|
|
|
# key predeclared as the first key. Because the ExtJS client decodes and processes |
252
|
|
|
|
|
|
|
# JSON in order, we want to make sure the store is processed before other parts |
253
|
|
|
|
|
|
|
# which may need to reference it by storeId. This is needed after perl 5.18 because |
254
|
|
|
|
|
|
|
# the order of hashes was changed in that version. We just happened to be lucky |
255
|
|
|
|
|
|
|
# that the order before 5.18 just happened to have the store key showup earlier |
256
|
|
|
|
|
|
|
# than we happened to be using it. After 5.18, its random. This solves the problem |
257
|
|
|
|
|
|
|
# once and for all. (Note: the case where this was a problem was in cases of |
258
|
|
|
|
|
|
|
# several nested modules maing use of defer_to_store_module feature which is not |
259
|
|
|
|
|
|
|
# a common use-case, so this was only an issue for very specific circumstances) |
260
|
|
|
|
|
|
|
has '+extconfig', default => sub { |
261
|
5
|
|
|
5
|
|
1412
|
use Tie::IxHash; |
|
5
|
|
|
|
|
4911
|
|
|
5
|
|
|
|
|
6738
|
|
262
|
|
|
|
|
|
|
my %cfg; |
263
|
|
|
|
|
|
|
tie(%cfg, 'Tie::IxHash', store => undef ); |
264
|
|
|
|
|
|
|
return \%cfg |
265
|
|
|
|
|
|
|
}; |
266
|
|
|
|
|
|
|
# ---- |
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
sub apply_store_to_extconfig { |
269
|
33
|
|
|
33
|
0
|
92
|
my $self = shift; |
270
|
|
|
|
|
|
|
|
271
|
33
|
50
|
|
|
|
1082
|
if (defined $self->defer_to_store_module) { |
272
|
0
|
|
|
|
|
0
|
$self->apply_extconfig( store => $self->defer_DataStore->getStore_func ); |
273
|
|
|
|
|
|
|
} |
274
|
|
|
|
|
|
|
else { |
275
|
33
|
|
|
|
|
167
|
$self->apply_extconfig( store => $self->Module('store')->JsonStore ); |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
has 'add_edit_formpanel_defaults', is => 'ro', isa => 'HashRef', lazy => 1, default => sub {{ |
281
|
|
|
|
|
|
|
xtype => 'form', |
282
|
|
|
|
|
|
|
frame => \1, |
283
|
|
|
|
|
|
|
labelAlign => 'right', |
284
|
|
|
|
|
|
|
labelWidth => 100, |
285
|
|
|
|
|
|
|
plugins => ['dynamic-label-width'], |
286
|
|
|
|
|
|
|
bodyStyle => 'padding: 25px 10px 5px 5px;', |
287
|
|
|
|
|
|
|
cls => 'ra-datastore-add-edit-form', |
288
|
|
|
|
|
|
|
defaults => { |
289
|
|
|
|
|
|
|
width => 250 |
290
|
|
|
|
|
|
|
}, |
291
|
|
|
|
|
|
|
autoScroll => \1, |
292
|
|
|
|
|
|
|
monitorValid => \1, |
293
|
|
|
|
|
|
|
buttonAlign => 'center', |
294
|
|
|
|
|
|
|
minButtonWidth => 100, |
295
|
|
|
|
|
|
|
|
296
|
|
|
|
|
|
|
# datastore-plus (client side) adds handlers based on the "name" properties 'save' and 'cancel' below |
297
|
|
|
|
|
|
|
buttons => [ |
298
|
|
|
|
|
|
|
{ |
299
|
|
|
|
|
|
|
name => 'save', |
300
|
|
|
|
|
|
|
text => 'Save', |
301
|
|
|
|
|
|
|
iconCls => 'ra-icon-save-ok', |
302
|
|
|
|
|
|
|
formBind => \1 |
303
|
|
|
|
|
|
|
}, |
304
|
|
|
|
|
|
|
{ |
305
|
|
|
|
|
|
|
name => 'cancel', |
306
|
|
|
|
|
|
|
text => 'Cancel', |
307
|
|
|
|
|
|
|
} |
308
|
|
|
|
|
|
|
] |
309
|
|
|
|
|
|
|
}}; |
310
|
|
|
|
|
|
|
|
311
|
|
|
|
|
|
|
sub get_add_edit_form_items { |
312
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
313
|
0
|
|
|
|
|
|
my $mode = shift; |
314
|
0
|
0
|
0
|
|
|
|
die '$mode should be "add" or "edit"' unless ($mode eq 'add' || $mode eq 'edit'); |
315
|
|
|
|
|
|
|
|
316
|
0
|
|
|
|
|
|
my $allow_flag = "allow_$mode"; |
317
|
|
|
|
|
|
|
|
318
|
0
|
|
|
|
|
|
my @items = (); |
319
|
|
|
|
|
|
|
|
320
|
0
|
|
|
|
|
|
foreach my $colname (@{$self->column_order}) { |
|
0
|
|
|
|
|
|
|
321
|
0
|
0
|
|
|
|
|
my $Cnf = $self->columns->{$colname} or next; |
322
|
0
|
0
|
0
|
|
|
|
next unless (defined $Cnf->{editor} and $Cnf->{editor} ne ''); |
323
|
|
|
|
|
|
|
|
324
|
0
|
|
|
|
|
|
my $allow = jstrue($Cnf->{$allow_flag}); |
325
|
|
|
|
|
|
|
$allow = $allow || jstrue($Cnf->{allow_batchedit}) if ( |
326
|
|
|
|
|
|
|
$mode eq 'edit' && |
327
|
|
|
|
|
|
|
!jstrue($Cnf->{no_column}) |
328
|
0
|
0
|
0
|
|
|
|
); |
|
|
|
0
|
|
|
|
|
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
#Skip columns with 'no_column' set to true except if $allow_flag is true: |
331
|
0
|
0
|
0
|
|
|
|
next if (jstrue($Cnf->{no_column}) && ! $allow); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
#Skip if $allow_flag is defined but set to false: |
334
|
0
|
0
|
0
|
|
|
|
next if (defined $Cnf->{$allow_flag} && ! $allow); |
335
|
|
|
|
|
|
|
|
336
|
0
|
|
|
|
|
|
my $field = clone($Cnf->{editor}); |
337
|
0
|
|
|
|
|
|
$field->{name} = $colname; |
338
|
0
|
0
|
|
|
|
|
$field->{allowBlank} = \1 unless (defined $field->{allowBlank}); |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
# New, extra check for newly added 'is_nullable' column attr (Github Issue #33) |
341
|
0
|
0
|
|
|
|
|
$field->{allowBlank} = \0 unless ($Cnf->{is_nullable}); |
342
|
|
|
|
|
|
|
|
343
|
0
|
0
|
|
|
|
|
unless (jstrue $field->{allowBlank}) { |
344
|
0
|
0
|
|
|
|
|
$field->{labelStyle} = '' unless (defined $field->{labelStyle}); |
345
|
0
|
|
|
|
|
|
$field->{labelStyle} .= 'font-weight:bold;'; |
346
|
|
|
|
|
|
|
} |
347
|
0
|
0
|
|
|
|
|
$field->{header} = $Cnf->{header} if(defined $Cnf->{header}); |
348
|
0
|
0
|
0
|
|
|
|
$field->{header} = $colname unless (defined $field->{header} and $field->{header} ne ''); |
349
|
0
|
|
|
|
|
|
$field->{fieldLabel} = $field->{header}; |
350
|
0
|
|
|
|
|
|
$field->{anchor} = '-20'; |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
# ---- Moved from DataStorePlus JS (client-side): |
353
|
|
|
|
|
|
|
# Important: autoDestroy must be false on the store or else store-driven |
354
|
|
|
|
|
|
|
# components (i.e. combos) will be broken as soon as the form is closed |
355
|
|
|
|
|
|
|
# the first time |
356
|
0
|
0
|
|
|
|
|
$field->{store}{autoDestroy} = \1 if ($field->{store}); |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
# Make sure that hidden fields that can't be changed don't |
359
|
|
|
|
|
|
|
# block validation of the form if they are empty and erroneously |
360
|
|
|
|
|
|
|
# set with allowBlank: false (common-sense failsafe): |
361
|
0
|
0
|
|
|
|
|
$field->{allowBlank} = \1 if (jstrue $field->{hidden}); |
362
|
|
|
|
|
|
|
# ---- |
363
|
|
|
|
|
|
|
|
364
|
|
|
|
|
|
|
# -- New: if column 'documentation' is present, render it via Ext.ux.FieldHelp plugin |
365
|
0
|
0
|
|
|
|
|
if($Cnf->{documentation}) { |
366
|
0
|
|
0
|
|
|
|
$field->{plugins} ||= []; |
367
|
0
|
|
|
|
|
|
push @{$field->{plugins}}, 'fieldhelp'; |
|
0
|
|
|
|
|
|
|
368
|
0
|
|
|
|
|
|
$field->{helpText} = $Cnf->{documentation}; |
369
|
|
|
|
|
|
|
} |
370
|
|
|
|
|
|
|
# -- |
371
|
|
|
|
|
|
|
|
372
|
0
|
|
|
|
|
|
push @items, $field; |
373
|
|
|
|
|
|
|
} |
374
|
|
|
|
|
|
|
|
375
|
0
|
|
|
|
|
|
return @items; |
376
|
|
|
|
|
|
|
} |
377
|
|
|
|
|
|
|
|
378
|
|
|
|
|
|
|
sub get_add_form { |
379
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
380
|
|
|
|
|
|
|
return { |
381
|
0
|
|
|
|
|
|
%{$self->add_edit_formpanel_defaults}, |
|
0
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
items => [ $self->get_add_form_items ] |
383
|
|
|
|
|
|
|
}; |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
sub get_add_form_items { |
387
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
388
|
0
|
|
|
|
|
|
return $self->get_add_edit_form_items('add'); |
389
|
|
|
|
|
|
|
} |
390
|
|
|
|
|
|
|
|
391
|
|
|
|
|
|
|
sub get_edit_form { |
392
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
393
|
|
|
|
|
|
|
return { |
394
|
0
|
|
|
|
|
|
%{$self->add_edit_formpanel_defaults}, |
|
0
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
items => [ $self->get_edit_form_items ] |
396
|
|
|
|
|
|
|
}; |
397
|
|
|
|
|
|
|
} |
398
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub get_edit_form_items { |
400
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
401
|
0
|
|
|
|
|
|
return $self->get_add_edit_form_items('edit'); |
402
|
|
|
|
|
|
|
} |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
|
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
sub before_batch_update { |
407
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
408
|
0
|
|
|
|
|
|
my $editSpec = $self->param_decodeIf($self->c->req->params->{editSpec}); |
409
|
0
|
|
|
|
|
|
my $update = $editSpec->{update}; |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
die usererr "Invalid editSpec - record_pk found in update data!!" |
412
|
0
|
0
|
|
|
|
|
if (exists $update->{$self->record_pk}); |
413
|
|
|
|
|
|
|
|
414
|
0
|
0
|
|
|
|
|
my $count = $editSpec->{count} or die usererr "Invalid editSpec - no count supplied"; |
415
|
|
|
|
|
|
|
|
416
|
0
|
|
|
|
|
|
my $max = $self->batch_update_max_rows; |
417
|
|
|
|
|
|
|
|
418
|
0
|
0
|
0
|
|
|
|
die usererr |
419
|
|
|
|
|
|
|
"Too many rows for batch update ($count) - max allowed rows: $max", |
420
|
|
|
|
|
|
|
title => "Batch Update Denied" |
421
|
|
|
|
|
|
|
if($max && $count > $max); |
422
|
|
|
|
|
|
|
}; |
423
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
# This is expensive, but compatible with the generic DataStore2 (update) API. |
425
|
|
|
|
|
|
|
# Should be overridden in more specific derived classes, like in DbicLink2, to |
426
|
|
|
|
|
|
|
# perform a smarter/more efficient operation |
427
|
|
|
|
|
|
|
sub batch_update { |
428
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
# this is called directly instead of adding a method modifier because a modifier |
431
|
|
|
|
|
|
|
# would not get called when batch_update is overridden by another Role (such as in |
432
|
|
|
|
|
|
|
# DbicLink2) |
433
|
0
|
|
|
|
|
|
$self->before_batch_update; |
434
|
|
|
|
|
|
|
|
435
|
0
|
|
|
|
|
|
my $editSpec = $self->param_decodeIf($self->c->req->params->{editSpec}); |
436
|
0
|
|
|
|
|
|
my $read_params = $editSpec->{read_params}; |
437
|
0
|
|
|
|
|
|
my $update = $editSpec->{update}; |
438
|
|
|
|
|
|
|
|
439
|
0
|
|
|
|
|
|
delete $read_params->{start}; |
440
|
0
|
|
|
|
|
|
delete $read_params->{limit}; |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
# perform a read to verify that totalCount matches the supplied/expected count |
443
|
0
|
|
|
|
|
|
my %orig_params = %{$self->c->req->params}; |
|
0
|
|
|
|
|
|
|
444
|
0
|
|
|
|
|
|
%{$self->c->req->params} = %$read_params; |
|
0
|
|
|
|
|
|
|
445
|
0
|
|
|
|
|
|
my $readdata = $self->read_records(); |
446
|
0
|
|
|
|
|
|
my $rows = $readdata->{rows}; |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
die "Actual row count (" . @$rows . ") doesn't agree with 'results' property (" . $readdata->{results} . ")" |
449
|
0
|
0
|
|
|
|
|
unless (@$rows == $readdata->{results}); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
die usererr "Update count mismatch (" . |
452
|
|
|
|
|
|
|
$editSpec->{count} . ' vs ' . $readdata->{results} . ') ' . |
453
|
|
|
|
|
|
|
"- This can happen if someone else modified one or more of the records in the update set.\n\n" . |
454
|
|
|
|
|
|
|
"Reload the the grid and try again." |
455
|
0
|
0
|
|
|
|
|
unless ($editSpec->{count} == $readdata->{results}); |
456
|
|
|
|
|
|
|
|
457
|
|
|
|
|
|
|
# apply update data to rows: |
458
|
0
|
|
|
|
|
|
%$_ = (%$_,%$update) for (@$rows); |
459
|
|
|
|
|
|
|
|
460
|
0
|
|
|
|
|
|
my $result; |
461
|
|
|
|
|
|
|
{ |
462
|
0
|
|
|
|
|
|
local $RapidApp::Module::DatStor::BATCH_UPDATE_IN_PROGRESS = 1; |
|
0
|
|
|
|
|
|
|
463
|
0
|
|
|
|
|
|
$result = $self->DataStore->update_handler->call($rows,$read_params); |
464
|
|
|
|
|
|
|
} |
465
|
|
|
|
|
|
|
|
466
|
0
|
|
|
|
|
|
%{$self->c->req->params} = %orig_params; |
|
0
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
return $result if ( |
469
|
|
|
|
|
|
|
ref($result) eq 'HASH' and |
470
|
|
|
|
|
|
|
defined $result->{success} |
471
|
0
|
0
|
0
|
|
|
|
); |
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
return { |
474
|
0
|
0
|
|
|
|
|
success => \1, |
475
|
|
|
|
|
|
|
msg => 'Batch Update Succeeded' |
476
|
|
|
|
|
|
|
} if ($result); |
477
|
|
|
|
|
|
|
|
478
|
0
|
|
|
|
|
|
die "Update Failed"; |
479
|
|
|
|
|
|
|
} |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub param_decodeIf { |
483
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
484
|
0
|
|
|
|
|
|
my $param = shift; |
485
|
0
|
|
0
|
|
|
|
my $default = shift || undef; |
486
|
|
|
|
|
|
|
|
487
|
0
|
0
|
|
|
|
|
return $default unless (defined $param); |
488
|
|
|
|
|
|
|
|
489
|
0
|
0
|
|
|
|
|
return $param if (ref $param); |
490
|
0
|
|
|
|
|
|
return $self->json->decode($param); |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
# New for #85: |
495
|
|
|
|
|
|
|
sub dedicated_add_form { |
496
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
497
|
0
|
0
|
|
|
|
|
die "Not allowed" unless $self->dedicated_add_form_enabled; |
498
|
|
|
|
|
|
|
|
499
|
0
|
|
|
|
|
|
my $c = $self->c; |
500
|
0
|
|
|
|
|
|
my $content = $self->content; |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
# Just in case custom add_form_url_params are configured, merge them into the current |
503
|
|
|
|
|
|
|
# request params so they are available as they would be if called via Ajax... |
504
|
0
|
|
0
|
|
|
|
my $afuParams = $self->get_extconfig_param('add_form_url_params') || {}; |
505
|
0
|
|
|
|
|
|
%{$c->req->params} = ( %{$c->req->params}, %$afuParams ); |
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
506
|
|
|
|
|
|
|
|
507
|
0
|
|
|
|
|
|
my $fp = $self->get_add_form; |
508
|
|
|
|
|
|
|
|
509
|
0
|
|
0
|
|
|
|
my $btnCfg = ($self->get_extconfig_param('store_button_cnf')||{})->{add} || {}; |
510
|
|
|
|
|
|
|
|
511
|
|
|
|
|
|
|
return $self->render_data({ |
512
|
|
|
|
|
|
|
xtype => 'datastore-dedicated-add-form', |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
source_cmp => $content, |
515
|
|
|
|
|
|
|
formpanel => $fp, |
516
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
tabTitle => $btnCfg->{text} || '(Add ...)', |
518
|
0
|
|
0
|
|
|
|
tabIconCls => $btnCfg->{iconCls} || 'ra-icon-add' |
|
|
|
0
|
|
|
|
|
519
|
|
|
|
|
|
|
|
520
|
|
|
|
|
|
|
}); |
521
|
|
|
|
|
|
|
} |
522
|
|
|
|
|
|
|
|
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
|
525
|
|
|
|
|
|
|
#### --------------------- #### |
526
|
|
|
|
|
|
|
|
527
|
|
|
|
|
|
|
|
528
|
5
|
|
|
5
|
|
52
|
no Moose; |
|
5
|
|
|
|
|
13
|
|
|
5
|
|
|
|
|
41
|
|
529
|
|
|
|
|
|
|
#__PACKAGE__->meta->make_immutable; |
530
|
|
|
|
|
|
|
1; |
531
|
|
|
|
|
|
|
|