.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Bread::Board::Manual::Example::FormSensible 3pm" .TH Bread::Board::Manual::Example::FormSensible 3pm "2022-12-12" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Bread::Board::Manual::Example::FormSensible \- A Form::Sensible and Catalyst example. .SH "VERSION" .IX Header "VERSION" version 0.37 .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& _\|_PACKAGE_\|_\->config( \& # ... your other Catalyst configs ... \& \& # first put our universal \& # FormBuilder container \& # inside the config \& FormBuilder => container \*(AqFormBuilder\*(Aq => [ \*(AqFields\*(Aq ] => as { \& service \*(AqForm\*(Aq => ( \& class => \*(AqForm::Sensible\*(Aq, \& block => sub { \& my $s = shift; \& my $c = $s\->parent; \& my $fields = $c\->get_sub_container(\*(AqFields\*(Aq); \& my $form = Form::Sensible::Form\->new( name => $s\->param(\*(Aqname\*(Aq) ); \& foreach my $name ( $fields\->get_service_list ) { \& $form\->add_field( \& $fields\->get_service( $name )\->get \& ); \& } \& \& if ( my $state = $s\->param(\*(Aqstate\*(Aq) ) { \& $form\->set_values( $state ); \& } \& \& $form; \& }, \& parameters => { \& name => { isa => \*(AqStr\*(Aq }, \& state => { isa => \*(AqHashRef\*(Aq, optional => 1 }, \& } \& ); \& }, \& \& # Then we can build a set of \& # Fields for the \*(Aqfoo\*(Aq form \& Fields => { \& foo => container \*(AqFooFields\*(Aq => [ \*(AqModel\*(Aq ] => as { \& \& service \*(AqUsername\*(Aq => ( \& class => \*(AqForm::Sensible::Field::Text\*(Aq, \& block => sub { \& Form::Sensible::Field::Text\->new( \& name => \*(Aqusername\*(Aq, \& validation => { regex => qr/^[0\-9a\-z]*$/ } \& ); \& } \& ); \& \& service \*(AqPassword\*(Aq => ( \& class => \*(AqForm::Sensible::Field::Text\*(Aq, \& block => sub { \& Form::Sensible::Field::Text\->new( \& name => \*(Aqpassword\*(Aq, \& render_hints => { \& \*(AqHTML\*(Aq => { \& field_type => \*(Aqpassword\*(Aq \& } \& } \& ); \& } \& ); \& \& service \*(AqSubmit\*(Aq => ( \& class => \*(AqForm::Sensible::Field::Trigger\*(Aq, \& block => sub { \& Form::Sensible::Field::Trigger\->new( \& name => \*(Aqsubmit\*(Aq \& ); \& } \& ); \& \& service \*(AqAccessLevel\*(Aq => ( \& class => \*(AqForm::Sensible::Field::Select\*(Aq, \& block => sub { \& my $s = shift; \& my $select = Form::Sensible::Field::Select\->new( \& name => \*(Aqaccess_level\*(Aq, \& ); \& foreach my $access_level ( $s\->param(\*(Aqschema\*(Aq)\->resultset(\*(AqAccessLevels\*(Aq)\->all ) { \& $select\->add_option( \& $access_level\->id, \& $access_level\->name \& ); \& } \& $select; \& }, \& dependencies => { \& schema => depends_on(\*(AqModel/schema\*(Aq) , \& }, \& ); \& } \& } \& ); \& \& \& # later, in a \& # catalyst action ... \& sub process_foo : Local { \& my ($self, $c) = @_; \& my $Model = container \*(AqModel\*(Aq => as { service \*(Aqschema\*(Aq => $c\->model(\*(AqDBIC\*(Aq) }; \& my $Form = $c\->config\->{FormBuilder}\->create( \& Fields => $c\->config\->{Fields}\->{foo}\->create( \& Model => $Model \& ) \& ); \& \& my $f = $Form\->resolve( \& service => \*(AqForm\*(Aq, \& parameters => { \& name => \*(Aqfoo\*(Aq, \& state => $c\->req\->parameters \& } \& ); \& \& my $result = $f\->validate; \& \& if ($result\->is_valid) { \& # ... \& } \& else { \& # ... \& } \& } .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This example came out of a discussion with Jay Kuri about how Bread::Board might be used in conjunction with his Form::Sensible module. .PP My idea was to create a generic form builder which is parameterized by a Fields container. This could be used to store all kind of application wide behaviors. Since this in the context of Catalyst it made sense to me for this to be stuffed into the Catalyst config hash. I also decided to use service parameters in the Form service, this allows you to pass in a specific name and to optionally pass in a captured state to the Form::Sensible::Form instance that is being created. .PP The next idea was that the Fields container parameter could be created for each specific form in the application. In the above example all the services are hardcoded, but this could be made more re-usable using the \f(CW\*(C`include\*(C'\fR keyword from Bread::Board itself, or some degree of subclassing of the Container objects. .PP Jay also asked about passing in the Catalyst model into the fields so that he could populate something like a select pull-down menu. Again I used parameterized modules, in this case we parameterized the FooFields container with a Model container which had a schema service (which was a DBIx::Class schema object). .PP From here we move into a Catalyst action to show how this might be used. We start out by wrapping the Catalyst \s-1DBIC\s0 model with a simple container, and then proceed to build our \f(CW$Form\fR object. The \f(CW$Form\fR is a Bread::Board container born of 3 levels of parameterized containers, it is worth spending a little time pondering exactly what is happening there. .PP So once we have the \f(CW$Form\fR container, all we need to do is create an instance of our Form::Sensible::Form, passing in the name and the captured state. .PP This example could likely be expanded even further to show the use of the Form::Sensible rendering as well. Further creative use of parameterized containers and a couple utility methods in the Catalyst controllers could produce fairly robust and easy to use \s-1API\s0 for an application. .SH "AUTHOR" .IX Header "AUTHOR" Stevan Little .SH "BUGS" .IX Header "BUGS" Please report any bugs or feature requests on the bugtracker website https://github.com/stevan/BreadBoard/issues .PP When submitting a bug or request, please include a test-file or a patch to an existing test-file that illustrates the bug or desired feature. .SH "COPYRIGHT AND LICENSE" .IX Header "COPYRIGHT AND LICENSE" This software is copyright (c) 2019, 2017, 2016, 2015, 2014, 2013, 2011, 2009 by Infinity Interactive. .PP This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.