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