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