refactor of the API and mainly Catalyst::View::Email::Template
[catagits/Catalyst-View-Email.git] / lib / Catalyst / View / Email / Template.pm
index e213a10..2d58c38 100644 (file)
@@ -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 <jshirley@gmail.com>
 
 Simon Elliott <cpan@browsing.co.uk>
 
+Alexander Hartmaier <alex_hartmaier@hotmail.com>
+
 =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;
-