The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Form::Tiny::Plugin - base class for Form::Tiny plugins

SYNOPSIS

        package Form::Tiny::Plugin::MyPlugin;

        use parent 'Form::Tiny::Plugin';

        sub plugin
        {
                my ($self, $caller, $context) = @_;

                return {
                        subs => {
                                subname => sub { ... },
                        },
                        roles => ['My::Role', ...],
                        meta_roles => ['My::Meta::Role', ...],
                };
        }

DESCRIPTION

Plugins are interface and behavior definitions for Form::Tiny forms - they determine how the form is built and can change how it behaves.

To use your plugin in a form, Form::Tiny must be imported like this:

        use Form::Tiny plugins => [qw(MyPlugin +Full::Namespace::Plugin)];

Prepending the name with a plus sign will stop Form::Tiny from prepending the given name with Form::Tiny::Plugin::.

WRITING A PLUGIN

Plugin definition consists of:

  • subs which will be added to the namespace

    These subs will be treated as new DSL keywords. They will be imported into the package and take part in building the form, but they can also be cleaned away with namespace::autoclean (together with all other DSL keywords).

  • roles which will be composed to the package

    These roles and all roles from other plugins will be composed into the form package in one operation, detecting method conflicts properly.

  • meta roles which will be composed to the meta object

    Same as roles, but for the package metaobject.

You may specify all, any, or none of those in the resulting hashref of the plugin method. It will be called in class context:

        Form::Tiny::Plugin::MyPlugin->plugin($caller, $context);

Where:

Your plugin package must inherit from Form::Tiny::Plugin and must reintroduce the plugin method (without calling SUPER::plugin).

Accessing form metaobject

The $caller variable will be a class name with form_meta method. However, since your plugin will take part in configuring the form, there will not yet be a form_meta method during execution of plugin:

        sub plugin
        {
                my ($self, $caller, $context) = @_;

                # Bad - form is still being configured, and the meta method hasn't yet been generated
                $caller->form_meta;

                return {
                        subs => {
                                subname => sub {
                                        # Good - called after the package has been fully configured
                                        $caller->form_meta;
                                }
                        }
                };

If you wish to perform an action after the form is configured, consider implementing a metaobject role that will have an after method modifier on setup method.

Handling context

Context is passed into the plugin method as a scalar reference. Your DSL keywords can set or consume context, and it should always be a subclass of Form::Tiny::FieldDefinition or Form::Tiny::FieldDefinitionBuilder. The reference itself is guaranteed to be defined.

        sub plugin
        {
                my ($self, $caller, $context) = @_;

                return {
                        subs => {
                                # set field to required with a keyword
                                is_required => sub {
                                        die 'no context'
                                                unless defined $$context;

                                        die 'field for rename must be static'
                                                unless $$context->isa('Form::Tiny::FieldDefinition');

                                        $$context->set_required(1);
                                },
                        },
                };
        }

Example plugins

All of Form::Tiny importing functionality is based on plugins. See these packages as a reference: