407
|
1 package IMPL::Web::Handler::ViewSelector;
|
|
2 use strict;
|
|
3
|
|
4 use IMPL::Const qw(:prop);
|
|
5
|
|
6 use IMPL::declare {
|
|
7 require => {
|
|
8 NotAcceptable => 'IMPL::Web::NotAcceptableException',
|
|
9 HttpResponse => 'IMPL::Web::HttpResponse'
|
|
10 },
|
|
11 base => [
|
|
12 'IMPL::Object' => undef,
|
|
13 'IMPL::Object::Autofill' => '@_',
|
|
14 'IMPL::Object::Serializable' => undef
|
|
15 ],
|
|
16 props => [
|
|
17 views => PROP_RW | PROP_LIST,
|
|
18 fallback => PROP_RW,
|
|
19 types => PROP_RW
|
|
20 ]
|
|
21 };
|
|
22
|
|
23 sub Invoke {
|
|
24 my ( $this, $action, $next ) = @_;
|
|
25
|
|
26 my $result = $next ? $next->($action) : undef;
|
|
27
|
|
28 my $model;
|
|
29
|
|
30 return $result if eval { $result->isa(HttpResponse) };
|
|
31
|
|
32 my $handler;
|
|
33 my $path = $action->pathInfo;
|
|
34
|
|
35 if ( $this->types and $path =~ m/\.(\w+)$/ ) {
|
|
36 my $forced;
|
|
37 if ( $forced = $this->types->{$1} and $action->query->Accept($forced) )
|
|
38 {
|
|
39 ($handler) =
|
|
40 grep eval { $_->can('contentType') }
|
|
41 && $_->contentType eq $forced, $this->views;
|
|
42 }
|
|
43 }
|
|
44
|
|
45 if ( not $handler ) {
|
|
46
|
|
47 my @handlers =
|
|
48 sort { $b->{preference} <=> $a->{preference} } map {
|
|
49 {
|
|
50 handler => $_,
|
|
51 preference => eval { $_->can('contentType') }
|
|
52 ? $action->query->Accept( $_->contentType )
|
|
53 : 0
|
|
54 }
|
|
55 } $this->views;
|
|
56
|
|
57 my $info = shift @handlers;
|
|
58 $handler = $info ? $info->{handler} : undef;
|
|
59
|
|
60 }
|
|
61
|
|
62 die NotAcceptable->new(
|
|
63 map {
|
|
64 eval { $_->can('contentType') } ? $_->contentType : ()
|
|
65 } $this->views
|
|
66 ) unless $handler;
|
|
67
|
|
68 return $handler->Invoke( $action, sub { $result } );
|
|
69 }
|
|
70
|
|
71 1;
|
|
72
|
|
73 __END__
|
|
74
|
|
75 =pod
|
|
76
|
|
77 =head1 NAME
|
|
78
|
|
79 C<IMPL::Web::Handler::ViewSelector> - Выбор нужного представления на основе заголовка C<Accept>
|
|
80
|
|
81 =head1 DESCRIPTION
|
|
82
|
|
83 Использует заголовок запроса C<Accept> для выбора подходящего представления, если задано свойство C<types>,
|
|
84 пытается в первую очередь по расширению определить, какое представление подходит.
|
|
85
|
|
86 В случаях, когда не требуется строить представление для данных (например, при перенаправлении к другому
|
|
87 ресурсу или если нет данных), нужно, чтобы данному обработчику был возвращен
|
|
88 L<IMPL::Web::Application::ActionResult>, который будет просто передан далее.
|
|
89
|
|
90 =head1 MEMBERS
|
|
91
|
|
92 =head2 C<[get,set,list]views>
|
|
93
|
|
94 Список представлений, которые могут быть возвращены.
|
|
95
|
|
96 =head2 C<[get,set]types>
|
|
97
|
|
98 Хеш с соотвествием между расширением и типом содержимого, для подсказки при выборе представления.
|
|
99
|
|
100 =cut
|