From: Alexander Hartmaier Date: Fri, 19 Oct 2007 21:42:40 +0000 (+0000) Subject: refactor of the API and mainly Catalyst::View::Email::Template X-Git-Tag: v0.14~22 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=06afcdbcc06c0507c57be48db69fa81d3b835577;p=catagits%2FCatalyst-View-Email.git refactor of the API and mainly Catalyst::View::Email::Template --- diff --git a/Changes b/Changes index f5734d8..812e6a8 100644 --- a/Changes +++ b/Changes @@ -1,5 +1,7 @@ Revision history for Perl extension Catalyst::View::Email. +0.07 - refactored by Alexander Hartmaier with slight api changes + 0.06 - Fixing some slight issues with configuration not being handled appropriately (thanks dwc and mst) diff --git a/lib/Catalyst/View/Email.pm b/lib/Catalyst/View/Email.pm index 4af0484..8b4ea33 100644 --- a/lib/Catalyst/View/Email.pm +++ b/lib/Catalyst/View/Email.pm @@ -11,9 +11,10 @@ use Email::MIME::Creator; use base qw|Catalyst::View|; -our $VERSION = '0.08'; +our $VERSION = '0.07'; -__PACKAGE__->mk_accessors(qw(sender stash_key content_type mailer)); +#__PACKAGE__->mk_accessors(qw(sender stash_key content_type mailer)); +__PACKAGE__->mk_accessors(qw(stash_key content_type mailer)); =head1 NAME @@ -32,7 +33,7 @@ In your app configuration (example in L): stash_key: email content_type: text/plain sender: - method: SMTP + mailer: SMTP # mailer_args is passed directly into Email::Send mailer_args: Host: smtp.example.com # defaults to localhost @@ -48,7 +49,10 @@ somewhere and not be delivered. =cut __PACKAGE__->config( - stash_key => 'email', + stash_key => 'email', + default => { + content_type => 'text/html', + }, ); =head1 SENDING EMAIL @@ -108,7 +112,8 @@ have L for use. You can also toggle this as being used by setting up your configuration to look like this: View::Email: - default_view: TT + default: + view: TT Then, Catalyst::View::Email will forward to your View::TT by default. @@ -119,31 +124,31 @@ sub new { my ( $c, $arguments ) = @_; - my $mailer = Email::Send->new; + my $sender = Email::Send->new; - if ( my $method = $self->sender->{method} ) { - croak "$method is not supported, see Email::Send" - unless $mailer->mailer_available($method); - $mailer->mailer($method); + if ( my $mailer = $self->{sender}->{mailer} ) { + croak "$mailer is not supported, see Email::Send" + unless $sender->mailer_available($mailer); + $sender->mailer($mailer); } else { # Default case, run through the most likely options first. for ( qw/SMTP Sendmail Qmail/ ) { - $mailer->mailer($_) and last if $mailer->mailer_available($_); + $sender->mailer($_) and last if $sender->mailer_available($_); } } - if ( my $args = $self->sender->{mailer_args} ) { + if ( my $args = $self->{sender}->{mailer_args} ) { if ( ref $args eq 'HASH' ) { - $mailer->mailer_args([ %$args ]); + $sender->mailer_args([ %$args ]); } elsif ( ref $args eq 'ARRAY' ) { - $mailer->mailer_args($args); + $sender->mailer_args($args); } else { croak "Invalid mailer_args specified, check pod for Email::Send!"; } } - $self->mailer($mailer); + $self->mailer($sender); return $self; } diff --git a/lib/Catalyst/View/Email/Template.pm b/lib/Catalyst/View/Email/Template.pm index e213a10..2d58c38 100644 --- a/lib/Catalyst/View/Email/Template.pm +++ b/lib/Catalyst/View/Email/Template.pm @@ -5,14 +5,13 @@ use strict; use Class::C3; use Carp; +use Scalar::Util qw( blessed ); use Email::MIME::Creator; use base qw|Catalyst::View::Email|; -our $VERSION = '0.08'; - -__PACKAGE__->mk_accessors( qw(default_view template_prefix) ); +our $VERSION = '0.07'; =head1 NAME @@ -23,53 +22,65 @@ Catalyst::View::Email::Template - Send Templated Email from Catalyst Sends Templated mail, based upon your Default View. Will capture the output of the rendering path, slurps in based on mime-types and assembles a multi-part email and sends it out. +It uses Email::MIME to create the mail. =head2 CONFIGURATION View::Email::Template: - # Set it up so if you have multiple parts, they're alternatives. - # This is on the top-level message, not the individual parts. - content_type: multipart/alternative # Optional prefix to look somewhere under the existing configured - # template paths. + # template paths. Default is none. template_prefix: email - # Where to look in the stash for the email information + # Where to look in the stash for the email information. + # 'email' is the default, so you don't have to specify it. stash_key: email + # Define the defaults for the mail + default: + # Defines the default content type (mime type) for every template. + content_type: text/html + # Defines the default charset for every MIME part with the content + # type 'text'. + # According to RFC2049 such a MIME part without a charset should + # be treated as US-ASCII by the mail client. + # If the charset is not set it won't be set for all MIME parts + # without an overridden one. + charset: utf-8 + # Defines the default view which is used to render the templates. + view: TT # Setup how to send the email + # all those options are passed directly to Email::Send sender: - method: SMTP - host: smtp.myhost.com - username: username - password: password + mailer: SMTP + mailer_args: + Host: smtp.example.com # defaults to localhost + username: username + password: password =head1 SENDING EMAIL -Sending email is just setting up your stash key, and forwarding to the view. +Sending email is just setting up your defaults, the stash key and forwarding to the view. $c->stash->{email} = { to => 'jshirley@gmail.com', from => 'no-reply@foobar.com', subject => 'I am a Catalyst generated email', - # Specify which templates to include - templates => [ - qw{text_plain/test.tt}, - qw{text_html/test.tt} - ] + template => 'test.tt', }; $c->forward('View::Email::Template'); -Alternatively if you want more control over your templates you can use the following idiom :- +Alternatively if you want more control over your templates you can use the following idiom +to override the defaults: templates => [ - { view => 'TT', - template => 'email/test.html.tt', - content_type => 'text/html' - }, - { view => 'TT', - template => 'email/test.plain.tt', - content_type => 'text/plain' - } - + { + template => 'email/test.html.tt', + content_type => 'text/html', + view => 'TT', + }, + { + template => 'email/test.plain.mason', + content_type => 'text/plain', + view => 'Mason', + } ] @@ -77,6 +88,9 @@ If it fails $c->error will have the error message. =cut +# here the defaults of Catalyst::View::Email are extended by the additional +# ones Template.pm needs. + __PACKAGE__->config( template_prefix => '', ); @@ -94,97 +108,110 @@ __PACKAGE__->config( # into an Email::MIME container. The mime-type will be stupidly guessed with # the subdir on the template. # -# TODO: Make this unretarded. -# -sub process { - my ( $self, $c ) = @_; - my $stash_key = $self->stash_key || 'email'; +# Set it up so if you have multiple parts, they're alternatives. +# This is on the top-level message, not the individual parts. +#multipart/alternative - croak "No template specified for rendering" - unless $c->stash->{$stash_key}->{template} or - $c->stash->{$stash_key}->{templates}; - # Where to look - my $template_prefix = $self->template_prefix; - my @templates = (); - - if ( $c->stash->{$stash_key}->{templates} && !ref $c->stash->{$stash_key}->{templates}[0]) { - push @templates, map { - join('/', $template_prefix, $_); - } @{$c->stash->{$stash_key}->{templates}}; - - } elsif($c->stash->{$stash_key}->{template}) { - push @templates, join('/', $template_prefix, - $c->stash->{$stash_key}->{template}); - } - - my $default_view = $c->view( $self->default_view ); +sub _validate_view { + my ($self, $view) = @_; + + croak "Email::Template's configured view '$view' isn't an object!" + unless (blessed($view)); + + croak "Email::Template's configured view '$view' isn't an Catalyst::View!" + unless ($view->isa('Catalyst::View')); + + croak "Email::Template's configured view '$view' doesn't have a render method!" + unless ($view->can('render')); +} - unless ( $default_view->can('render') ) { - croak "Email::Template's configured view does not have a render method!"; +sub _generate_part { + my ($self, $c, $attrs) = @_; + + my $template_prefix = $self->{template_prefix}; + my $default_view = $self->{default}->{view}; + my $default_content_type = $self->{default}->{content_type}; + + my $view = $c->view($attrs->{view} || $default_view); + # validate the per template view + $self->_validate_view($view); +# $c->log->debug("VIEW: $view"); + + # prefix with template_prefix if configured + my $template = $template_prefix ne '' ? join('/', $template_prefix, $attrs->{template}) : $attrs->{template}; + + my $content_type = $attrs->{content_type} || $default_content_type; + + # render the email part + my $output = $view->render( $c, $template, { + content_type => "$content_type", + stash_key => $self->stash_key, + %{$c->stash}, + }); + + if (ref $output) { + croak $output->can('as_string') ? $output->as_string : $output; } + + return Email::MIME->create( + attributes => { + content_type => "$content_type", + }, + body => $output, + ); +} - #$c->log->_dump($default_view->config); +sub process { + my ( $self, $c ) = @_; - my @parts = (); - foreach my $template ( @templates ) { - $template =~ s#^/+##; # Make sure that we don't have an absolute path. - # This seems really stupid to me... argh. will give me nightmares! - my $template_path = $template; - $template_path =~ s#^$template_prefix/##; - my ( $content_type, $extra ) = split('/', $template_path); - if ( $extra ) { - $content_type ||= 'text/plain'; - $content_type =~ s#_#/#; - } else { - $content_type = 'text/plain'; - } + # validate here so _generate_part doesn't have to do it for every part + my $stash_key = $self->{stash_key}; + croak "Email::Template's stash_key isn't defined!" + if ($stash_key eq ''); + + # don't validate template_prefix - my $output = $default_view->render( $c, $template, { - content_type => $content_type, - stash_key => $self->stash_key, - %{$c->stash}, - }); + # the default view is validated on use later anyways... + # but just to be sure even if not used +# $self->_validate_view($c->view($self->{default}->{view})); - # Got a ref, not a scalar. An error! - if ( ref $output ) { - croak $output->can("as_string") ? $output->as_string : $output; - } - push @parts, Email::MIME->create( - attributes => { - content_type => $content_type - }, - body => $output - ); - } +# $c->log->debug("SELF: $self"); +# $c->log->debug('DEFAULT VIEW: ' . $self->{default}->{view}); - #add user parts :- - if ( $c->stash->{$stash_key}->{'templates'} && ref $c->stash->{$stash_key}->{templates}[0] ) { - foreach my $part (@{$c->stash->{$stash_key}->{'templates'}}) { - my $view = $c->view($part->{'view'} || $self->config->{default_view}); + # the content type should be validated by Email::MIME::Creator - my $content_type = $part->{'content_type'} || 'text/plain'; - unless ( $view->can('render') ) { - croak "Part does not have valid render view"; - } + croak "No template specified for rendering" + unless $c->stash->{$stash_key}->{template} + or $c->stash->{$stash_key}->{templates}; + + # this array holds the Email::MIME objects + # in case of the simple api only one + my @parts = (); - my $output = $view->render( $c, $part->{'template'}, { - 'content_type' => $content_type, - %{$c->stash} }); - - if ( ref $output ) { - croak $output->can("as_string") ? $output->as_string : $output; - } - - push @parts, Email::MIME->create( - attributes => { - content_type => $content_type - }, - body => $output - ); - } + # now find out if the single or multipart api was used + # prefer the multipart one + + # multipart api + if ($c->stash->{$stash_key}->{templates} + && ref $c->stash->{$stash_key}->{templates} eq 'ARRAY' + && ref $c->stash->{$stash_key}->{templates}[0] eq 'HASH') { + # loop through all parts of the mail + foreach my $part (@{$c->stash->{$stash_key}->{templates}}) { + push @parts, $self->_generate_part($c, { + view => $part->{view}, + template => $part->{template}, + content_type => $part->{content_type}, + }); } - + } + # single part api + elsif($c->stash->{$stash_key}->{template}) { + push @parts, $self->_generate_part($c, { + template => $c->stash->{$stash_key}->{template}, + }); + } + delete $c->stash->{$stash_key}->{body}; $c->stash->{$stash_key}->{parts} ||= []; push @{$c->stash->{$stash_key}->{parts}}, @parts; @@ -224,6 +251,8 @@ J. Shirley Simon Elliott +Alexander Hartmaier + =head1 LICENSE This library is free software, you can redistribute it and/or modify it under @@ -232,4 +261,3 @@ the same terms as Perl itself. =cut 1; - diff --git a/t/07mason.t b/t/07mason.t index afa9190..3bfeae3 100644 --- a/t/07mason.t +++ b/t/07mason.t @@ -15,7 +15,7 @@ plan tests => 10; use_ok('Catalyst::Test', 'TestApp'); -TestApp->config->{default_view} = 'mason'; +TestApp->config->{default}->{view} = 'mason'; my $response; my $time = time; diff --git a/t/lib/TestApp.pm b/t/lib/TestApp.pm index 3789de3..8443301 100644 --- a/t/lib/TestApp.pm +++ b/t/lib/TestApp.pm @@ -6,16 +6,18 @@ use FindBin; TestApp->config( root => "$FindBin::Bin/root", - default_view => 'TT', 'View::Email::AppConfig' => { sender => { - method => 'Test', + mailer => 'Test', }, }, 'View::Email::Template::AppConfig' => { stash_key => 'template_email', sender => { - method => 'Test', + mailer => 'Test', + }, + default => { + view => 'TT', }, }, ); diff --git a/t/lib/TestApp/Controller/Root.pm b/t/lib/TestApp/Controller/Root.pm index d96fc22..6cabe66 100644 --- a/t/lib/TestApp/Controller/Root.pm +++ b/t/lib/TestApp/Controller/Root.pm @@ -62,11 +62,19 @@ sub template_email : Global('template_email') { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', - content_type => 'multipart/alternative', +# content_type => 'multipart/alternative', templates => [ - qw{text_plain/test.tt}, - qw{text_html/test.tt} - ] + { + view => 'TT', + template => 'text_plain/test.tt', + content_type => 'text/plain', + }, + { + view => 'TT', + template => 'text_html/test.tt', + content_type => 'text/html', + }, + ], }; $c->forward('TestApp::View::Email::Template'); @@ -88,11 +96,17 @@ sub template_email_app_config : Global('template_email_app_config') { to => 'test-email@example.com', from => 'no-reply@example.com', subject => 'Just a test', - content_type => 'multipart/alternative', +# content_type => 'multipart/alternative', templates => [ - qw{text_plain/test.tt}, - qw{text_html/test.tt} - ] + { + template => 'text_plain/test.tt', + content_type => 'text/plain', + }, + { + template => 'text_html/test.tt', + content_type => 'text/html', + }, + ], }; $c->forward('TestApp::View::Email::Template::AppConfig'); @@ -116,9 +130,15 @@ sub mason_email : Global('mason_email') { subject => 'Just a test', content_type => 'multipart/alternative', templates => [ - qw{text_plain/test.m}, - qw{text_html/test.m} - ] + { + template => 'text_plain/test.tt', + content_type => 'text/plain', + }, + { + template => 'text_html/test.tt', + content_type => 'text/html', + }, + ], }; $c->forward('TestApp::View::Email::Template'); diff --git a/t/lib/TestApp/View/Email.pm b/t/lib/TestApp/View/Email.pm index dc737a3..d3ca6f8 100644 --- a/t/lib/TestApp/View/Email.pm +++ b/t/lib/TestApp/View/Email.pm @@ -7,7 +7,7 @@ use base 'Catalyst::View::Email'; __PACKAGE__->config( sender => { - method => 'Test' + mailer => 'Test' }, ); diff --git a/t/lib/TestApp/View/Email/Template.pm b/t/lib/TestApp/View/Email/Template.pm index e7d6ee2..a594d07 100644 --- a/t/lib/TestApp/View/Email/Template.pm +++ b/t/lib/TestApp/View/Email/Template.pm @@ -6,7 +6,7 @@ use base 'Catalyst::View::Email::Template'; __PACKAGE__->config( sender => { - method => 'Test' + mailer => 'Test' }, stash_key => 'email', template_prefix => '' diff --git a/t/lib/TestApp/View/Mason.pm b/t/lib/TestApp/View/Mason.pm index 070749f..d3a3b34 100644 --- a/t/lib/TestApp/View/Mason.pm +++ b/t/lib/TestApp/View/Mason.pm @@ -4,6 +4,6 @@ package # Hide me. use strict; eval "use base 'Catalyst::View::Mason';"; -__PACKAGE__->config( data_dir => TestApp->path_to('cache')->stringify ); +eval "__PACKAGE__->config( data_dir => TestApp->path_to('cache')->stringify );"; 1;