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 )