407
|
1 package IMPL::Web::Handler::RestController;
|
|
2 use strict;
|
|
3
|
|
4 use IMPL::Const qw(:prop);
|
|
5 use IMPL::declare {
|
|
6 require => {
|
|
7 Locator => 'IMPL::Web::AutoLocator',
|
|
8 ResourceInterface => 'IMPL::Web::Application::ResourceInterface',
|
|
9 Exception => 'IMPL::Exception',
|
|
10 ArgumentExecption => '-IMPL::InvalidArgumentException',
|
|
11 NotFoundException => 'IMPL::Web::NotFoundException',
|
|
12 Loader => 'IMPL::Code::Loader'
|
|
13 },
|
|
14 base => {
|
|
15 'IMPL::Object' => undef,
|
|
16 'IMPL::Object::Autofill' => '@_',
|
|
17 'IMPL::Object::Serializable' => undef
|
|
18 },
|
|
19 props => [
|
|
20 resourceFactory => PROP_RO,
|
|
21 trailingSlash => PROP_RO
|
|
22 ]
|
|
23 };
|
|
24
|
|
25 sub CTOR {
|
|
26 my ($this) = @_;
|
|
27
|
|
28 die ArgumentException->new(resourceFactory => "A web-resource is required")
|
|
29 unless $this->resourceFactory;
|
|
30 #unless eval { $this->resourceFacotry->isa(ResourceInterface) };
|
|
31
|
|
32 }
|
|
33
|
|
34 sub GetResourcePath {
|
|
35 my ($this,$action) = @_;
|
|
36
|
|
37 my $pathInfo = $action->pathInfo;
|
|
38 my @segments;
|
|
39
|
|
40 if (length $pathInfo) {
|
|
41
|
|
42 @segments = split(/\//, $pathInfo, $this->trailingSlash ? -1 : 0);
|
|
43
|
|
44 # remove first segment if it is empty
|
|
45 shift @segments if @segments && length($segments[0]) == 0;
|
|
46 }
|
|
47
|
|
48 return @segments;
|
|
49 }
|
|
50
|
|
51
|
|
52 sub Invoke {
|
|
53 my ($this,$request) = @_;
|
|
54
|
|
55 my $method = $request->requestMethod;
|
|
56
|
|
57 my @segments = $this->GetResourcePath($request);
|
|
58
|
|
59 my $factory = $this->resourceFactory;
|
|
60
|
|
61 $factory = Loader->default->Require($factory)
|
|
62 unless ref($factory) || eval { $factory->can('new') };
|
|
63
|
|
64 my $res = $factory->new(
|
|
65 id => 'root',
|
|
66 request => $request,
|
|
67 location => Locator->new(base => $request->application->baseUrl),
|
|
68 );
|
|
69
|
|
70 while(@segments) {
|
|
71 my $id = shift @segments;
|
|
72 $res = $res->FetchChildResource($id);
|
|
73 }
|
|
74
|
|
75 $res = $res->InvokeHttpVerb($method);
|
|
76 }
|
|
77
|
|
78 1;
|
|
79
|
|
80 __END__
|
|
81
|
|
82 =pod
|
|
83
|
|
84 =head1 NAME
|
|
85
|
|
86 C<IMPL::Web::Handler::RestController> - Обрабатывает C<HTTP> запрос передавая
|
|
87 его соответствующему ресурсу.
|
|
88
|
|
89 =head1 SYNOPSIS
|
|
90
|
|
91 Используется в конфигурации приложения как элемент цепочки обработчиков.
|
|
92 Как правило располагается на самом верхнем уровне.
|
|
93
|
|
94 =begin code xml
|
|
95
|
|
96 <handlers type="ARRAY">
|
|
97 <item type="IMPL::Web::Handler::RestController">
|
|
98 <resourceFactory>My::App::Web::RootResource</resourceFactory>
|
|
99 </item>
|
|
100 <item type="IMPL::Web::Handler::JSONView" />
|
|
101 <item type="IMPL::Web::Handler::SecureCookie" />
|
|
102 <item type="IMPL::Web::Handler::ErrorHandler" />
|
|
103 </handlers>
|
|
104
|
|
105 =end code xml
|
|
106
|
|
107
|
|
108 =head1 DESCRIPTION
|
|
109
|
|
110 Использует C<PATH_INFO> для определения нужного ресурса, затем предает
|
|
111 найденному ресурсу управление для обработки запроса.
|
|
112
|
|
113 Если ресурс не найден, то возникает исключение C<IMPL::Web::NotFoundException>.
|
|
114
|
|
115 Для определения нужного ресурса контроллер разбивает C<PATH_INFO> на фрагменты
|
|
116 и использует каждый фрагмент для получения дочернего ресурса начиная с корневого.
|
|
117 Для чего используется метод
|
|
118 C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>.
|
|
119
|
|
120 Дерево ресурсов сущестувет независимо от обрабатываемого запроса, однако оно
|
|
121 может полностью или частично загружаться в начале обработки запроса и
|
|
122 освобождаться по окончании обработки запроса. Поэтому при получении дочерних
|
|
123 ресурсов не участвует C<HTTP> запрос, он адресуется только последнему ресурсу.
|
|
124
|
|
125 =begin text
|
|
126
|
|
127 /music/audio.mp3 -> ['music','audio.mp3']
|
|
128
|
|
129 =end text
|
|
130
|
|
131 =head1 MEMEBERS
|
|
132
|
|
133 =head2 C<[get]resourceFactory>
|
|
134
|
|
135 Фабрика для создания корневого ресурса приложения, полученный ресурс должен
|
|
136 реализовывать интерфейс C<IMPL::Web::Application::ResourceInterface>.
|
|
137
|
|
138 Фабрика может сохранять ссылку на корневой ресурс и каждый раз не создавать
|
|
139 его, а возвращать уже существующий. Это вполне оправдано, если хранение
|
|
140 дерева ресурсов требует меньше ресурсов, чем его создание и при этом приложение
|
|
141 остается в памяти между C<HTTP> запросами.
|
|
142
|
|
143 =head2 C<[get]trailingSlash>
|
|
144
|
|
145 Если данная переменная имеет значение C<true>, то слеш в конце пути к ресурсу
|
|
146 будет интерпретироваться, как дочерний ресурс с пустым идентификатором.
|
|
147
|
|
148 =cut |