Mojolicious-Plugin-FormFieldsFromJSON
view release on metacpan or search on metacpan
lib/Mojolicious/Plugin/FormFieldsFromJSON.pm view on Meta::CPAN
radio => 1,
hidden => 1,
textarea => 1,
password => 1,
);
my %configfiles;
$app->helper(
forms => sub {
if (%configfiles) {
my @sorted_configfiles = sort keys %configfiles;
return @sorted_configfiles;
}
for my $dir ( @{ $self->dir } ) {
my $dir = IO::Dir->new($dir);
FILE:
while ( my $file = $dir->read ) {
next FILE if $file !~ m{\.json\z};
my $filename = basename $file;
$filename =~ s{\.json\z}{};
$configfiles{$filename} = 1;
}
}
my @sorted_configfiles = sort keys %configfiles;
return @sorted_configfiles;
}
);
$app->helper( "form_fields_from_json_dir" => sub { return $self->dir } );
$app->helper(
fields => sub {
my ( $c, $file, $params ) = @_;
if ( !$configs{$file} ) {
$self->_load_config_from_file( $c, \%configs, $file );
}
my @fields;
my @fields_long;
for my $field ( @{ $configs{$file} } ) {
my $name = $field->{label} // $field->{name} // '';
push @fields, $name;
push @fields_long, +{ label => $name, name => $field->{name} // '' };
}
if ( $params and $params->{hash} ) {
return @fields_long;
}
return @fields;
}
);
$app->helper(
'validate_form_fields' => sub {
my ( $c, $file ) = @_;
return '' if !$file;
if ( !$configs{$file} ) {
$self->_load_config_from_file( $c, \%configs, $file );
}
return '' if !$configs{$file};
my $config = $configs{$file};
my $validation = $c->validation;
my $params_hash = $c->req->params->to_hash;
my @param_names = keys %{ $params_hash || {} };
my %params;
for my $name ( @param_names ) {
my $param_values = $c->every_param($name);
$params{$name} = @{$param_values || [] } > 1 ?
$param_values : $param_values->[-1];
}
$validation->input( \%params );
my %errors;
FIELD:
for my $field ( @{$config} ) {
if ( 'HASH' ne ref $field ) {
$app->log->error('Field definition must be a HASH - skipping field');
next FIELD;
}
if ( !$field->{validation} ) {
next FIELD;
}
if ( 'HASH' ne ref $field->{validation} ) {
$app->log->warn('Validation settings must be a HASH - skipping field');
next FIELD;
}
my $filters = $field->{validation}->{filters};
my $name = $field->{name} // $field->{label} // '';
my $global_error = 1;
if ( $field->{validation}->{required} ) {
$validation->required($name, @{ $filters || [] });
my $value = $field->{validation}->{required};
if ( ref $value && 'HASH' eq ref $value ) {
$global_error = $value->{msg} // 1;
}
}
else {
$validation->optional($name, @{ $filters || [] });
lib/Mojolicious/Plugin/FormFieldsFromJSON.pm view on Meta::CPAN
};
Now you can use
[
{
"label" : "Name",
"type" : "testfield",
"name" : "name"
}
]
For more details see L<Additional Types|/New Types>.
=back
=head1 HELPER
=head2 form_fields
C<form_fields> returns a string with all configured fields "translated" to HTML.
$controller->form_fields( 'formname' );
Given this configuration:
[
{
"label" : "Name",
"type" : "text",
"name" : "name"
},
{
"label" : "City",
"type" : "text",
"name" : "city"
}
]
You'll get
<input id="name" name="name" type="text" value="" />
<input id="city" name="city" type="text" value="" />
=head3 dynamic config
Instead of a formname, you can pass a config:
$controller->form_fields(
[
{
"label" : "Name",
"type" : "testfield",
"name" : "name"
}
]
);
This way, you can build your forms dynamically (e.g. based on database entries).
=head2 validate_form_fields
This helper validates the input. It uses the L<Mojolicious::Validator::Validation> and it
validates all fields defined in the configuration file.
For more details see L<Validation|Mojolicious::Plugin::FormFieldsFromJSON/Validation>.
=head2 forms
This method returns a list of forms. That means the filenames of all .json files
in the configured directory.
my @forms = $controller->forms;
The filenames are returned without the file suffix .json.
=head2 fields
C<fields()> returns a list of fields (label or name).
my @fieldnames = $controller->fields('formname');
If your configuration looks like
[
{
"label" : "Email",
"name" : "email",
"type" : "text"
},
{
"name" : "password",
"type" : "password"
}
]
You get
(
Email,
password
)
=head1 FIELD DEFINITIONS
This plugin supports several form fields:
=over 4
=item * text
=item * checkbox
=item * radio
=item * select
=item * textarea
=item * password
=item * hidden
=back
lib/Mojolicious/Plugin/FormFieldsFromJSON.pm view on Meta::CPAN
Country: <select id="country" name="country"><option value="au">au</option></select>
=head2 A field specific template
When you want to use a different template for a specific field, you can use the
C<template> field in the configuration file.
plugin 'FormFieldsFromJSON' => {
dir => File::Spec->catdir( dirname( __FILE__ ) || '.', 'conf' ),
template => '<label for="<%= $id %>"><%= $label %>:</label><div><%= $field %></div>',
};
With a configuration file like
[
{
"label" : "Name",
"type" : "text",
"name" : "name"
}
{
"label" : "Country",
"type" : "select",
"name" : "country",
"data" : [ "au" ],
"template" : "<%= $label %>: <%= $field %>"
}
]
You get
<label for="name">Name:</label><div><input id="name" name="name" type="text" value="" /></div>
Country: <select id="country" name="country"><option value="au">au</option></select>
=head2 Template variables
You get three template variables for free:
=over 4
=item * $label
If a label is defined in the field configuration
=item * $field
The form field (HTML)
=item * $id
The id for the field. If no id is defined, the name of the field is set.
=back
=head1 Validation
You can define some validation rules in your config file. And when you call C<validate_form_fields>, the
fields defined in the configuration file are validated.
L<Mojolicious::Validator::Validation> is shipped with some basic validation checks:
=over 4
=item * in
=item * size
=item * like
=item * equal_to
=back
There is L<Mojolicious::Plugin::AdditionalValidationChecks> with some more basic checks. And you can also
define your own checks.
The I<validation> field is a hashref where the name of the check is the key
and the parameters for the check can be defined in the value:
"validation" : {
"size" : [ 2, 5 ]
},
This will call C<< ->size(2,5) >>. If you want to pass a single parameter,
you can set a scalar:
"validation" : {
"equal_to" : "foo"
},
Validation checks are done in asciibetical order.
You can also use the L<filters|Mojolicious::Validator/FILTERS>:
"validation" : {
"size" : [ 2, 5 ],
"filters" : [ "trim" ]
},
=head2 Check a string for its length
This is a simple check for the length of a string
[
{
"label" : "Name",
"type" : "text",
"validation" : {
"size" : [ 2, 5 ]
},
"name" : "name"
}
]
Then you can call C<validate_form_fields>:
my %errors = $c->validate_form_fields( $config_name );
In the returned hash, you get the fieldnames as keys where a validation check fails.
=head2 A mandatory string
If you have mandatory fields, you can define them as required
[
{
"label" : "Name",
"type" : "text",
"validation" : {
"required" : "name"
},
"name" : "name"
}
]
=head2 Provide your own error message
With the simple configuration seen above, the C<%error> hash contains the value "1" for
each invalid field. If you want to get a better error message, you can define a hash
in the validation config
[
{
"label" : "Name",
"type" : "text",
"validation" : {
"like" : { "args" : [ "es" ], "msg" : "text must contain 'es'" },
"size" : { "args" : [ 2, 5 ], "msg" : "length must be between 2 and 5 chars" }
},
"name" : "name"
}
]
Examples:
text | error
-------+---------------------------------
test |
t | text must contain 'es'
tester | length must be between 2 and 5 chars
=head1 Translation
Most webapplications nowadays are internationalized, therefor this module
provides some support for translations.
If I<translate_labels> is set to a true value, a template is used and
I<translation_method> is given, the labels are translated.
=head2 translation_method
I<translation_method> has to be a reference to a subroutine.
=head3 An example for translation
Load and configure the plugin:
( run in 1.500 second using v1.01-cache-2.11-cpan-39bf76dae61 )