8b9eef89de46bcc0f1d51c3b313adca0384c5e08
[catagits/Catalyst-Runtime.git] / lib / Catalyst / ActionRole / HTTPMethods.pm
1 package Catalyst::ActionRole::HTTPMethods;
2
3 use Moose::Role;
4
5 requires 'match', 'match_captures', 'list_extra_info';
6
7 around ['match','match_captures'] => sub {
8   my ($orig, $self, $ctx, @args) = @_;
9   my $expected = $ctx->req->method;
10   return $self->_has_expected_http_method($expected) ?
11     $self->$orig($ctx, @args) :
12     0;
13 };
14
15
16 sub _has_expected_http_method {
17   my ($self, $expected) = @_;
18   return 1 unless scalar(my @allowed = $self->allowed_http_methods);
19   return scalar(grep { lc($_) eq lc($expected) } @allowed) ?
20     1 : 0;
21 }
22
23 sub allowed_http_methods { @{shift->attributes->{Method}||[]} }
24
25 around 'list_extra_info' => sub {
26   my ($orig, $self, @args) = @_;
27   return {
28     %{ $self->$orig(@args) }, 
29     HTTP_METHODS => [sort $self->allowed_http_methods],
30   };
31 };
32
33 1;
34
35 =head1 NAME
36
37 Catalyst::ActionRole::HTTPMethods - Match on HTTP Methods
38
39 =head1 SYNOPSIS
40
41     package MyApp::Web::Controller::MyController;
42
43     use Moose;
44     use MooseX::MethodAttributes;
45
46     extends 'Catalyst::Controller';
47
48     sub user_base : Chained('/') CaptureArg(0) { ... }
49
50       sub get_user    : Chained('user_base') Args(1) GET { ... }
51       sub post_user   : Chained('user_base') Args(1) POST { ... }
52       sub put_user    : Chained('user_base') Args(1) PUT { ... }
53       sub delete_user : Chained('user_base') Args(1) DELETE { ... }
54       sub head_user   : Chained('user_base') Args(1) HEAD { ... }
55       sub option_user : Chained('user_base') Args(1) OPTION { ... }
56       sub option_user : Chained('user_base') Args(1) PATCH { ... }
57
58
59       sub post_and_put : Chained('user_base') POST PUT Args(1) { ... }
60       sub method_attr  : Chained('user_base') Method('DELETE') Args(0) { ... }
61
62     __PACKAGE__->meta->make_immutable;
63
64 =head1 DESCRIPTION
65
66 This is an action role that lets your L<Catalyst::Action> match on standard
67 HTTP methods, such as GET, POST, etc.
68
69 Since most web browsers have limited support for rich HTTP Method vocabularies
70 we use L<Plack::Middleware::MethodOverride> which allows you to 'tunnel' your
71 request method over POST  This works in two ways.  You can set an extension
72 HTTP header C<X-HTTP-Method-Override> which will contain the value of the
73 desired request method, or you may set a search query parameter
74 C<x-tunneled-method>.  Remember, these only work over HTTP Request type
75 POST.  See L<Plack::Middleware::MethodOverride> for more.
76
77 =head1 REQUIRES
78
79 This role requires the following methods in the consuming class.
80
81 =head2 match
82
83 =head2 match_captures
84
85 Returns 1 if the action matches the existing request and zero if not.
86
87 =head1 METHODS
88
89 This role defines the following methods
90
91 =head2 match
92
93 =head2 match_captures
94
95 Around method modifier that return 1 if the request method matches one of the
96 allowed methods (see L</http_methods>) and zero otherwise.
97
98 =head2 allowed_http_methods
99
100 An array of strings that are the allowed http methods for matching this action
101 normalized as noted above (using X-Method* overrides).
102
103 =head2 list_extra_info
104
105 Adds a key => [@values] "HTTP_METHODS" whose value is an ArrayRef of sorted
106 allowed methods to the ->list_extra_info HashRef.  This is used primarily for
107 debugging output.
108
109 =head2 _has_expected_http_method ($expected)
110
111 Private method which returns 1 if C<$expected> matches one of the allowed
112 in L</http_methods> and zero otherwise.
113
114 =head1 AUTHORS
115
116 Catalyst Contributors, see Catalyst.pm
117
118 =head1 COPYRIGHT
119
120 This library is free software. You can redistribute it and/or modify it under
121 the same terms as Perl itself.
122
123 =cut