File Coverage

lib/Catalyst/Action/Serialize.pm
Criterion Covered Total %
statement 37 42 88.1
branch 15 28 53.5
condition 3 8 37.5
subroutine 5 5 100.0
pod 1 1 100.0
total 61 84 72.6


line stmt bran cond sub pod time code
1             package Catalyst::Action::Serialize;
2             $Catalyst::Action::Serialize::VERSION = '1.21';
3 12     12   80519 use Moose;
  12         28  
  12         137  
4 12     12   63650 use namespace::autoclean;
  12         24  
  12         87  
5              
6             extends 'Catalyst::Action::SerializeBase';
7 12     12   823 use Module::Pluggable::Object;
  12         30  
  12         305  
8 12     12   54 use MRO::Compat;
  12         22  
  12         5144  
9              
10             has _encoders => (
11                is => 'ro',
12                isa => 'HashRef',
13                default => sub { {} },
14             );
15              
16             sub execute {
17 24     24 1 27267     my $self = shift;
18 24         58     my ( $controller, $c ) = @_;
19              
20 24         115     $self->maybe::next::method(@_);
21              
22 24 50       873     return 1 if $c->req->method eq 'HEAD';
23 24 100       1421     return 1 if $c->response->has_body;
24 8 50       266     return 1 if scalar @{ $c->error };
  8         23  
25 8 50       196     return 1 if $c->response->status =~ /^(?:204)$/;
26 8 50       783     return 1 if defined $c->stash->{current_view};
27 8 50       438     return 1 if defined $c->stash->{current_view_instance};
28              
29             # on 3xx responses, serialize if there's something to
30             # serialize, no-op if not
31                 my $stash_key = (
32                    $controller->{'serialize'} ?
33                        $controller->{'serialize'}->{'stash_key'} :
34 8   50     437                 $controller->{'stash_key'}
35                        ) || 'rest';
36 8 50 33     165     return 1 if $c->response->status =~ /^(?:3\d\d)$/ && ! defined $c->stash->{$stash_key};
37              
38 8         775     my ( $sclass, $sarg, $content_type ) =
39                   $self->_load_content_plugins( "Catalyst::Action::Serialize",
40                     $controller, $c );
41 8 50       40     unless ( defined($sclass) ) {
42 0 0       0         if ( defined($content_type) ) {
43 0         0             $c->log->info("Could not find a serializer for $content_type");
44                     } else {
45 0         0             $c->log->info(
46                             "Could not find a serializer for an empty content-type");
47                     }
48 0         0         return 1;
49                 }
50                 $c->log->debug(
51 8 0       28         "Serializing with $sclass" . ( $sarg ? " [$sarg]" : '' ) ) if $c->debug;
    50          
52              
53 8   33     236     $self->_encoders->{$sclass} ||= $sclass->new;
54 8         256     my $sobj = $self->_encoders->{$sclass};
55              
56 8         14     my $rc;
57 8         20     eval {
58 8 100       22         if ( defined($sarg) ) {
59 3         10             $rc = $sobj->execute( $controller, $c, $sarg );
60                     } else {
61 5         17             $rc = $sobj->execute( $controller, $c );
62                     }
63                 };
64 8 100       327     if ($@) {
    50          
65 1         9         return $self->serialize_bad_request( $c, $content_type, $@ );
66                 } elsif (!$rc) {
67 0         0         return $self->unsupported_media_type( $c, $content_type );
68                 }
69              
70 7         22     return 1;
71             }
72              
73             __PACKAGE__->meta->make_immutable;
74              
75             1;
76              
77             =head1 NAME
78            
79             Catalyst::Action::Serialize - Serialize Data in a Response
80            
81             =head1 SYNOPSIS
82            
83             package Foo::Controller::Bar;
84            
85             __PACKAGE__->config(
86             'default' => 'text/x-yaml',
87             'stash_key' => 'rest',
88             'map' => {
89             'text/html' => [ 'View', 'TT', ],
90             'text/x-yaml' => 'YAML',
91             'text/x-data-dumper' => [ 'Data::Serializer', 'Data::Dumper' ],
92             }
93             );
94            
95             sub end :ActionClass('Serialize') {}
96            
97             =head1 DESCRIPTION
98            
99             This action will serialize the body of an HTTP Response. The serializer is
100             selected by introspecting the HTTP Requests content-type header.
101            
102             It requires that your Catalyst controller is properly configured to set up the
103             mapping between Content Type's and Serialization classes.
104            
105             The specifics of serializing each content-type is implemented as a plugin to
106             L<Catalyst::Action::Serialize>.
107            
108             Typically, you would use this ActionClass on your C<end> method. However,
109             nothing is stopping you from choosing specific methods to Serialize:
110            
111             sub foo :Local :ActionClass('Serialize') {
112             .. populate stash with data ..
113             }
114            
115             When you use this module, the request class will be changed to
116             L<Catalyst::Request::REST>.
117            
118             =head1 CONFIGURATION
119            
120             =head2 map
121            
122             Takes a hashref, mapping Content-Types to a given serializer plugin.
123            
124             =head2 default
125            
126             This is the 'fall-back' Content-Type if none of the requested or acceptable
127             types is found in the L</map>. It must be an entry in the L</map>.
128            
129             =head2 stash_key
130            
131             Specifies the key of the stash entry holding the data that is to be serialized.
132             So if the value is "rest", we will serialize the data under:
133            
134             $c->stash->{'rest'}
135            
136             =head2 content_type_stash_key
137            
138             Specifies the key of the stash entry that optionally holds an overriding
139             Content-Type. If set, and if the specified stash entry has a valid value,
140             then it takes priority over the requested content types.
141            
142             This can be useful if you want to dynamically force a particular content type,
143             perhaps for debugging.
144            
145             =head1 HELPFUL PEOPLE
146            
147             Daisuke Maki pointed out that early versions of this Action did not play
148             well with others, or generally behave in a way that was very consistent
149             with the rest of Catalyst.
150            
151             =head1 CUSTOM ERRORS
152            
153             For building custom error responses when serialization fails, you can create
154             an ActionRole (and use L<Catalyst::Controller::ActionRole> to apply it to the
155             C<end> action) which overrides C<unsupported_media_type> and/or C<serialize_bad_request>
156             methods.
157            
158             =head1 SEE ALSO
159            
160             You likely want to look at L<Catalyst::Controller::REST>, which implements
161             a sensible set of defaults for doing a REST controller.
162            
163             L<Catalyst::Action::Deserialize>, L<Catalyst::Action::REST>
164            
165             =head1 AUTHORS
166            
167             See L<Catalyst::Action::REST> for authors.
168            
169             =head1 LICENSE
170            
171             You may distribute this code under the same terms as Perl itself.
172            
173             =cut
174