bumped version again as i missed it in Template
[catagits/Catalyst-View-Email.git] / lib / Catalyst / View / Email / Template.pm
CommitLineData
529915ab 1package Catalyst::View::Email::Template;
2
ce1977b0 3use Moose;
529915ab 4use Carp;
ea115f9b 5use Scalar::Util qw/ blessed /;
1e331578 6use Data::Dumper;
ce1977b0 7extends 'Catalyst::View::Email';
529915ab 8
b15e8ad4 9our $VERSION = '0.16';
529915ab 10
11=head1 NAME
12
13Catalyst::View::Email::Template - Send Templated Email from Catalyst
14
15=head1 SYNOPSIS
16
4a44bcd3 17Sends templated mail, based upon your default view. It captures the output
529915ab 18of the rendering path, slurps in based on mime-types and assembles a multi-part
4a44bcd3 19email using L<Email::MIME::Creator> and sends it out.
529915ab 20
ea115f9b 21=head1 CONFIGURATION
22
4a44bcd3 23WARNING: since version 0.10 the configuration options slightly changed!
24
25Use the helper to create your view:
ea115f9b 26
27 $ script/myapp_create.pl view Email::Template Email::Template
28
4a44bcd3 29For basic configuration look at L<Catalyst::View::Email/CONFIGURATION>.
30
ea115f9b 31In your app configuration (example in L<YAML>):
529915ab 32
33 View::Email::Template:
529915ab 34 # Optional prefix to look somewhere under the existing configured
ea115f9b 35 # template paths.
36 # Default: none
529915ab 37 template_prefix: email
06afcdbc 38 # Define the defaults for the mail
39 default:
ea115f9b 40 # Defines the default view used to render the templates.
41 # If none is specified neither here nor in the stash
42 # Catalysts default view is used.
43 # Warning: if you don't tell Catalyst explicit which of your views should
44 # be its default one, C::V::Email::Template may choose the wrong one!
06afcdbc 45 view: TT
529915ab 46
47=head1 SENDING EMAIL
48
4a44bcd3 49Sending email works just like for L<Catalyst::View::Email> but by specifying
50the template instead of the body and forwarding to your Email::Template view:
51
52 sub controller : Private {
53 my ( $self, $c ) = @_;
54
55 $c->stash->{email} = {
56 to => 'jshirley@gmail.com',
57 cc => 'abraxxa@cpan.org',
6a68a57d 58 bcc => 'hidden@secret.com hidden2@foobar.com',
4a44bcd3 59 from => 'no-reply@foobar.com',
60 subject => 'I am a Catalyst generated email',
61 template => 'test.tt',
ab4326b4 62 content_type => 'multipart/alternative'
4a44bcd3 63 };
64
65 $c->forward( $c->view('Email::Template') );
66 }
529915ab 67
06afcdbc 68Alternatively if you want more control over your templates you can use the following idiom
69to override the defaults:
12c85b56 70
71 templates => [
06afcdbc 72 {
73 template => 'email/test.html.tt',
74 content_type => 'text/html',
ea115f9b 75 charset => 'utf-8',
06afcdbc 76 view => 'TT',
77 },
78 {
79 template => 'email/test.plain.mason',
80 content_type => 'text/plain',
ea115f9b 81 charset => 'utf-8',
06afcdbc 82 view => 'Mason',
83 }
12c85b56 84 ]
85
86
4a44bcd3 87=head1 HANDLING ERRORS
88
89See L<Catalyst::View::Email/HANDLING ERRORS>.
529915ab 90
91=cut
92
06afcdbc 93# here the defaults of Catalyst::View::Email are extended by the additional
94# ones Template.pm needs.
95
ce1977b0 96has 'stash_key' => (
97 is => 'rw',
98 isa => 'Str',
99 default => sub { "email" },
100 lazy => 1,
529915ab 101);
102
ce1977b0 103has 'template_prefix' => (
104 is => 'rw',
105 isa => 'Str',
106 default => sub { '' },
107 lazy => 1,
108);
109
110has 'default' => (
111 is => 'rw',
112 isa => 'HashRef',
113 default => sub {
114 {
115 view => 'TT',
116 content_type => 'text/html',
117 };
118 },
119 lazy => 1,
120);
529915ab 121
122# This view hitches into your default view and will call the render function
123# on the templates provided. This means that you have a layer of abstraction
124# and you aren't required to modify your templates based on your desired engine
125# (Template Toolkit or Mason, for example). As long as the view adequately
126# supports ->render, all things are good. Mason, and others, are not good.
127
128#
129# The path here is to check configuration for the template root, and then
130# proceed to call render on the subsequent templates and stuff each one
131# into an Email::MIME container. The mime-type will be stupidly guessed with
132# the subdir on the template.
133#
529915ab 134
06afcdbc 135# Set it up so if you have multiple parts, they're alternatives.
136# This is on the top-level message, not the individual parts.
137#multipart/alternative
529915ab 138
06afcdbc 139sub _validate_view {
ce1977b0 140 my ( $self, $view ) = @_;
141
4a44bcd3 142 croak "C::V::Email::Template's configured view '$view' isn't an object!"
ce1977b0 143 unless ( blessed($view) );
06afcdbc 144
ce1977b0 145 croak
146 "C::V::Email::Template's configured view '$view' isn't an Catalyst::View!"
147 unless ( $view->isa('Catalyst::View') );
06afcdbc 148
ce1977b0 149 croak
150"C::V::Email::Template's configured view '$view' doesn't have a render method!"
151 unless ( $view->can('render') );
06afcdbc 152}
529915ab 153
4a44bcd3 154=head1 METHODS
155
156=over 4
11a0bf18 157
4a44bcd3 158=item generate_part
159
160Generates a MIME part to include in the email. Since the email is template based
11a0bf18 161every template piece is a separate part that is included in the email.
162
163=cut
164
43090696 165sub generate_part {
ce1977b0 166 my ( $self, $c, $attrs ) = @_;
d0e11256 167
ce1977b0 168 my $template_prefix = $self->template_prefix;
169 my $default_view = $self->default->{view};
170 my $default_content_type = $self->default->{content_type};
171 my $default_charset = $self->default->{charset};
ea115f9b 172
ea115f9b 173 my $view;
ce1977b0 174
ea115f9b 175 # use the view specified for the email part
ce1977b0 176 if ( exists $attrs->{view}
177 && defined $attrs->{view}
178 && $attrs->{view} ne '' )
179 {
180 $view = $c->view( $attrs->{view} );
181 $c->log->debug(
182 "C::V::Email::Template uses specified view $view for rendering.")
183 if $c->debug;
ea115f9b 184 }
ce1977b0 185
ea115f9b 186 # if none specified use the configured default view
187 elsif ($default_view) {
188 $view = $c->view($default_view);
ce1977b0 189 $c->log->debug(
190 "C::V::Email::Template uses default view $view for rendering.")
191 if $c->debug;
ea115f9b 192 }
ce1977b0 193
ea115f9b 194 # else fallback to Catalysts default view
195 else {
196 $view = $c->view;
ce1977b0 197 $c->log->debug(
198"C::V::Email::Template uses Catalysts default view $view for rendering."
199 ) if $c->debug;
ea115f9b 200 }
06afcdbc 201
06afcdbc 202 # validate the per template view
203 $self->_validate_view($view);
ce1977b0 204
06afcdbc 205 # prefix with template_prefix if configured
ce1977b0 206 my $template =
207 $template_prefix ne ''
208 ? join( '/', $template_prefix, $attrs->{template} )
209 : $attrs->{template};
210
43090696 211 # setup the attributes (merge with defaults)
ce1977b0 212 my $e_m_attrs = $self->SUPER::setup_attributes( $c, $attrs );
ea115f9b 213
06afcdbc 214 # render the email part
ce1977b0 215 my $output = $view->render(
216 $c,
217 $template,
218 {
219 content_type => $e_m_attrs->{content_type},
220 stash_key => $self->stash_key,
1e331578 221 %{$c->stash},
ce1977b0 222 }
223 );
1e331578 224 warn "Email output: $output";
43090696 225 if ( ref $output ) {
226 croak $output->can('as_string') ? $output->as_string : $output;
529915ab 227 }
43090696 228
06afcdbc 229 return Email::MIME->create(
ea115f9b 230 attributes => $e_m_attrs,
43090696 231 body => $output,
06afcdbc 232 );
233}
529915ab 234
4a44bcd3 235=item process
11a0bf18 236
4a44bcd3 237The process method is called when the view is dispatched to. This creates the
11a0bf18 238multipart message and then sends the message contents off to
4a44bcd3 239L<Catalyst::View::Email> for processing, which in turn hands off to
240L<Email::Send>.
11a0bf18 241
242=cut
243
ce1977b0 244around 'process' => sub {
245 my ( $orig, $self, $c, @args ) = @_;
246 my $stash_key = $self->stash_key;
cce24d41 247 return $self->$orig( $c, @args )
ce1977b0 248 unless $c->stash->{$stash_key}->{template}
249 or $c->stash->{$stash_key}->{templates};
250 warn "Stash: " . $stash_key;
8b10ee55 251
06afcdbc 252 # in case of the simple api only one
ce1977b0 253 my @parts = ();
12c85b56 254
06afcdbc 255 # now find out if the single or multipart api was used
256 # prefer the multipart one
ce1977b0 257
06afcdbc 258 # multipart api
ce1977b0 259 if ( $c->stash->{$stash_key}->{templates}
06afcdbc 260 && ref $c->stash->{$stash_key}->{templates} eq 'ARRAY'
ce1977b0 261 && ref $c->stash->{$stash_key}->{templates}[0] eq 'HASH' )
262 {
263
06afcdbc 264 # loop through all parts of the mail
ce1977b0 265 foreach my $part ( @{ $c->stash->{$stash_key}->{templates} } ) {
266 push @parts,
267 $self->generate_part(
268 $c,
269 {
270 view => $part->{view},
271 template => $part->{template},
272 content_type => $part->{content_type},
273 charset => $part->{charset},
274 }
275 );
43090696 276 }
06afcdbc 277 }
ce1977b0 278
06afcdbc 279 # single part api
ce1977b0 280 elsif ( $c->stash->{$stash_key}->{template} ) {
281 push @parts,
282 $self->generate_part( $c,
283 { template => $c->stash->{$stash_key}->{template}, } );
06afcdbc 284 }
ce1977b0 285
8b10ee55 286 delete $c->stash->{$stash_key}->{body};
287 $c->stash->{$stash_key}->{parts} ||= [];
ce1977b0 288 push @{ $c->stash->{$stash_key}->{parts} }, @parts;
1e331578 289
290 warn "Stash: " . Dumper $c->stash;
cce24d41 291 return $self->$orig($c);
ce1977b0 292
293};
529915ab 294
4a44bcd3 295=back
296
529915ab 297=head1 TODO
298
299=head2 ATTACHMENTS
300
301There needs to be a method to support attachments. What I am thinking is
302something along these lines:
25650747 303
529915ab 304 attachments => [
305 # Set the body to a file handle object, specify content_type and
306 # the file name. (name is what it is sent at, not the file)
307 { body => $fh, name => "foo.pdf", content_type => "application/pdf" },
308 # Or, specify a filename that is added, and hey, encoding!
309 { filename => "foo.gif", name => "foo.gif", content_type => "application/pdf", encoding => "quoted-printable" },
310 # Or, just a path to a file, and do some guesswork for the content type
311 "/path/to/somefile.pdf",
312 ]
313
314=head1 SEE ALSO
315
316=head2 L<Catalyst::View::Email> - Send plain boring emails with Catalyst
317
318=head2 L<Catalyst::Manual> - The Catalyst Manual
319
320=head2 L<Catalyst::Manual::Cookbook> - The Catalyst Cookbook
321
322=head1 AUTHORS
323
324J. Shirley <jshirley@gmail.com>
325
12c85b56 326Simon Elliott <cpan@browsing.co.uk>
327
4a44bcd3 328Alexander Hartmaier <abraxxa@cpan.org>
06afcdbc 329
529915ab 330=head1 LICENSE
331
332This library is free software, you can redistribute it and/or modify it under
333the same terms as Perl itself.
334
335=cut
336
3371;