=pod

=head1 NAME

Form::Tiny::Manual::Internals - details on form implementation

=head1 DESCRIPTION

This guide gets in depth into Form::Tiny metaobject model. This knowledge
should not be required to make full use of the module, but is required to
extend it or contribute to it.

=head2 How does the module work?

Behind the scenes, the module stores objects of L<Form::Tiny::Meta> for each
package that was turned into a form by a proper Form::Tiny call. Meta object is
an object that stores all information about the form layout, but no information
about form input or validation state. Each class of L<Form::Tiny::Form>
contains the C<form_meta> method, which returns this meta object for the given
package.

Form building is done just by calling methods on the meta object. Each helper
of the DSL is just a single call to a metaobject method, for example, the
following calls are equivalent:

	form_field 'field-name' => %args;
	__PACKAGE__->form_meta->add_field('field-name' => %args);

The actual form object only stores data that is relevant to form state, not to
form layout. Thanks to this model, the layout needs not to be rebuilt each time
a new form object is constructed, which speeds up construction.

Additional behavior like filtering is implemented by composing new roles to the
meta object and declaring new hooks in C<setup> method. Refer to the code of
L<Form::Tiny::Plugin::Filtered> to see how meta roles may define additional
behavior.

=head3 Why use meta object model at all?

The I<1.00> series of the module did not implement a meta object, and in turn
implementing DSL keywords ended up being a hack, abusing Perl's ability to
replace symbols in the package with strict mode turned off. New implementation
allowed to get rid of all that dark magic, replacing it with something readable
and reliable.

=head2 Static forms vs dynamic forms

The form metaobject keeps track of whether it is static or dynamic via the
C<is_dynamic> property.

A dynamic form is a form that has at least one dynamic field. Dynamic fields
are fields that are built by a subroutine.

Static forms are preferred over dynamic forms because they allow us to make
certain optimizations and overall know more about a form from just having its
metaobject. Dynamic forms are more of a closed box, and the only way to know
what's inside is by building them with an instantiated form.

For the sake of completeness and backwards compatibility, we continue to
support dynamic forms in the base distribution.

=head2 Form blueprint

Form metaobjects can be used to produce a Perl hash reference with an identical
structure to fields data, called I<blueprint>. For example, a form with those
fields:

	scalar1
	array1.*
	array2.*.*
	hash1.scalar2
	hash1.scalar3

Will generate this blueprint:

	{
		scalar1 => FieldDefinition,
		array1 => [FieldDefinition],
		array2 => [
			[FieldDefinition]
		],
		hash1 => {
			scalar2 => FieldDefinition,
			scalar3 => FieldDefinition
		}
	}

Each leaf will be a L<Form::Tiny::FieldDefinition> instance, and subforms will
be turned into their own blueprints and embedded. This can be used to do more
post-processing on a C<< $form->fields >> hashref compared to the full form
definition, without the need to loop the form fields array and manually handle
all the possibilities.

To get the blueprint of a form, call:

	# for dynamic forms or when
	# it is not known whether the form in dynamic
	$blueprint = $form_object->form_meta->blueprint($form_object, %options);

	# for static forms - all calls are valid
	$blueprint = $form_object->form_meta->blueprint(%options);
	$blueprint = FormPackage->form_meta->blueprint(%options);

For static forms without extra options, the blueprint will be cached and reused
on the next call. Otherwise, it has to be generated each time, which will
impose a performance hit if it is called frequently.

Additionally, the C<blueprint> method can accept a hash of options. Currently
supported options are:

=over

=item * recurse => Bool

If passed C<0>, subforms will not be turned into their own blueprints, but will
end up as a L<Form::Tiny::FieldDefinition> object instead. C<1> by default.

=item * transform => sub ($field_definition, $default_handler)

This option enables a way to specify a custom handler which will be used to
turn C<$field_definition> into a blueprint value. This subroutine reference is
expected to return a scalar value - a new blueprint value.

In case you want to turn back into the default handler, call C<<
$default_handler->($field_definition) >>.

=back

=head2 Finalizing the meta

After creating the meta object with C<create_form_meta> function, the object
exists in an incomplete state. It is so that superclasses can be applied before
finalizing the metaobject and applying inheritance. Calling
C<get_package_form_meta> will apply all changes needed to achieve complete
state.

Finalized meta is not really a complete form - the inheritance and basic setup
is done, but it still misses all of its parts like hooks and fields. Since we
use no keyword just before finishing the package like Moose's C<<
meta->make_immutable >>, the form meta has no way of knowing when it has
actually been filled with those elements. The current strategy to work around
this (when it is needed at all) is to update meta incrementally when adding
those elements.

=head2 Using the module without the syntactic sugar

It is entirely possible, although a bit tedious, to use the module without
importing L<Form::Tiny> package. The following example declares a form with a
single field taken from the example above.

The code present in C<metaobject.pl> example should result in a form that has
the same capabilities as the one below:

	package MyForm;

	use Form::Tiny;

	form_field 'field-name' => (
		required => 1,
	);

	1;

B<Notice:> building your form like this should be done only for educational
purposes. Changes in import procedure are not covered by the 3 month
deprecation period policy.

=head1 SEE ALSO

=over

=item * L<Form::Tiny::Manual>

=item * L<Form::Tiny::Manual::Compatibility>

=back

