[Catalyst] Exceptions and templates and stuff.

Caroline Johnston johnston at biochemistry.ucl.ac.uk
Wed Nov 30 21:05:00 CET 2005


Hi,

I've been playing with having my own error templates rather than the
default ones. I've got it set up so that I can throw exceptions I've
defined which know about their own templates. It seems to work, but I've
never used Exception::Class before and I've not entirely got the hang of
Catalyst yet, so can someone have a look and tell me if I'm doing
something really daft?

Cheers,

Cass.

----

1. In MyApp::end

    if (my $e = ${$c->error}[-1]){
	 unless ($e->isa('MyApp::Exception')){
	     $e = new MyApp::Exception($c, "$e");
	 }
	 $c->stash->{template} = $e->template;
	 $c->stash->{err} = $e;
     }
     $c->error(0);
     $c->forward('MyApp::V::TT') unless $c->res->output;


2. In a controller somewhere:

 throw WebR::Exception($c, "I'm an unhelpful error message");

or,

 throw WebR::Exception::DFV($c) unless $c->form->success();


3. My base Exception class is just an extension of Exception::Class::Base:

package MyApp::Exception;
use Exception::Class;
use base qw/Exception::Class::Base Class::Accessor::Fast
Class::Data::Inheritable/;
use Clone qw(clone);
use Data::Dumper;
use HTML::Entities;

__PACKAGE__->mk_classdata('template' );
__PACKAGE__->mk_classdata('debug_template');
__PACKAGE__->mk_accessors(qw/c res req stash/);

#set default templates
__PACKAGE__->template('error/error_basic.tt');
__PACKAGE__->debug_template('error/error_debug.tt');

#grab your context
sub _initialize{
    my $self = shift;
    $self->c(shift);
    die "can't raise a MyApp::Exception without a catalyst context."
	unless $self->c->isa('Catalyst::Base');
    $self->SUPER::_initialize(@_);
}

#additional methods for debug template (mostly nicked from
finalize_errors)
sub req {
    my $self = shift;
    my $req = clone($self->c->req);
    delete $req->{_context};
    delete $req->{_body};
    local $Data::Dumper::Terse = 1;
    return encode_entities(Dumper($req));
}

sub res {
 my $self = shift;
 my $res = clone($self->c->res);
 delete $res->{_context};
 delete $res->{_finalized_headers};
 local $Data::Dumper::Terse = 1;
 return encode_entities(Dumper($res));
}

sub stash {
 my $self = shift;
 my $stash = $self->c->stash;
 local $Data::Dumper::Terse = 1;
 return encode_entities(Dumper($stash));
}

1;

and MyApp::Exception::DFV just changes the template:

package MyApp::Exception::DFV;
use base qw/MyApp::Exception/;

__PACKAGE__->template('error/dfv_error.tt');
1;


And then in my templates:
#error/error.tt
  [%INCLUDE error/error_basic.tt%]
  [%IF c.debug %]
   [%INCLUDE error/error_debug.tt%]
  [%END%]

error_basic.tt
<h1>Error!</h1>
[%IF err.message%]
  <p class="warning"> [%err.message%] </p>
[%END%]

error_debug.tt (assuming css and js for the dropdown)
<h3>Response <a href="#" onclick="return dropdown('res');"> +/- </a></h3>
<pre id='res'>[% err.res %]</pre>
<h3>Request<a href="#" onclick="return dropdown('req');"> +/- </a></h3>
<pre id='req'>[% err.req %]</pre>
<h3>Stash<a href="#" onclick="return dropdown('stash');"> +/- </a></h3>
<pre id='stash'>[% err.stash %]</pre>

error_dfv.tt
 <h3 class="warning">There was a problem with your form:</h3>
 [% FOREACH thing IN c.form.msgs %]
 <b class="warning">[% thing.key %]:</b> [% thing.value %]  <br/>
 [% END %]
 <p/>















More information about the Catalyst mailing list