line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Mojolicious::Command::generate::resources; |
2
|
3
|
|
|
3
|
|
72098
|
use Mojo::Base 'Mojolicious::Command', -signatures; |
|
3
|
|
|
|
|
116050
|
|
|
3
|
|
|
|
|
33
|
|
3
|
|
|
|
|
|
|
|
4
|
3
|
|
|
3
|
|
49073
|
use Mojo::Util qw(class_to_path decamelize camelize getopt); |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
182
|
|
5
|
3
|
|
|
3
|
|
17
|
use Mojo::File 'path'; |
|
3
|
|
|
|
|
6
|
|
|
3
|
|
|
|
|
122
|
|
6
|
3
|
|
|
3
|
|
16
|
use List::Util 'first'; |
|
3
|
|
|
|
|
7
|
|
|
3
|
|
|
|
|
10120
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:BEROV'; |
9
|
|
|
|
|
|
|
our $VERSION = '0.21'; |
10
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
has args => sub { {} }; |
12
|
|
|
|
|
|
|
has description => |
13
|
|
|
|
|
|
|
(path(__FILE__)->slurp() =~ /${\__PACKAGE__}\s+-\s+(.+)\n/)[0]; |
14
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
has usage => sub { shift->extract_usage }; |
16
|
|
|
|
|
|
|
has _templates_path => ''; |
17
|
|
|
|
|
|
|
has '_db_helper'; |
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
has routes => sub { |
20
|
|
|
|
|
|
|
$_[0]->{routes} = []; |
21
|
|
|
|
|
|
|
foreach my $t (@{$_[0]->args->{tables}}) { |
22
|
|
|
|
|
|
|
my $controller = camelize($t); |
23
|
|
|
|
|
|
|
my $route = decamelize($controller); |
24
|
|
|
|
|
|
|
push @{$_[0]->{routes}}, |
25
|
|
|
|
|
|
|
{ |
26
|
|
|
|
|
|
|
route => "/$route", |
27
|
|
|
|
|
|
|
via => ['GET'], |
28
|
|
|
|
|
|
|
to => "$route#index", |
29
|
|
|
|
|
|
|
name => "home_$route" |
30
|
|
|
|
|
|
|
}, |
31
|
|
|
|
|
|
|
{ |
32
|
|
|
|
|
|
|
route => "/$route/create", |
33
|
|
|
|
|
|
|
via => ['GET'], |
34
|
|
|
|
|
|
|
to => "$route#create", |
35
|
|
|
|
|
|
|
name => "create_$route", |
36
|
|
|
|
|
|
|
}, |
37
|
|
|
|
|
|
|
{ |
38
|
|
|
|
|
|
|
route => "/$route/:id", |
39
|
|
|
|
|
|
|
via => ['GET'], |
40
|
|
|
|
|
|
|
to => "$route#show", |
41
|
|
|
|
|
|
|
name => "show_$route" |
42
|
|
|
|
|
|
|
}, |
43
|
|
|
|
|
|
|
{ |
44
|
|
|
|
|
|
|
route => "/$route", |
45
|
|
|
|
|
|
|
via => ['POST'], |
46
|
|
|
|
|
|
|
to => "$route#store", |
47
|
|
|
|
|
|
|
name => "store_$route", |
48
|
|
|
|
|
|
|
}, |
49
|
|
|
|
|
|
|
{ |
50
|
|
|
|
|
|
|
route => "/$route/:id/edit", |
51
|
|
|
|
|
|
|
via => ['GET'], |
52
|
|
|
|
|
|
|
to => "$route#edit", |
53
|
|
|
|
|
|
|
name => "edit_$route" |
54
|
|
|
|
|
|
|
}, |
55
|
|
|
|
|
|
|
{ |
56
|
|
|
|
|
|
|
route => "/$route/:id", |
57
|
|
|
|
|
|
|
via => ['PUT'], |
58
|
|
|
|
|
|
|
to => "$route#update", |
59
|
|
|
|
|
|
|
name => "update_$route" |
60
|
|
|
|
|
|
|
}, |
61
|
|
|
|
|
|
|
{ |
62
|
|
|
|
|
|
|
route => "/$route/:id", |
63
|
|
|
|
|
|
|
via => ['DELETE'], |
64
|
|
|
|
|
|
|
to => "$route#remove", |
65
|
|
|
|
|
|
|
name => "remove_$route" |
66
|
|
|
|
|
|
|
}; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
return $_[0]->{routes}; |
69
|
|
|
|
|
|
|
}; |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
my $_init = sub ($self, @options) { |
72
|
|
|
|
|
|
|
return $self if $self->{_initialised}; |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
# Make sure the "tables" argument exists as an empty array |
75
|
|
|
|
|
|
|
my $args = $self->args({tables => []})->args; |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
getopt( |
78
|
|
|
|
|
|
|
\@options, |
79
|
|
|
|
|
|
|
'H|home_dir=s' => \$args->{home_dir}, |
80
|
|
|
|
|
|
|
'L|lib=s' => \$args->{lib}, |
81
|
|
|
|
|
|
|
'A|api_dir=s' => \$args->{api_dir}, |
82
|
|
|
|
|
|
|
'C|controller_namespace=s' => \$args->{controller_namespace}, |
83
|
|
|
|
|
|
|
'M|model_namespace=s' => \$args->{model_namespace}, |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
# TODO: 'O|overwrite' => \$args->{overwrite}, |
86
|
|
|
|
|
|
|
'T|templates_root=s' => \$args->{templates_root}, |
87
|
|
|
|
|
|
|
't|tables=s@' => \$args->{tables}, |
88
|
|
|
|
|
|
|
'D|db_helper=s' => \$args->{db_helper}, |
89
|
|
|
|
|
|
|
); |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
@{$args->{tables}} = split(/\s*?\,\s*?/, join(',', @{$args->{tables}})); |
92
|
|
|
|
|
|
|
Carp::croak $self->usage unless scalar @{$args->{tables}}; |
93
|
|
|
|
|
|
|
|
94
|
|
|
|
|
|
|
my $app = $self->app; |
95
|
|
|
|
|
|
|
$args->{controller_namespace} //= $app->routes->namespaces->[0]; |
96
|
|
|
|
|
|
|
$args->{model_namespace} //= ref($app) . '::Model'; |
97
|
|
|
|
|
|
|
$args->{home_dir} //= $app->home->realpath; |
98
|
|
|
|
|
|
|
$args->{lib} //= path($args->{home_dir})->realpath->child('lib'); |
99
|
|
|
|
|
|
|
$args->{api_dir} //= path($args->{home_dir})->realpath->child('api'); |
100
|
|
|
|
|
|
|
$args->{templates_root} |
101
|
|
|
|
|
|
|
//= path($app->renderer->paths->[0])->realpath->to_string; |
102
|
|
|
|
|
|
|
$args->{db_helper} //= 'sqlite'; |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
# Find templates. |
105
|
|
|
|
|
|
|
for my $path (@INC) { |
106
|
|
|
|
|
|
|
my $templates_path |
107
|
|
|
|
|
|
|
= path($path, 'Mojolicious/resources/templates/mojo/command/resources'); |
108
|
|
|
|
|
|
|
if (-d $templates_path) { |
109
|
|
|
|
|
|
|
$self->_templates_path($templates_path); |
110
|
|
|
|
|
|
|
last; |
111
|
|
|
|
|
|
|
} |
112
|
|
|
|
|
|
|
} |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
# Find the used database helper. One of sqlite, pg, mysql or passed on the |
115
|
|
|
|
|
|
|
# commandline |
116
|
|
|
|
|
|
|
my @db_helpers = qw(sqlite pg mysql); |
117
|
|
|
|
|
|
|
unshift @db_helpers, $args->{db_helper} |
118
|
|
|
|
|
|
|
unless first sub { $_ eq $args->{db_helper} }, @db_helpers; |
119
|
|
|
|
|
|
|
for (@db_helpers) { |
120
|
|
|
|
|
|
|
if ($app->renderer->get_helper($_)) { |
121
|
|
|
|
|
|
|
$self->_db_helper($_); |
122
|
|
|
|
|
|
|
last; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
} |
125
|
|
|
|
|
|
|
if (!$self->_db_helper) { |
126
|
|
|
|
|
|
|
die <<'MSG'; |
127
|
|
|
|
|
|
|
Guessing the used database wrapper helper failed. One of (@db_helpers) is |
128
|
|
|
|
|
|
|
required. This application does not use any of the supported database helpers |
129
|
|
|
|
|
|
|
nor the one provided as argument. |
130
|
|
|
|
|
|
|
One of Mojo::Pg, Mojo::mysql or Mojo::SQLite must be used to generate models. |
131
|
|
|
|
|
|
|
Aborting!.. |
132
|
|
|
|
|
|
|
MSG |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
$self->{_initialised} = 1; |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
return $self; |
138
|
|
|
|
|
|
|
}; |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
# Returns the full path to the first found template. |
141
|
|
|
|
|
|
|
# See http://localhost:3000/perldoc/Mojolicious/Renderer#template_path |
142
|
38
|
|
|
38
|
|
122
|
sub _template_path ($self, $template) { |
|
38
|
|
|
|
|
74
|
|
|
38
|
|
|
|
|
66
|
|
|
38
|
|
|
|
|
59
|
|
143
|
38
|
|
|
|
|
70
|
state $paths = $self->app->renderer->paths; |
144
|
38
|
|
|
|
|
91
|
state $tmpls_path = $self->_templates_path; |
145
|
38
|
|
100
|
|
|
95
|
-r and return $_ for map { path($_, $template) } @$paths, $tmpls_path; |
|
95
|
|
|
|
|
935
|
|
146
|
0
|
|
|
|
|
0
|
return; |
147
|
|
|
|
|
|
|
} |
148
|
|
|
|
|
|
|
|
149
|
2
|
|
|
2
|
1
|
418
|
sub run ($self, %options) { |
|
2
|
|
|
|
|
6
|
|
|
2
|
|
|
|
|
8
|
|
|
2
|
|
|
|
|
5
|
|
150
|
2
|
|
|
|
|
12
|
$self->$_init(%options); |
151
|
2
|
|
|
|
|
6
|
my $args = $self->args; |
152
|
2
|
|
|
|
|
11
|
my $app = $self->app; |
153
|
|
|
|
|
|
|
|
154
|
2
|
|
|
|
|
8
|
my $wrapper_helpers = ''; |
155
|
2
|
|
|
|
|
4
|
for my $t (@{$args->{tables}}) { |
|
2
|
|
|
|
|
14
|
|
156
|
|
|
|
|
|
|
|
157
|
4
|
|
|
|
|
63
|
my $class_name = camelize($t); |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
# Models |
160
|
4
|
|
|
|
|
86
|
my $mclass = "$args->{model_namespace}::$class_name"; |
161
|
4
|
|
|
|
|
19
|
my $m_file = path($args->{lib}, class_to_path($mclass)); |
162
|
4
|
|
|
|
|
124
|
my $table_columns = $self->_get_table_columns($t); |
163
|
4
|
|
|
|
|
35
|
my $template_args = { |
164
|
|
|
|
|
|
|
%$args, |
165
|
|
|
|
|
|
|
class => $mclass, |
166
|
|
|
|
|
|
|
t => lc $t, |
167
|
|
|
|
|
|
|
db_helper => $self->_db_helper, |
168
|
|
|
|
|
|
|
columns => $table_columns, |
169
|
|
|
|
|
|
|
column_info => $self->_column_info($t), |
170
|
|
|
|
|
|
|
}; |
171
|
4
|
|
|
|
|
18
|
my $tmpl_file = $self->_template_path('m_class.ep'); |
172
|
4
|
|
|
|
|
335
|
$self->render_template_to_file($tmpl_file, $m_file, $template_args); |
173
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
# Controllers |
175
|
4
|
|
|
|
|
1414
|
my $class = "$args->{controller_namespace}::$class_name"; |
176
|
4
|
|
|
|
|
23
|
my $c_file = path($args->{lib}, class_to_path($class)); |
177
|
4
|
|
|
|
|
143
|
$template_args = { |
178
|
|
|
|
|
|
|
%$template_args, |
179
|
|
|
|
|
|
|
class => $class, |
180
|
|
|
|
|
|
|
validation => $self->generate_validation($t) |
181
|
|
|
|
|
|
|
}; |
182
|
4
|
|
|
|
|
16
|
$tmpl_file = $self->_template_path('c_class.ep'); |
183
|
4
|
|
|
|
|
290
|
$self->render_template_to_file($tmpl_file, $c_file, $template_args); |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
|
186
|
|
|
|
|
|
|
# Templates |
187
|
4
|
|
|
|
|
1362
|
my $template_dir = decamelize($class_name); |
188
|
4
|
|
|
|
|
105
|
my $template_root = $args->{templates_root}; |
189
|
|
|
|
|
|
|
|
190
|
4
|
|
|
|
|
18
|
my @views = qw(index create show edit); |
191
|
4
|
|
|
|
|
13
|
for my $v (@views) { |
192
|
16
|
|
|
|
|
4184
|
my $to_t_file = path($template_root, $template_dir, $v . '.html.ep'); |
193
|
16
|
|
|
|
|
284
|
my $tmpl = $self->_template_path($v . '.html.ep'); |
194
|
16
|
|
|
|
|
1140
|
$self->render_template_to_file($tmpl, $to_t_file, $template_args); |
195
|
|
|
|
|
|
|
} |
196
|
4
|
|
|
|
|
1082
|
$tmpl_file = $self->_template_path('_form.html.ep'); |
197
|
4
|
|
|
|
|
280
|
my $to_t_file = path($template_root, $template_dir, '_form.html.ep'); |
198
|
4
|
|
|
|
|
76
|
$template_args |
199
|
|
|
|
|
|
|
= {%$template_args, fields => $self->generate_formfields($t)}; |
200
|
4
|
|
|
|
|
21
|
$self->render_template_to_file($tmpl_file, $to_t_file, $template_args); |
201
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
# Helpers |
203
|
4
|
|
|
|
|
1152
|
$template_args = {%$template_args, class => $mclass}; |
204
|
4
|
|
|
|
|
18
|
$tmpl_file = $self->_template_path('helper.ep'); |
205
|
4
|
|
|
|
|
291
|
$wrapper_helpers |
206
|
|
|
|
|
|
|
.= Mojo::Template->new->render_file($tmpl_file, $template_args); |
207
|
|
|
|
|
|
|
} # end foreach tables |
208
|
|
|
|
|
|
|
|
209
|
|
|
|
|
|
|
# OpenAPI |
210
|
2
|
|
|
|
|
46
|
$self->generate_openapi(); |
211
|
|
|
|
|
|
|
|
212
|
|
|
|
|
|
|
# Routes and TODO |
213
|
2
|
|
|
|
|
24
|
my $template_args |
214
|
|
|
|
|
|
|
= {%$args, helpers => $wrapper_helpers, routes => $self->routes}; |
215
|
2
|
|
|
|
|
37
|
my $tmpl_file = $self->_template_path('TODO.ep'); |
216
|
2
|
|
|
|
|
194
|
my $todo_file = path($args->{home_dir}, 'TODO'); |
217
|
2
|
|
|
|
|
42
|
$self->render_template_to_file($tmpl_file, $todo_file, $template_args); |
218
|
2
|
|
|
|
|
682
|
say qq{$/Please look at $todo_file for instructions to complete the setup.} |
219
|
|
|
|
|
|
|
. qq{$/Have fun!$/}; |
220
|
2
|
|
|
|
|
59
|
return $self; |
221
|
|
|
|
|
|
|
} |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
# Returns an array reference of columns from the table |
224
|
4
|
|
|
4
|
|
9
|
sub _get_table_columns ($self, $table) { |
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
5
|
|
225
|
4
|
|
|
|
|
8
|
my @columns = map ({ $_->{COLUMN_NAME} } @{$self->_column_info($table)}); |
|
16
|
|
|
|
|
245
|
|
|
4
|
|
|
|
|
15
|
|
226
|
4
|
|
|
|
|
13
|
return \@columns; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
22
|
|
|
22
|
|
30972
|
sub _column_info ($self, $table) { |
|
22
|
|
|
|
|
42
|
|
|
22
|
|
|
|
|
41
|
|
|
22
|
|
|
|
|
35
|
|
230
|
22
|
|
|
|
|
41
|
state $tci = {}; #tables column info |
231
|
22
|
|
|
|
|
57
|
state $db_helper = $self->_db_helper; |
232
|
22
|
|
66
|
|
|
135
|
$tci->{$table} |
233
|
|
|
|
|
|
|
//= $self->app->$db_helper->db->dbh->column_info(undef, undef, $table, '%') |
234
|
|
|
|
|
|
|
->fetchall_arrayref({}); |
235
|
22
|
|
|
|
|
42486
|
return $tci->{$table}; |
236
|
|
|
|
|
|
|
} |
237
|
|
|
|
|
|
|
|
238
|
32
|
|
|
32
|
1
|
61
|
sub render_template_to_file ($self, $filename, $path, $args) { |
|
32
|
|
|
|
|
64
|
|
|
32
|
|
|
|
|
54
|
|
|
32
|
|
|
|
|
53
|
|
|
32
|
|
|
|
|
52
|
|
|
32
|
|
|
|
|
50
|
|
239
|
32
|
|
|
|
|
200
|
my $out = Mojo::Template->new->render_file($filename, $args); |
240
|
32
|
|
|
|
|
684
|
return $self->write_file($path, $out); |
241
|
|
|
|
|
|
|
} |
242
|
|
|
|
|
|
|
|
243
|
4
|
|
|
4
|
1
|
11
|
sub generate_formfields ($self, $table) { |
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
7
|
|
244
|
4
|
|
|
|
|
8
|
my $fields = ''; |
245
|
4
|
|
|
|
|
9
|
for my $col (@{$self->_column_info($table)}) { |
|
4
|
|
|
|
|
14
|
|
246
|
16
|
|
|
|
|
38
|
my $name = $col->{COLUMN_NAME}; |
247
|
16
|
100
|
|
|
|
38
|
my $required = $col->{NULLABLE} ? '' : 'required => 1,'; |
248
|
16
|
100
|
|
|
|
47
|
my $size = $col->{COLUMN_SIZE} ? "size => $col->{COLUMN_SIZE}" : ''; |
249
|
16
|
100
|
|
|
|
42
|
if ($name eq 'id') { |
250
|
4
|
|
|
|
|
21
|
$fields |
251
|
|
|
|
|
|
|
.= qq|\n%=hidden_field '$name' => \$${table}->{id} if (\$action ne 'create');\n|; |
252
|
4
|
|
|
|
|
11
|
next; |
253
|
|
|
|
|
|
|
} |
254
|
12
|
100
|
66
|
|
|
96
|
if ($col->{TYPE_NAME} =~ /char/i && $col->{COLUMN_SIZE} < 256) { |
|
|
100
|
33
|
|
|
|
|
|
|
|
66
|
|
|
|
|
255
|
8
|
|
|
|
|
22
|
$fields .= <<"QQ"; |
256
|
8
|
|
|
|
|
51
|
%= label_for $name =>'${\ucfirst($name)}'\n |
257
|
|
|
|
|
|
|
%= text_field $name => \$${table}->{$name}, $required $size\n |
258
|
|
|
|
|
|
|
QQ |
259
|
8
|
|
|
|
|
22
|
next; |
260
|
|
|
|
|
|
|
} |
261
|
|
|
|
|
|
|
elsif ( $col->{TYPE_NAME} =~ /text/i |
262
|
|
|
|
|
|
|
|| $col->{TYPE_NAME} =~ /char/i && $col->{COLUMN_SIZE} > 255) |
263
|
|
|
|
|
|
|
{ |
264
|
2
|
|
|
|
|
9
|
$fields .= <<"QQ"; |
265
|
2
|
|
|
|
|
15
|
%= label_for '$name' => '${\ucfirst($name)}'\n |
266
|
|
|
|
|
|
|
%= text_area '$name' => \$${table}->{$name}, $required $size\n |
267
|
|
|
|
|
|
|
QQ |
268
|
2
|
|
|
|
|
8
|
next; |
269
|
|
|
|
|
|
|
} |
270
|
2
|
50
|
|
|
|
22
|
if ($col->{TYPE_NAME} =~ /INT|FLOAT|DOUBLE|DECIMAL/i) { |
271
|
2
|
|
|
|
|
9
|
$fields .= <<"QQ"; |
272
|
2
|
|
|
|
|
19
|
%= label_for $name => '${\ucfirst($name)}'\n |
273
|
|
|
|
|
|
|
%= number_field $name => \$${table}->{$name}, $required $size\n |
274
|
|
|
|
|
|
|
QQ |
275
|
2
|
|
|
|
|
7
|
next; |
276
|
|
|
|
|
|
|
} |
277
|
|
|
|
|
|
|
} |
278
|
4
|
|
|
|
|
42
|
return $fields; |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
4
|
|
|
4
|
1
|
10
|
sub generate_validation ($self, $table) { |
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
10
|
|
|
4
|
|
|
|
|
7
|
|
282
|
4
|
|
|
|
|
10
|
my $fields = ''; |
283
|
4
|
|
|
|
|
10
|
for my $col (@{$self->_column_info($table)}) { |
|
4
|
|
|
|
|
11
|
|
284
|
16
|
|
|
|
|
34
|
my $name = $col->{COLUMN_NAME}; |
285
|
16
|
100
|
|
|
|
41
|
my $required = $col->{NULLABLE} ? 0 : 1; |
286
|
16
|
100
|
|
|
|
44
|
my $size = $col->{COLUMN_SIZE} ? "size => $col->{COLUMN_SIZE}" : ''; |
287
|
16
|
100
|
|
|
|
48
|
if ($name eq 'id') { |
288
|
4
|
|
|
|
|
12
|
$fields .= qq|\$v->required('id') if \$c->stash->{action} ne 'store';\n|; |
289
|
4
|
|
|
|
|
9
|
next; |
290
|
|
|
|
|
|
|
} |
291
|
|
|
|
|
|
|
|
292
|
|
|
|
|
|
|
$fields |
293
|
12
|
100
|
|
|
|
39
|
.= $required |
294
|
|
|
|
|
|
|
? qq|\$v->required('$name', 'trim')| |
295
|
|
|
|
|
|
|
: qq|\$v->optional('$name', 'trim')|; |
296
|
12
|
100
|
66
|
|
|
77
|
if ($col->{TYPE_NAME} =~ /char/i && $col->{COLUMN_SIZE} < 256) { |
297
|
8
|
|
|
|
|
26
|
$fields .= "->size(0, $col->{COLUMN_SIZE})"; |
298
|
|
|
|
|
|
|
} |
299
|
|
|
|
|
|
|
|
300
|
12
|
100
|
|
|
|
50
|
if ($col->{TYPE_NAME} =~ /INT|FLOAT|DOUBLE|DECIMAL/i) { |
301
|
2
|
|
|
|
|
7
|
$fields .= q|->like(qr/\d+(\.\d+)?/)|; |
302
|
|
|
|
|
|
|
} |
303
|
12
|
|
|
|
|
38
|
$fields .= ';' . $/; |
304
|
|
|
|
|
|
|
} |
305
|
4
|
|
|
|
|
38
|
return $fields; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
2
|
|
|
2
|
1
|
5
|
sub generate_openapi ($self) { |
|
2
|
|
|
|
|
4
|
|
|
2
|
|
|
|
|
3
|
|
309
|
2
|
|
|
|
|
4
|
my $args = {%{$self->args}}; |
|
2
|
|
|
|
|
11
|
|
310
|
2
|
|
|
|
|
22
|
my $api_tmpl_file = $self->_template_path('api.json.ep'); |
311
|
2
|
|
|
|
|
148
|
my $api_file = path($args->{api_dir}, 'api.json'); |
312
|
2
|
|
|
|
|
37
|
$args->{api_title} = ref($self->app) . ' OpenAPI'; |
313
|
2
|
|
|
|
|
17
|
$args->{api_paths} = {}; |
314
|
2
|
|
|
|
|
6
|
my $api_defs = {}; |
315
|
2
|
|
|
|
|
7
|
$args->{api_definitions} = $api_defs; |
316
|
|
|
|
|
|
|
|
317
|
2
|
|
|
|
|
4
|
for my $t (@{$args->{tables}}) { |
|
2
|
|
|
|
|
8
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
# Generate descriptions for table objects. |
320
|
4
|
|
|
|
|
22
|
my $class_name = $args->{class_name} = camelize($t); |
321
|
4
|
|
|
|
|
87
|
my $object_name = $class_name . 'Item'; |
322
|
4
|
|
|
|
|
21
|
$api_defs->{$class_name}{items}{'$ref'} = "#/definitions/$object_name"; |
323
|
4
|
|
|
|
|
13
|
$api_defs->{$class_name}{type} = 'array'; |
324
|
|
|
|
|
|
|
$api_defs->{$object_name}{description} |
325
|
4
|
|
|
|
|
19
|
= "An object, representing one item of $class_name."; |
326
|
|
|
|
|
|
|
|
327
|
|
|
|
|
|
|
# Generate definition and parameter description for each column. |
328
|
4
|
|
|
|
|
27
|
$self->generate_path_api($t, $api_defs->{$object_name}, $args); |
329
|
|
|
|
|
|
|
} |
330
|
|
|
|
|
|
|
|
331
|
2
|
|
|
|
|
15
|
$self->render_template_to_file($api_tmpl_file, $api_file, $args); |
332
|
|
|
|
|
|
|
|
333
|
|
|
|
|
|
|
# Prettify generated JSON. With this step we also make sure the generated |
334
|
|
|
|
|
|
|
# JSON is syntactically correct. |
335
|
|
|
|
|
|
|
|
336
|
2
|
|
|
|
|
1198
|
my $decoded = JSON::PP::decode_json(path($api_file)->slurp()); |
337
|
2
|
|
|
|
|
97843
|
$decoded->{definitions} = {%{$decoded->{definitions}}, %$api_defs}; |
|
2
|
|
|
|
|
24
|
|
338
|
2
|
|
|
|
|
17
|
path($api_file)->spurt(JSON::PP->new->utf8->pretty->encode($decoded)); |
339
|
|
|
|
|
|
|
|
340
|
2
|
|
|
|
|
23932
|
return; |
341
|
|
|
|
|
|
|
} |
342
|
|
|
|
|
|
|
|
343
|
4
|
|
|
4
|
1
|
11
|
sub generate_path_api ($self, $t, $object_api_def, $args) { |
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
9
|
|
|
4
|
|
|
|
|
7
|
|
|
4
|
|
|
|
|
8
|
|
|
4
|
|
|
|
|
7
|
|
344
|
4
|
|
|
|
|
11
|
$object_api_def->{properties} = {}; |
345
|
4
|
|
|
|
|
11
|
$object_api_def->{required} = []; |
346
|
4
|
|
|
|
|
9
|
my $params = {}; |
347
|
4
|
|
|
|
|
8
|
for my $col (@{$self->_column_info($t)}) { |
|
4
|
|
|
|
|
15
|
|
348
|
16
|
|
|
|
|
40
|
my $name = $col->{COLUMN_NAME}; |
349
|
16
|
|
100
|
|
|
57
|
my $size = +$col->{COLUMN_SIZE} || 0; #must be number in JSON |
350
|
16
|
|
|
|
|
33
|
my $type = $col->{TYPE_NAME}; |
351
|
16
|
|
|
|
|
39
|
my $param_name = camelize($name) . "Of$args->{class_name}"; |
352
|
16
|
|
|
|
|
262
|
$params->{$param_name} = {name => $name}; |
353
|
|
|
|
|
|
|
|
354
|
16
|
100
|
|
|
|
51
|
unless ($col->{NULLABLE}) { |
355
|
6
|
|
|
|
|
21
|
$params->{$param_name}{required} = Mojo::JSON->true; |
356
|
6
|
|
|
|
|
43
|
push @{$object_api_def->{required}}, $name; |
|
6
|
|
|
|
|
18
|
|
357
|
|
|
|
|
|
|
} |
358
|
|
|
|
|
|
|
|
359
|
16
|
100
|
|
|
|
116
|
if ($type =~ /char|text|clob/i) { |
|
|
50
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
360
|
10
|
100
|
|
|
|
47
|
$object_api_def->{properties}{$name} |
361
|
|
|
|
|
|
|
= {($size ? (maxLength => $size) : ()), type => 'string'}; |
362
|
10
|
100
|
|
|
|
37
|
$params->{$param_name}{maxLength} = $size if $size; |
363
|
10
|
|
|
|
|
41
|
$params->{$param_name}{type} = 'string'; |
364
|
|
|
|
|
|
|
} |
365
|
|
|
|
|
|
|
elsif ($type =~ /INT/i) { |
366
|
6
|
100
|
|
|
|
37
|
$object_api_def->{properties}{$name} |
367
|
|
|
|
|
|
|
= {($size ? (maxLength => $size) : ()), type => 'integer'}; |
368
|
6
|
100
|
|
|
|
19
|
$params->{$param_name}{maxLength} = $size if $size; |
369
|
6
|
|
|
|
|
20
|
$params->{$param_name}{type} = 'integer'; |
370
|
|
|
|
|
|
|
} |
371
|
|
|
|
|
|
|
elsif ($type =~ /FLOAT|DOUBLE|DECIMAL|NUMBER/i) { |
372
|
0
|
|
0
|
|
|
0
|
my $scale = $col->{DECIMAL_DIGITS} || 0; |
373
|
0
|
|
|
|
|
0
|
my $precision = $size - $scale; |
374
|
0
|
|
|
|
|
0
|
my $pattern = qr/^-?\d{1,$precision}(?:\.\d{0,$scale})?$/x; |
375
|
0
|
0
|
|
|
|
0
|
$object_api_def->{properties}{$name} = { |
376
|
|
|
|
|
|
|
($size ? (maxLength => $size) : ()), |
377
|
|
|
|
|
|
|
type => 'number', |
378
|
|
|
|
|
|
|
pattern => $pattern |
379
|
|
|
|
|
|
|
}; |
380
|
0
|
0
|
|
|
|
0
|
$params->{$param_name}{maxLength} = $size if $size; |
381
|
0
|
|
|
|
|
0
|
$params->{$param_name}{type} = 'number'; |
382
|
|
|
|
|
|
|
} |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
#/$t/id |
385
|
16
|
100
|
|
|
|
42
|
if ($name eq 'id') { |
386
|
4
|
|
|
|
|
13
|
$params->{$param_name}{in} = 'path'; |
387
|
4
|
|
|
|
|
40
|
$params->{$param_name}{required} = Mojo::JSON->true; |
388
|
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
# GET and DELETE |
390
|
4
|
|
|
|
|
36
|
push @{$args->{show_params}}, $params->{$param_name}; |
|
4
|
|
|
|
|
22
|
|
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
# PUT |
393
|
4
|
|
|
|
|
8
|
push @{$args->{update_params}}, $params->{$param_name}; |
|
4
|
|
|
|
|
12
|
|
394
|
4
|
|
|
|
|
11
|
next; |
395
|
|
|
|
|
|
|
} |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# All other params are in form-data |
398
|
12
|
|
|
|
|
34
|
$params->{$param_name}{in} = 'formData'; |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
# POST |
401
|
12
|
|
|
|
|
18
|
push @{$args->{store_params}}, $params->{$param_name}; |
|
12
|
|
|
|
|
34
|
|
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
# PUT |
404
|
12
|
|
|
|
|
20
|
push @{$args->{update_params}}, $params->{$param_name}; |
|
12
|
|
|
|
|
38
|
|
405
|
|
|
|
|
|
|
} #end for my $col (@{$self->_column_info($t)}) |
406
|
4
|
|
|
|
|
18
|
$args->{t} = lc $t; |
407
|
|
|
|
|
|
|
|
408
|
4
|
|
|
|
|
12
|
for my $r (qw(home_ show_ store_ update_ remove_)) { |
409
|
20
|
|
|
154
|
|
77
|
$args->{$r . 'route'} = first { $_->{name} =~ /^$r$t/ } @{$self->routes}; |
|
154
|
|
|
|
|
690
|
|
|
20
|
|
|
|
|
63
|
|
410
|
|
|
|
|
|
|
} |
411
|
4
|
|
|
|
|
15
|
state $path_tmpl_file = $self->_template_path('path.json.ep'); |
412
|
4
|
|
|
|
|
160
|
my $ugly = Mojo::Template->new->render_file($path_tmpl_file, $args); |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
# Make sure the generated JSON is syntactically correct. |
415
|
4
|
|
|
|
|
108
|
my $decoded = JSON::PP::decode_json($ugly); |
416
|
|
|
|
|
|
|
|
417
|
4
|
|
|
|
|
94707
|
$args->{api_paths} = {%{$args->{api_paths}}, %$decoded}; |
|
4
|
|
|
|
|
33
|
|
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
# Cleanup for the next table |
420
|
|
|
|
|
|
|
delete $args->{$_} |
421
|
4
|
|
|
|
|
49
|
for ( |
422
|
|
|
|
|
|
|
qw(t store_params update_params show_params |
423
|
|
|
|
|
|
|
home_route show_route store_route update_route remove_route) |
424
|
|
|
|
|
|
|
); |
425
|
4
|
|
|
|
|
49
|
return; |
426
|
|
|
|
|
|
|
} |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
1; |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
|
431
|
|
|
|
|
|
|
=encoding utf8 |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
=head1 NAME |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
Mojolicious::Command::generate::resources - Generate MVC & OpenAPI RESTful API files from database tables |
436
|
|
|
|
|
|
|
|
437
|
|
|
|
|
|
|
=head1 SYNOPSIS |
438
|
|
|
|
|
|
|
|
439
|
|
|
|
|
|
|
Usage: APPLICATION generate resources [OPTIONS] |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
my_app.pl generate help resources # help with all available options |
442
|
|
|
|
|
|
|
my_app.pl generate resources --tables users,groups |
443
|
|
|
|
|
|
|
my_app.pl generate resources --tables users,groups -D dbx |
444
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
=head1 PERL REQUIREMENTS |
446
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
This command uses L, therefore Perl 5.20 is required. |
448
|
|
|
|
|
|
|
|
449
|
|
|
|
|
|
|
=head1 DESCRIPTION |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
An usable release... |
452
|
|
|
|
|
|
|
|
453
|
|
|
|
|
|
|
L generates directory structure for |
454
|
|
|
|
|
|
|
a fully functional L |
455
|
|
|
|
|
|
|
L, |
456
|
|
|
|
|
|
|
L and RESTful API specification in |
457
|
|
|
|
|
|
|
L format based on |
458
|
|
|
|
|
|
|
existing tables in your application's database. |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
The purpose of this tool is to promote |
461
|
|
|
|
|
|
|
L by generating |
462
|
|
|
|
|
|
|
the boilerplate code for model (M), templates (V) and controller (C) and help |
463
|
|
|
|
|
|
|
programmers to quickly create well structured, fully functional applications. |
464
|
|
|
|
|
|
|
It assumes that you already have tables created in a database and you just want |
465
|
|
|
|
|
|
|
to generate |
466
|
|
|
|
|
|
|
L actions |
467
|
|
|
|
|
|
|
for them. |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
In the generated actions you will find eventually working code for reading, |
470
|
|
|
|
|
|
|
creating, updating and deleting records from the tables you specified on the |
471
|
|
|
|
|
|
|
command-line. The generated code is just boilerplate to give you a jump start, |
472
|
|
|
|
|
|
|
so you can concentrate on writing your business-specific code. It is assumed |
473
|
|
|
|
|
|
|
that you will modify the generated code to suit your specific needs. All the |
474
|
|
|
|
|
|
|
generated code is produced from templates. You can copy the folder with the |
475
|
|
|
|
|
|
|
templates, push it to C<@{$app-Erenderer-Epaths}> and modify to your |
476
|
|
|
|
|
|
|
taste. Please look into the C folder of this distribution for examples. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
The command expects to find and will use one of the commonly used helpers |
479
|
|
|
|
|
|
|
C, C C. The supported wrappers are respectively L, |
480
|
|
|
|
|
|
|
L and L. |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
=head1 OPTIONS |
483
|
|
|
|
|
|
|
|
484
|
|
|
|
|
|
|
Below are the options this command accepts, described in Getopt::Long notation. |
485
|
|
|
|
|
|
|
Both short and long variants are shown as well as the types of values they |
486
|
|
|
|
|
|
|
accept. All of them, beside C<--tables>, are guessed from your application and |
487
|
|
|
|
|
|
|
usually do not need to be specified. |
488
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
|
490
|
|
|
|
|
|
|
=head2 H|home_dir=s |
491
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
Optional. Defaults to Chome> (which is MyApp home directory). Used to |
493
|
|
|
|
|
|
|
set the root directory to which the files will be dumped. If you set this |
494
|
|
|
|
|
|
|
option, respectively the C and C folders will be created under the |
495
|
|
|
|
|
|
|
new C. If you want them elsewhere, set these options explicitly. |
496
|
|
|
|
|
|
|
|
497
|
|
|
|
|
|
|
=head2 L|lib=s |
498
|
|
|
|
|
|
|
|
499
|
|
|
|
|
|
|
Optional. Defaults to Chome/lib> (relative to the C<--home_dir> |
500
|
|
|
|
|
|
|
directory). If you installed L in some custom path and you wish to |
501
|
|
|
|
|
|
|
generate your controllers into e.g. C, set this option. |
502
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
=head2 api_dir=s |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
Optional. Directory where |
506
|
|
|
|
|
|
|
the L C file will |
507
|
|
|
|
|
|
|
be generated. Defaults to Chome/api> (relative to the C<--home_dir> |
508
|
|
|
|
|
|
|
directory). If you installed L in some custom path and you wish to |
509
|
|
|
|
|
|
|
generate your C files into for example C, set |
510
|
|
|
|
|
|
|
this option explicitly. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=head2 C|controller_namespace=s |
513
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Optional. The namespace for the controller classes to be generated. Defaults to |
515
|
|
|
|
|
|
|
Croutes-Enamespaces-E[0]>, usually L, where |
516
|
|
|
|
|
|
|
MyApp is the name of your application. If you decide to use another namespace |
517
|
|
|
|
|
|
|
for the controllers, do not forget to add it to the list |
518
|
|
|
|
|
|
|
Croutes-Enamespaces> in C or your plugin |
519
|
|
|
|
|
|
|
configuration file. Here is an example. |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
# Setting the Controller class from which all controllers must inherit. |
522
|
|
|
|
|
|
|
# See /perldoc/Mojolicious/#controller_class |
523
|
|
|
|
|
|
|
# See /perldoc/Mojolicious/Guides/Growing#Controller-class |
524
|
|
|
|
|
|
|
app->controller_class('MyApp::C'); |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
# Namespace(s) to load controllers from |
527
|
|
|
|
|
|
|
# See /perldoc/Mojolicious#routes |
528
|
|
|
|
|
|
|
app->routes->namespaces(['MyApp::C']); |
529
|
|
|
|
|
|
|
|
530
|
|
|
|
|
|
|
=head2 M|model_namespace=s |
531
|
|
|
|
|
|
|
|
532
|
|
|
|
|
|
|
Optional. The namespace for the model classes to be generated. Defaults to |
533
|
|
|
|
|
|
|
L. |
534
|
|
|
|
|
|
|
|
535
|
|
|
|
|
|
|
=head2 T|templates_root=s |
536
|
|
|
|
|
|
|
|
537
|
|
|
|
|
|
|
Optional. Defaults to Crenderer-Epaths-E[0]>. This is usually |
538
|
|
|
|
|
|
|
Chome/templates> directory. If you want to use another directory, do |
539
|
|
|
|
|
|
|
not forget to add it to the Crenderer-Epaths> list in your |
540
|
|
|
|
|
|
|
configuration file. Here is how to add a new directory to |
541
|
|
|
|
|
|
|
Crenderer-Epaths> in C. |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# Application/site specific templates |
544
|
|
|
|
|
|
|
# See /perldoc/Mojolicious/Renderer#paths |
545
|
|
|
|
|
|
|
unshift @{app->renderer->paths}, $home->rel_file('site_templates'); |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
=head2 D|db_helper=s |
548
|
|
|
|
|
|
|
|
549
|
|
|
|
|
|
|
Optional. If passed, this method name will be used when generating Model |
550
|
|
|
|
|
|
|
classes and helpers. The application is still expected to support the unified |
551
|
|
|
|
|
|
|
API of the supported database adapters. This feature helps to generate code |
552
|
|
|
|
|
|
|
for an application that wants to support all the three adaptors or if for |
553
|
|
|
|
|
|
|
example tomorrow suddenly appears a Mojo::Oracle tiny wrapper around |
554
|
|
|
|
|
|
|
L. |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=head2 t|tables=s@ |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
Mandatory. List of tables separated by commas for which controllers should be generated. |
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
=head1 SUPPORT |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
Please report bugs, contribute and make merge requests on |
563
|
|
|
|
|
|
|
L. |
564
|
|
|
|
|
|
|
|
565
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
L inherits all attributes from |
568
|
|
|
|
|
|
|
L and implements the following new ones. |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
=head2 args |
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
Used for storing arguments from the command-line. |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
my $args = $self->args; |
575
|
|
|
|
|
|
|
|
576
|
|
|
|
|
|
|
=head2 description |
577
|
|
|
|
|
|
|
|
578
|
|
|
|
|
|
|
my $description = $command->description; |
579
|
|
|
|
|
|
|
$command = $command->description('Foo!'); |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
Short description of this command, used for the C<~$ mojo generate> commands |
582
|
|
|
|
|
|
|
list. |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
=head2 routes |
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
$self->routes; |
587
|
|
|
|
|
|
|
|
588
|
|
|
|
|
|
|
Returns an ARRAY reference containing routes, prepared after |
589
|
|
|
|
|
|
|
C<$self-Eargs-E{tables}>. Suggested Perl code for the routes is dumped |
590
|
|
|
|
|
|
|
in a file named TODO in C<--homedir> so you can copy and paste into your |
591
|
|
|
|
|
|
|
application code. |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
=head2 usage |
594
|
|
|
|
|
|
|
|
595
|
|
|
|
|
|
|
my $usage = $command->usage; |
596
|
|
|
|
|
|
|
$command = $command->usage('Foo!'); |
597
|
|
|
|
|
|
|
|
598
|
|
|
|
|
|
|
Usage information for this command, used for the help screen. |
599
|
|
|
|
|
|
|
|
600
|
|
|
|
|
|
|
=head1 METHODS |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
L inherits all methods from |
603
|
|
|
|
|
|
|
L and implements the following new ones. |
604
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
=head2 run |
606
|
|
|
|
|
|
|
|
607
|
|
|
|
|
|
|
Mojolicious::Command::generate::resources->new(app=>$app)->run(@ARGV); |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
Run this command. |
610
|
|
|
|
|
|
|
|
611
|
|
|
|
|
|
|
=head2 render_template_to_file |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
Renders a template from a file to a file using L. Parameters: |
614
|
|
|
|
|
|
|
C<$tmpl_file> - full path tho the template file; C<$target_file> - full path to |
615
|
|
|
|
|
|
|
the file to be written; C<$template_args> - a hash reference containing the |
616
|
|
|
|
|
|
|
arguments to the template. See also L. |
617
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
$self->render_template_to_file($tmpl_file, $target_file, $template_args); |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
=head2 generate_formfields |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
Generates form-fields from columns information found in the respective table. |
623
|
|
|
|
|
|
|
The result is put into C<_form.html.ep>. The programmer can then modify the |
624
|
|
|
|
|
|
|
generated form-fields. |
625
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
$form_fields = $self->generate_formfields($table_name); |
627
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
=head2 generate_openapi |
629
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
Generates L file in json |
631
|
|
|
|
|
|
|
format. The generated file is put in L--api_dir>. The filename is |
632
|
|
|
|
|
|
|
C. This is the file which will be loaded by C. |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
=head2 generate_path_api |
635
|
|
|
|
|
|
|
|
636
|
|
|
|
|
|
|
Generates API definitions and paths for each table. Invoked in |
637
|
|
|
|
|
|
|
L. B C<$t> - the table name; |
638
|
|
|
|
|
|
|
C<$api_defs_object> - the object API definition, based on the table name; |
639
|
|
|
|
|
|
|
C<$tmpl_args> - the arguments for the templates. C<$api_defs_object> and |
640
|
|
|
|
|
|
|
C<$tmpl_args> will be enriched with additional key-value pairs as required by |
641
|
|
|
|
|
|
|
the OpenAPI specification. Returns C. |
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
=head2 generate_validation |
644
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
Generates code for the C<_validation> method in the respective controler. |
646
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
$validation_code = $self->generate_validation($table_name); |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=head1 TODO |
650
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
The work on the features may not go in the same order specified here. Some |
652
|
|
|
|
|
|
|
parts may be fully implemented while others may be left for later. |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
- Improve documentation. |
655
|
|
|
|
|
|
|
- Add initial documentation stub to the generated classes. |
656
|
|
|
|
|
|
|
- Improve templates to generate code to which is more ready to use. |
657
|
|
|
|
|
|
|
- Append to the existing api.json if it already exists. More tests. |
658
|
|
|
|
|
|
|
|
659
|
|
|
|
|
|
|
=head1 AUTHOR |
660
|
|
|
|
|
|
|
|
661
|
|
|
|
|
|
|
Красимир Беров |
662
|
|
|
|
|
|
|
CPAN ID: BEROV |
663
|
|
|
|
|
|
|
berov@cpan.org |
664
|
|
|
|
|
|
|
|
665
|
|
|
|
|
|
|
=head1 COPYRIGHT |
666
|
|
|
|
|
|
|
|
667
|
|
|
|
|
|
|
This program is free software licensed under |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
Artistic License 2.0 |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
The full text of the license can be found in the LICENSE file included with |
672
|
|
|
|
|
|
|
this module. |
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
=head1 SEE ALSO |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
L, |
677
|
|
|
|
|
|
|
L, |
678
|
|
|
|
|
|
|
L, |
679
|
|
|
|
|
|
|
L, |
680
|
|
|
|
|
|
|
L. |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=cut |
683
|
|
|
|
|
|
|
|