Showing posts with label Perl. Show all posts
Showing posts with label Perl. Show all posts

Friday, April 20, 2012

Rendering with blocks in HTML::FormHandler

When rendering, FormHandler loops through the sorted fields in the form and executes the 'render' method on each field. Fields in FormHandler forms, particularly those that interface with a database, are usually structured in a way that matches the data structure. This doesn't always fit with the way that you want to display the form.


'Blocks' provide an alternative way of structuring the display. A 'block' is a fairly basic object that contains a 'render' method. The standard block class, HTML::FormHandler::Widget::Block, has Moose attributes to set the HTML tag, the label, the classes, etc, plus a 'render_list' which contains the names of a list of fields or other blocks to render.


You create a block with 'has_block':

has_block 'comment' => ( tag => 'p', content => 'This is a comment',
        class => ['comment'] );

Blocks can contain lists of fields:


has_block 'fset1' => ( tag => 'fieldset', render_list => ['foo', 'bar'] );

In order to use blocks when rendering instead of fields, you need to provide the form with a 'render_list' too (in addition to any render_lists that might exist in the blocks).


sub build_render_list { ['fset1', 'comment', 'a_field' 'submit_btn' ] }

A complete form that renders using blocks:


package MyApp::Test::Form;
    use HTML::FormHandler::Moose;
    extends 'HTML::FormHandler';

    sub build_render_list {['abc', 'def', 'ghi', 'submit_btn']}
    has_field 'foo';
    has_field 'bar';
    has_field 'flim';
    has_field 'flam';
    has_field 'fee';
    has_field 'fie';
    has_field 'fo';
    has_field 'fum';
    has_field 'submit_btn';
  

    has_block 'abc' => ( tag => 'fieldset', render_list => ['foo', 'fo'] );
    has_block 'def' => ( render_list => ['bar', 'fum'], label => "My DEF Block",
        label_class => ['block', 'label'] );
    has_block 'ghi' => ( render_list => ['flim', 'flam'], wrapper => 0 );



More flexible form rendering in Perl with FormHandler....



Monday, March 8, 2010

HTML::FormHandler result object

Sometime last year I re-structured HTML::FormHandler so that the input and values that are produced by the form validation process are stored in separate result objects. There is an alternate method 'run' (as opposed to the usual 'process' method) to get these objects, or you can get them from a form after 'process'.

I expected that those who were interested in using this would materialize and provide input into what additional facilities/hooks were needed, but as far as I can tell nobody has actually used the feature. I think that it's a fair assumption that nobody actually knows about it, or can't figure out the point.

The standard way to use FormHandler is (simplified) something like:

    my $form = MyApp::Form->new;
    $form->process( params => $params, item => $item, ...);
    if( $form->validated ) {
     ....
    }

When using the the result object, the form acts like a kind of factory, and it looks like this:

    my $form = MyApp::Form->new;
    my $result = $form->run( params => $parsms, item => $item, ... );
    if( $result->validated ) {
       ...
    }

...and all the state is stored in the result objects, ideally leaving none left in the form

Currently result objects refer back to some attributes of the form object for rendering, since a number of rendering related definitions are stored there. It would be possible to decouple that, but then you'd end up having to define the validation and rendering aspects of the fields in two places.

In practice, the separation between static (form definition) information and ephemeral data is not nearly as clearcut as you might think. I find that people often want to change attributes that would probably be initially defined as static based on values that are passed in. It is possible to do this in a clean way, of course. But since the previous results are always cleared out at the beginning of each 'process' call, in practice the difference between using the form with 'process' and using it with 'run' aren't huge.

Nonetheless, I am sure there are people who have good use cases for this alternative architecture, and would love to have people pound on it and use it.

Sunday, February 21, 2010

creating a FormHandler form from a DBIx::Class result source

Someone regularly pops up in #formhandler looking for a way to automatically create a form from a DBIx::Class result source. After explaining how to create a fairly simple role that would do that, the people have always gone away and nothing ever came of it.

I have mixed feelings about the idea, myself. Sure, there's a theoretical benefit to not defining things in multiple places. But in practice, there's almost always differences in selection, presentation, etc, that mean that an automatically derived form is of surprisingly little use. At least in my experience. YMMV. It's awfully easy to take the list of column names and type "has_field 'column';"

But then the eleventeenth person asked about automatic form generation - and the yaks must have been particularly hairy this weekend...because I made a good start at shaving this particular one.

There is now a new trait: HTML::FormHandler::TraitFor::DBICFields, and a package to do the mapping from source info to field definitions: HTML::FormHandler::Model::DBIC::TypeMap. I'm pretty sure that it's not quite right yet, but at least a start has been made, and it should be easier for those that want this kind of functionality to polish, add, and tweak. For one thing, it doesn't handle relationships yet. FormHandler can create form fields out of a lot of the standard DBIx::Class relationships, yet it is often not what you would want to have happen automatically. So I think skipping relationships as a default is probably OK.

Anyway, here is how to create a form by looking at the source columns:

   my $book = $schema->resultset('Book')->find(1);
   my $form = HTML::FormHandler::Model::DBIC->new_with_traits( 
      traits => ['HTML::FormHandler::TraitFor::DBICFields'],
      field_list => [ 'submit' => 
          { type => 'Submit', value => 'Save', order => 99 } ],
      item => $book );

The field_list attribute is because I thought it was better to explicitly specify the submit field, rather than automatically create it. I could be argued out of it...

The interface is only a few hours old, so if you have thoughts about how this should work, this is the time to speak up, before somebody starts using it and it becomes harder to change. :-)

Speaking of dynamic forms... HTML::FormHandler is known for it's Moose-y sugar interface, but there are other ways to create a FormHandler form. Using a 'field_list' as a parameter to 'new' works fine to create a dynamic form (though there are things that are possible inside a class that just can't be done with that kind of interface):

my @select_options = ( {value => 1, label => 'One'}, 
       {value => 2, label => 'Two'}, {value => 3, label => 'Three'} );
my $args =  {
    name       => 'test',
    field_list => [
        'username' => {
            type  => 'Text',
            apply => [ { check => qr/^[0-9a-z]*/, message => 
                   'Contains invalid characters' } ],
        },
        'password' => {
            type => 'Password',
        },
        'a_number' => {
            type      => 'IntRange',
            range_min => 12,
            range_max => 291,
        },
        'a_select' => {
            type    => 'Select',
            options => \@select_options,
        },
        'sub' => {
            type => 'Compound',
        },
        'sub.user' => {
            type  => 'Text',
            apply => [ { check => qr/^[0-9a-z]*/, 
               message => 'Not a valid user' } ],
        },
        'sub.name' => {
            type  => 'Text',
            apply => [ { check => qr/^[0-9a-z]*/, 
                message => 'Not a valid name' } ],
        },
        'submit' => {
            type => 'Submit',
        },
    ]
};
my $form = HTML::FormHandler->new( %$args );

And of course you can use one of the rendering roles, HTML::FormHandler::Render::Simple, or the rendering widgets, or write your own renderer... Too Many Ways To Do Things (tm).

Tuesday, June 16, 2009

Where the cleaver falls...

Way back in the dark ages, I worked on one of the first projects at IBM to use that fancy new methodology, object oriented programming. They sent the whole team to a month of OO training, and then that wasn't quite enough to bring us up to speed, so they sent us to another month with a different traning company. I remember that one month used a well-regarded (at that time) book by Grady Booch. The whole object thing wasn't that hard to understand, but the thing that I couldn't quite wrap my mind around was how you figured out what to make the objects, how to split up the problem domain into pieces. So I eagerly flipped through the Booch book, thinking that they must have some words of wisdom on this point, and finally I found it. Buried somewhere in the middle they had one page with three paragraphs which basically said: and then a miracle occurs.

Pretty much the equivalent of the humorous saying somebody I know was fond of: Where the cleaver falls, there the chicken parts. (Maybe you had to be there...)

So I was working on a comment screen that needed a captcha. I had never used one before, but I figured it couldn't be that hard. HTML::FormHandler is a form processor, and a captcha is a form element, so it seemed obvious that a captcha field for HFH was in order. That part was easy... And then I realized that in order to check the value typed in by the user, the captcha had to be stored in the session. The session (in this case) is managed by a Catalyst plugin, and for the form field to be aware of the session just seems wrong. Too much mixing of areas of concern.

So a Moose role comes to the rescue. (Perl!) I created a Moose role that contained the captcha field, plus provided 'get_captcha' and 'set_captcha' methods. This seems relatively clean - or at least better than having the field mess with the session. Of course in order to access the session, the Catalyst context or session needs to be passed in to the form object. Not ideal, but not all that bad either. But now these methods are form methods... They could be turned into callbacks, or coderefs that are set on the field, but I've already had to deal with not-entirely-clean relationships between form and field before, so for now I decide to just call them as form methods. I don't really like this, because I'd prefer that the fields not know about the object that contains them, but it's easy and it works.

Then I realize that I'll need a URL for the image in the field. Damn. This is getting messy. I suppose that I can add yet another attribute 'captcha_url' and set THAT too. But then there's another required piece of code that's neither form nor field, but a controller action. Sigh. It's too many different pieces of code for one simple thing.

Oject oriented programming is no longer the new, shiny thing that it was so long ago, but the problem of splitting up the problem into nice little pieces is still with us. That OO training was for was an early attempt at an object oriented interface to a SQL database. It failed utterly. Looking back, I have to say that the problem wasn't fully understood - or at least we didn't understand it. It was a brave attempt, but a fair amount of knowledge about the problems associated with doing ORMs has grown up, and they're better these days.

So I guess progress is being made. In some places by some people..

Friday, June 5, 2009

Flexible extensions with Moose method modifiers

When constructing an API for a library intended to be subclassed by users, you run into the classic tension between power and simplicity. Too many ways to call your code, too many different methods and the user is overwhelmed. Yet if you don't have enough power, the user may by stymied when he reaches some level of complexity.

Moose method modifiers provide a lot of flexibility that doesn't necessarily have to be provided by an explicit API. In some cases they may provide stopgap ways of extending, in other cases they may actually be better than creating more complexity by providing more explicit hooks.

The main processing method for HTML::FormHandler is pretty straightforward:
sub process
{
   my $self = shift;

   $self->clear if $self->processed;
   $self->_setup_form(@_);
   $self->validate_form if $self->has_params;
   $self->update_model if $self->validated;
   $self->processed(1);
   return $self->validated;
}
The above method is called when a form is processed:
   my $form = MyApp::Form::User->new;
   $form->process( item => $user, params => $c->req->params );
The form is something like:
   package MyApp::Form::User;
   use HTML::FormHandler::Moose;
   extends 'HTML::FormHandler::Model::DBIC';

   has_field 'username' ( required => 1 );
   has_field 'some_attr';
A common need is to have particular fields be required in some circumstances and not in others. So maybe it would be nice to have some kind of callback to determine whether the field is required or not... But a simple Moose method modifier on one of the methods called in the 'process' routine will do the trick just fine:
   before 'validate_form' => sub {
      my $self = shift;
      $self->field('some_attr')->required(1)
         if( ...some condition... );
   };
Now maybe there's some magical API syntax that could achieve the same thing, but really this is pretty straightforward and easy. Maybe there's some additional database update that you want to do that's not directly related to the fields, such as recording that the user updated his record. Another Moose method modifier comes to the rescue:
   before 'update_model' => sub {
      shift->item->user_updated;
   };
...where 'user_updated' is a method on your DBIx::Class result source that sets a flag or an updated time or whatever you want. The same result could be achieved by subclassing the methods of course, but the method modifiers can also be used in Moose roles, making it possible to split up your form pieces into nice chunks that can be reused in multiple forms.
   package MyApp::Form::Options;
   use HTML::FormHandler::Moose::Role;

   has_field 'opt_in';
   has_field 'something_else';
   after 'validate' => sub {
      ...do some specific cross validation...
   };
   before 'update_model' => sub {
      ...some db processing...
   };
And then a form class could just be a collection of roles:
   package MyApp::Form::User;
   use HTML::FormHandler::Moose;
   extends 'HTML::FormHandler::Model::DBIC';
   with 'MyApp::Form::Options';
   with 'MyApp::Form::Login';
   1;
So the power and flexibility of HTML::FormHandler's API are increased without extra code simply by using Moose and its method modifiers. When I was originally hired to program in Perl I wasn't that happy about it, partly because the native Perl OO features are weak and kludgy. But with Moose that's a thing of the past. Perl + Moose are as good as or better than any other object oriented language I've worked with.

Wednesday, May 27, 2009

Validating structured data

In an earlier post I discussed how HTML form processing, when sufficiently generalized, leads to processing structured data (by which I mean data in Perl-ish hashes and lists). Here is an example of some structured data:
my $user_record = {
   username => 'Joe Blow',
   occupation => 'Programmer',
   tags => ['Perl', 'programming', 'Moose' ],
   employer => {
      name => 'TechTronix',
      country => 'Utopia',
   },
   options => {
      flags => {
         opt_in => 1,
         email => 0,
      },
      cc_cards => [
         {
            type => 'Visa',
            number => '4248999900001010',
         },
         {
            type => 'MasterCard',
            number => '4335992034971010',
         },
      ],
   },
   addresses => [
      {
         street => 'First Street',
         city => 'Prime City',
         country => 'Utopia',
         id => 0,
      },
      {
         street => 'Second Street',
         city => 'Secondary City',
         country => 'Graustark',
         id => 1,
      },
      {
         street => 'Third Street',
         city => 'Tertiary City',
         country => 'Atlantis',
         id => 2,
      }
   ]
};

Here is the HTML::FormHandler form that defines field validators to process that structure:
{
   package Structured::Form;
   use HTML::FormHandler::Moose;
   extends 'HTML::FormHandler';

   has_field 'username';
   has_field 'occupation';
   has_field 'tags' => ( type => 'Repeatable' );
   has_field 'tags.contains' => ( type => 'Text' );
   has_field 'employer' => ( type => 'Compound' );
   has_field 'employer.name';
   has_field 'employer.country';
   has_field 'options' => ( type => 'Compound' );
   has_field 'options.flags' => ( type => 'Compound' );
   has_field 'options.flags.opt_in' => ( type => 'Boolean' );
   has_field 'options.flags.email' => ( type => 'Boolean' );
   has_field 'options.cc_cards' => ( type => 'Repeatable' );
   has_field 'options.cc_cards.type';
   has_field 'options.cc_cards.number';
   has_field 'addresses' => ( type => 'Repeatable' );
   has_field 'addresses.street';
   has_field 'addresses.city';
   has_field 'addresses.country';
   has_field 'addresses.id';

}

The names of the fields are flattened references to the elements of the structure, with special field types for Repeatable and Compound elements. These types of structures can be used to update a database with DBIx::Class (although there are limits, of course).

I've left off the actual validators, but they can be defined pretty easily using Moose types or other constraints.
  has_field 'cc_type' => ( apply => [ CCType ] );
It would probably be better to define some of the fields in a role or field, to keep some of the related validation in the same place. The validation of the credit card numbers depend on the type of the credit card, for example. Error messages can be retrieved from an array of error fields or plain error messages, but there need to be more flexible ways of getting those messages. I'm not exactly sure what people will want yet.

Real Soon Now (tm) I'm going to work on a KiokuDB model... So many programming tasks, so little time.

Tuesday, May 19, 2009

Complexity happens

I've heard a programmer's job described as 'managing complexity'. People who like programming tend to like other complex systems, like, say D&D. (They also like fantasy in general... no doubt there's some clever comment there that my cold-fogged brain can't work out.)

And yet, one of the primary goals in a programming project is to keep it simple. (Otherwise known as KISS.) So there's this continual tension between simplicity and complexity. Simplicity in one area may require complexity in another. Creating a simple, easy-to-use API often requires more underlying complexity than a non-intuitive but straightforward interface. Though there are occasionally golden moments when things fall into place and you can achieve both greater simplicity of interface AND greater code simplicity. Just don't hold your breath waiting for them...

Problems that seem simple to start with acquire complexity when you add features, when you handle more use cases. Simple, stupid things like the fact that you don't get anything in CGI parameters for an un-checked checkbox introduce irregularities that flow through to surprising corners of code. Decisions made about what it means to not have a particular parameter or have it set to empty cascade through formerly pristine and clean lines of code.

I'm not quite sure whether this is a complaint or simply a report. Sometimes the logical complexity is fascinating. You poke something to see what happens; you try some new way of factoring to see if that magical moment of greater order occurs... And then sometimes you can hardly stay awake and certainly can't concentrate, and you find yourself surfing Amazon for some new fantasy novel that's a lot more your speed.

Or desperately trying to think of something to write that's somehow remotely related to Perl programming. Because you foolishly committed to DOING THAT in a moment of insanity.

Let me just repeat that key phrase a couple of more times, in case foolish sites that count dumb things and claim they mean something aren't paying attention: Perl programming Perl programming Perl programming

Thanks. I'm done blathering now. I think I've got enough of a word count.

Monday, May 4, 2009

Moose beginners: clear, predicate, and triggers

One of the nice things about Moose is that it adds another state for your instance variables -- whether or not the variable is actually set. With standard Perl variables you can check whether the variable is defined or undefined and true or false. In Moose the state of being undefined is different from the state of being set. In order to take advantage of this additional state you need to use the 'clearer' and 'predicate' methods for your attribute:
   has 'my_var' => ( isa => 'Str|Undef', is => 'rw', 
          clearer => 'clear_my_var',
          predicate => 'has_my_var' );
Setting 'my_var' to 'undef' is different than doing 'clear_my_var'. If you set it to undefined:
   $my_obj->my_var(undef);
then the predicate 'has_my_var' will return true. If you check for truth in the usual way:
   if( $my_obj->my_var ) { ... }
false will be returned for both the case where the attribute has been set to undefined and has been cleared. So you have to to use the predicate method:
   if( $my_obj->has_my_var ) { ... }
The predicate method will return true if 'my_var' has been set to undefined, and false if 'my_var' has been cleared.
An important piece of related behavior is that a trigger on an attribute is called when you set it, whether or not you are setting it to undefined, but the trigger is not called when you do a clear. So if you have an object in which only one of two variables should have a value, you can create triggers for both of them and use clear to un-set the other variable.
   has 'my_var' => ( isa => 'Str', is => 'rw',
           clearer => 'clear_my_var',
           predicate => 'has_my_var',
           trigger => sub { shift->clear_my_other_var }
   );
   has 'my_other_var' => ( isa => 'Str', is => 'rw',
           clearer => 'clear_my_other_var,
           predicate => 'has_my_other_var',
           trigger => sub { shift->clear_my_var }
   );
If you tried to set 'my_var' to undef in the trigger, you would end up in an infinite recursion, since each attempt to set the other variable would cause the trigger in that variable to fire. Another issue is whether or not you should allow a particular attribute to be set to undefined. Some attributes may need an explicit undefined state, in which case you must set your isa to 'Str|Undef', but if you don't actually need an undefined state then you are better off not allowing it and using a predicate, in which case you must clear the variable to un-set it since setting it to undef will fail.

Tuesday, July 15, 2008

Moose is fun

I've been converting an old, badly designed set of Perl classes to Moose, and it's actually been fun. I split the old classes up into a number of sub-objects, but was able to maintain the silly old interface with "handles", forwarding the calls to the appropriate class.

If you work with Perl and haven't tried Moose yet, you're missing something. The current three classes are 67 pages of printed Perl. I estimate that I'll end up with maybe 6 or 7 classes and probably no more than 20 pages.