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

Data::MuForm::Manual::Hooks - Overriding or supplementing form processing

VERSION

version 0.05

SYNOPSIS

Manual Index

There are a number of places that you can use to override the processing of a form. Some of these are explicitly provided as hooks, others are methods that are convenient to override.

A lot of the MuForm (and FormHandler) flexibility comes from the supported ability to override parts of form object processing.

Note that these 'supported' hooks do not mean that you can't override other methods with 'before', 'around', and 'after', or with a standard override plus $self->next::method(@). The methods listed here are just the places that handle the most common requirements.

DESCRIPTION

To understand where in the process these hooks or overrides occur, it's probably best to read the MuForm code. The 'process' or 'check' methods in Data::MuForm contain the flow in the simplest form.

after_build_fields

This method is called from BUILD, after the 'build_fields' method completes. This is probably the best place to put code that modifies the fields based on some attribute, or the place to put things like providing all fields with a different build_id method. Code that in FH was handled by 'update_subfields' would go here. At this point the "base" fields in a repeatable are most easily updated. After the fields are "filled" in 'setup', there may be cloned fields to represent the instances of the Repeatable. This would also be a good place to do 'add_field', if you're creating a new form object on every request.

    sub after_build_fields {
        my $self = shift;
        foreach my $field ( values %{$self->index} ) {
            $field->{methods}->{build_id} = \&build_id;
        }
    }

(Note: the above is purely an example, but you don't need to do that to have a common form build_id method. You only have to create a 'build_field_id' sub in the form class.)

Note that looking in the 'index' will get you all the fields, but if you use the 'all_fields' method, you would only get the top-level fields and would need to also loop through sub-fields (such as in a Compound or Repeatable) if you have them.

    sub after_build_fields {
        my $self = shift;
        foreach my $field ( $self->all_repeatable_fields ) {
            $field->init_instance({ 'ra.wa.class' => ['rep_elem'] });
        }
        foreach my $field ( $self->all_fields ) {
            if ( $field->type eq 'Select' ) {
                $field->render_args->{wrapper_attr}{class} = ['sel_wrapper'];
            }
            elsif ( $field->type eq 'Boolean' ) {
                $field->render_args->{element_attr}{class} = ['sel_elem'];
            }
        }
    }

This method is a user hook. No internal MuForm code will use this method.

in_setup

This comes in the 'setup' sub, right after 'set_active' is called. In FormHandler forms, the same point in the process was usually hooked by overriding 'set_active'. This is a good place to change the status of fields on this process call, such as setting fields inactive or active (if done by code instead of with arguments in the process call), setting fields disabled or not, etc.

This would probably be a good place to do 'add_field', if you're using that instead of activating/inactivating fields or using 'include'.

This method is purely a hook. No internal MuForm code will use this method.

after_setup

This is called after the 'setup' method completes. This would be useful if you want to modify fields after the field values and inputs have been filled in by the 'fill_from_object', 'fill_from_fields', and 'fill_from_input' methods have completed. (The 'fill_from' methods were '_result_from_*' methods in FH.)

This method is a user hook. No internal MuForm code will use this method.

validate

This is the normal place to put form-level validation code. No internal MuForm code will use this method. Called in 'validate_form' which is called by 'process' and 'check'.

validate_model

This is called by the DBIC model to validate that unique fields are unique. If you create your own model you could use it, but otherwise you'd probably just use the 'validate' method.

This will not run if you use 'check'.

update_model

This method is very commonly overridden. If you're using the DBIC model and want the normal DBIC model updates to be done, you need to do $self->next::method(@_) or use some method modifier.

If you want to insert additional column updates that don't come directly from the form's fields, you can insert them into the 'values' hashref here, before calling 'next::method'.

Some of the ways that relationships like Repeatables are updated don't work well with some databases, so this would be the place where you'd handle those updates yourself. You can either delete those fields from the 'values' hashref and update just those, or handle all of the updates yourself.

This is also the place where you'd do database updates on form validation if you're *not* using the DBIC model. A common pattern is to add a 'schema' attribute to the form, and then perform the database updates from the form data in this method. This treats the form class as a kind of 'model', and keeps more code out of the controllers, which lets you create better test cases.

This will not run if you use 'check'.

after_update_model

This method reloads Repeatable fields after processing, but can also be overridden if you need to do some similar kind of cleanup. If you have Repeatable fields, be sure to allow the base method to run.

This will not run if you use 'check'.

AUTHOR

Gerda Shank

COPYRIGHT AND LICENSE

This software is copyright (c) 2018 by Gerda Shank.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.