Catalyst-Controller-HTML-FormFu

 view release on metacpan or  search on metacpan

lib/Catalyst/Controller/HTML/FormFu.pm  view on Meta::CPAN

package Catalyst::Controller::HTML::FormFu;

# ABSTRACT: Catalyst integration for HTML::FormFu

use strict;

our $VERSION = '2.04'; # VERSION
our $AUTHORITY = 'cpan:NIGELM'; # AUTHORITY

use Moose;

use HTML::FormFu;
use Config::Any;
use Regexp::Assemble;
use Scalar::Util qw/ isweak weaken /;
use Carp qw/ croak /;

use namespace::autoclean;

# see https://rt.cpan.org/Ticket/Display.html?id=55780
BEGIN {
    extends 'Catalyst::Controller';
}

with 'Catalyst::Component::InstancePerContext';

has _html_formfu_config => ( is => 'rw' );

sub build_per_context_instance {
    my ( $self, $c ) = @_;
    return $self unless ( ref $c );
    $self->{c} = $c;

    weaken( $self->{c} )
        if !isweak( $self->{c} );

    return $self;
}

sub BUILD { }

after BUILD => sub {
    my ($self) = @_;

    my $app           = $self->_app;
    my $self_config   = $self->config->{'Controller::HTML::FormFu'} || {};
    my $parent_config = $app->config->{'Controller::HTML::FormFu'} || {};

    my %defaults = (
        request_token_enable          => 0,
        request_token_field_name      => '_token',
        request_token_session_key     => '__token',
        request_token_expiration_time => 3600,
        form_method                   => 'form',
        form_stash                    => 'form',
        form_attr                     => 'Form',
        config_attr                   => 'FormConfig',
        method_attr                   => 'FormMethod',
        form_action                   => "Catalyst::Controller::HTML::FormFu::Action::Form",
        config_action                 => "Catalyst::Controller::HTML::FormFu::Action::FormConfig",
        method_action                 => "Catalyst::Controller::HTML::FormFu::Action::FormMethod",

        multiform_method        => 'multiform',
        multiform_stash         => 'multiform',
        multiform_attr          => 'MultiForm',
        multiform_config_attr   => 'MultiFormConfig',
        multiform_method_attr   => 'MultiFormMethod',
        multiform_action        => "Catalyst::Controller::HTML::FormFu::Action::MultiForm",
        multiform_config_action => "Catalyst::Controller::HTML::FormFu::Action::MultiFormConfig",
        multiform_method_action => "Catalyst::Controller::HTML::FormFu::Action::MultiFormMethod",

        context_stash => 'context',

        model_stash => {},

        constructor           => {},
        multiform_constructor => {},

        config_callback => 1,
    );

    my %args = ( %defaults, %$parent_config, %$self_config );

    my $local_path = $app->path_to( 'root', 'formfu' );

    if (   !exists $args{constructor}{tt_args}
        || !exists $args{constructor}{tt_args}{INCLUDE_PATH} && -d $local_path ) {
        $args{constructor}{tt_args}{INCLUDE_PATH} = [$local_path];
    }

    $args{constructor}{query_type} ||= 'Catalyst';

    if ( !exists $args{constructor}{config_file_path} ) {
        $args{constructor}{config_file_path} = $app->path_to( 'root', 'forms' );

lib/Catalyst/Controller/HTML/FormFu.pm  view on Meta::CPAN


    if ( $config->{request_token_enable} ) {
        $form->plugins(
            {   type            => 'RequestToken',
                context         => $config->{context_stash},
                field_name      => $config->{request_token_field_name},
                session_key     => $config->{request_token_session_key},
                expiration_time => $config->{request_token_expiration_time}
            }
        );
    }

    return $form;
}

sub _multiform {
    my $self = shift;

    require HTML::FormFu::MultiForm;

    my $multi = HTML::FormFu::MultiForm->new(
        {   %{ $self->_html_formfu_config->{constructor} },
            %{ $self->_html_formfu_config->{multiform_constructor} },
            ( @_ ? %{ $_[0] } : () ),
        }
    );

    $self->_common_construction($multi);

    return $multi;
}

sub _common_construction {
    my ( $self, $form ) = @_;

    croak "form or multi arg required" if !defined $form;

    $form->query( $self->{c}->request );

    my $config = $self->_html_formfu_config;

    if ( $config->{config_callback} ) {
        $form->config_callback(
            {   plain_value => sub {
                    return if !defined $_;
                    s{__uri_for\((.+?)\)__}
                     { $self->{c}->uri_for( split( '\s*,\s*', $1 ) ) }eg
                        if /__uri_for\(/;

                    s{__path_to\(\s*(.+?)\s*\)__}
                     { $self->{c}->path_to( split( '\s*,\s*', $1 ) ) }eg
                        if /__path_to\(/;

                    s{__config\((.+?)\)__}
                     { $self->{c}->config->{$1}  }eg
                        if /__config\(/;
                }
            }
        );

        weaken( $self->{c} )
            if !isweak( $self->{c} );
    }

    if ( $config->{languages_from_context} ) {
        $form->languages( $self->{c}->languages );
    }

    if ( $config->{localize_from_context} ) {
        $form->add_localize_object( $self->{c} );
    }

    if ( $config->{default_action_use_name} ) {
        my $action = $self->{c}->uri_for( $self->{c}->{action}->name );

        $self->{c}->log->debug("FormFu - Setting default action by name: $action")
            if $self->{c}->debug;

        $form->action($action);
    }
    elsif ( $config->{default_action_use_path} ) {
        my $action = $self->{c}->{request}->base . $self->{c}->{request}->path;

        $self->{c}->log->debug("FormFu - Setting default action by path: $action")
            if $self->{c}->debug;

        $form->action($action);
    }

    my $context_stash = $config->{context_stash};
    $form->stash->{$context_stash} = $self->{c};
    weaken( $form->stash->{$context_stash} );

    my $model_stash = $config->{model_stash};

    for my $model ( keys %$model_stash ) {
        $form->stash->{$model} = $self->{c}->model( $model_stash->{$model} );
    }

    return;
}

sub create_action {
    my $self = shift;
    my %args = @_;

    my $config = $self->_html_formfu_config;

    for my $type (
        qw/
        form
        config
        method
        multiform
        multiform_config
        multiform_method /
    ) {
        my $attr = $config->{"${type}_attr"};

        if ( exists $args{attributes}{$attr} ) {
            $args{_attr_params} = delete $args{attributes}{$attr};
        }
        elsif ( exists $args{attributes}{"$attr()"} ) {
            $args{_attr_params} = delete $args{attributes}{"$attr()"};
        }
        else {
            next;
        }

        push @{ $args{attributes}{ActionClass} }, $config->{"${type}_action"};
        last;
    }

    $self->SUPER::create_action(%args);
}

1;

__END__

=pod

=encoding UTF-8

=head1 NAME

Catalyst::Controller::HTML::FormFu - Catalyst integration for HTML::FormFu

=head1 VERSION

version 2.04

lib/Catalyst/Controller/HTML/FormFu.pm  view on Meta::CPAN


The form C<< __uri_for(URI, PATH, PARTS)__ >> is also supported, which is
equivalent to C<< $c->uri_for( 'URI', \@ARGS ) >>. At this time, there is no
way to pass query values equivalent to C<< $c->uri_for( 'URI', \@ARGS,
\%QUERY_VALUES ) >>.

The second codeword that is being replaced is C<__path_to( @DIRS )__>. Any
instance is replaced with the result of passing the C<DIRS> arguments to
L<Catalyst/path_to>. Don't use qoutationmarks as they would become part of the
path.

Default value: 1

=head2 default_action_use_name

If set to a true value the action for the form will be set to the currently
called action name.

Default value: C<false>.

=head2 default_action_use_path

If set to a true value the action for the form will be set to the currently
called action path. The action path includes concurrent to action name
additioal parameters which were code inside the path.

Default value: C<false>.

Example:

    action: /foo/bar
    called uri contains: /foo/bar/1

    # default_action_use_name => 1 leads to:
    $form->action = /foo/bar

    # default_action_use_path => 1 leads to:
    $form->action = /foo/bar/1

=head2 model_stash

Arguments: \%stash_keys_to_model_names

Used to place Catalyst models on the form stash.

If it's being used to make a L<DBIx::Class> schema available for
L<HTML::FormFu::Model::DBIC/options_from_model>, for C<Select> and other
Group-type elements - then the hash-key must be C<schema>. For example, if your
schema model class is C<MyApp::Model::MySchema>, you would set C<model_stash>
like so:

    <Controller::HTML::FormFu>
        <model_stash>
            schema MySchema
        </model_stash>
    </Controller::HTML::FormFu>

=head2 context_stash

To allow your form validation packages, etc, access to the catalyst context, a
weakened reference of the context is copied into the form's stash.

    $form->stash->{context};

This setting allows you to change the key name used in the form stash.

Default value: C<context>

=head2 languages_from_context

If you're using a L10N / I18N plugin such as L<Catalyst::Plugin::I18N> which
provides a C<languages> method that returns a list of valid languages to use
for the currect request - and you want to use formfu's built-in I18N packages,
then setting L</languages_from_context>

=head2 localize_from_context

If you're using a L10N / I18N plugin such as L<Catalyst::Plugin::I18N> which
provides it's own C<localize> method, you can set L<localize_from_context> to
use that method for formfu's localization.

=head2 request_token_enable

If true, adds an instance of L<HTML::FormFu::Plugin::RequestToken> to every
form, to stop accidental double-submissions of data and to prevent CSRF
attacks.

=head2 request_token_field_name

Defaults to C<_token>.

=head2 request_token_session_key

Defaults to C<__token>.

=head2 request_token_expiration_time

Defaults to C<3600>.

=head1 DISCONTINUED CONFIG SETTINGS

=head2 config_file_ext

Support for this has now been removed. Config files are now searched for, with
any file extension supported by Config::Any.

=head2 config_file_path

Support for this has now been removed. Use C<< {constructor}{config_file_path}
>> instead.

=head1 CAVEATS

When using the C<Form> action attribute to create an empty form, you must call
L<< $form->process|HTML::FormFu/process >> after populating the form. However,
you don't need to pass any arguments to C<process>, as the Catalyst request
object will have automatically been set in L<< $form->query|HTML::FormFu/query
>>.

When using the C<FormConfig> and C<FormMethod> action attributes, if you make
any modifications to the form, such as adding or changing it's elements, you



( run in 1.123 second using v1.01-cache-2.11-cpan-39bf76dae61 )