Data::Manager is a really fantastic marriage of two very well thought out and uncoupled modules, Data::Verifier and Message::Stack. Data::Verifier does exactly what its name says, which is verifies data. You give it a hashref of constraints to verify against, and call ->validate on your data that you've passed in, and boom, data is verified with errors and filters. Messages::Stack is again, another very aptly named module. It gives you a programmatic interface to creating a stack of messages with a syslog flavor to them with regards to message level, scope, id, etc. You can then, after creating a stack of messages, retrieve messages matching a scope, or a block of messages pertaining to a certain attribute of your data, search through the messages and grab the ones that match your search criteria, or get all of the messages.
So with that, I'm going to show you how Data::Manager allows you to use both of these modules to validate your data and create coherent messages in a manageable and scalable fashion. For level playing field reasons, I'm going to be demonstrating with a Catalyst application I recently used these methods in.
I have set up an API controller to handle the CRUD interface to this application. Data::Manager provided a perfect single source for data verification (beyond various form validation in front facing portions of the site) and message building for results. Basically, the controller looks like this:
package Denzel::Controller::Users;
use Moose;
use namespace::autoclean;
BEGIN { extends 'Catalyst::Controller' }
use URI;
use Try::Tiny;
use Form::Sensible::Reflector::DBIC;
use Carp;
use Data::Dumper;
use DateTime;
## CLUE stuff
sub clue_base : Chained('/') PathPart('user') CaptureArgs(1) {
my ( $self, $c, $userid ) = @_;
$c->stash( userid => $userid );
}
sub cl_base : Chained('/') PathPart('users') CaptureArgs(0) {
my ( $self, $c ) = @_;
}
sub create_user : Chained('cl_base') PathPart('new') Args(0) {
my ( $self, $c ) = @_;
my $reflector = Form::Sensible::Reflector::DBIC->create_form(
{
handle => $c->model('Database')->schema,
form => { name => "user" }
}
);
$reflector->field('role')->value('member');
$reflector->field('created_on')->value( DateTime->now );
my $output;
$reflector->add_field(
{
name => 'captcha',
field_class => 'Text',
value => $c->captcha_string
}
);
$reflector->add_field( { name => 'Join', field_class => 'Trigger' } );
my $renderer = Form::Sensible->get_renderer('HTML');
if ( $c->req->param('Join') ) {
$c->forward(qw/ Controller::API create_user /);
$c->log->debug("Messages inside Users: " . Dumper $c->stash->{'messages'});
if ( @{ $c->error } ) {
$c->stash( errors => @{ $c->error } );
$c->detach;
}
$c->stash( message => "Added successfully!");
}
$output = $renderer->render($reflector)->complete( '/users/new', 'POST' );
$c->stash( form => $output );
}
Boom. forward to the API controller if the form is valid, go on with ya bad self.
The final piece of this is the template. I use Template::Toolkit because it's awesome and less hateful than the rest of the templating systems. This took a bit of thought, so here's what I came up with:
<div id="messages">
<h2>
[% message %]
</h2>
<h2>
[% error %]
</h2>
<ul>
[% IF messages.has_messages %]
<h2>Form Errors: </h2>
<ul>
[% SET i = messages.count - 1 %]
[% WHILE i >= 0 %]
<li>
[% messages.get_message(i).subject %]
</li>
<li>
[% messages.get_message(i).id.replace('_', ' ') %]
[% i = i - 1 %]
[% END %]
[% END %]
</ul>
</div>
And just for good measure, the create user template:
[% IF errors %]
<div>[% errors %]</div>
[% END %]
[% IF success %]
<div>Thanks for joining! Check your email for your confirmation link.</div>
<div><a href="[% c.uri_for_action('/users/clue/view_privileged_profile', user.userid) %]">click here to edit your profile</a>
[% END %]
[% UNLESS c.req.param('join') %]
<h2>Join Denzelfuckingwashington.com</h2>
[% form %]
<div><img src="[% c.uri_for("/captcha")%]" /></div>
[% END %]
Bingo bango done. Rock solid. And yes, this is also a pitch for denzelfuckingwashington.com :-)




Leave a comment
All comments are moderated. Spammers don't waste your time