comparison Lib/IMPL/Web/Handler/RestController.pm @ 229:47f77e6409f7

heavily reworked the resource model of the web application: *some ResourcesContraact functionality moved to Resource +Added CustomResource *Corrected action handlers
author sergey
date Sat, 29 Sep 2012 02:34:47 +0400
parents d6e2ea24af08
children 6d8092d8ce1b
comparison
equal deleted inserted replaced
228:431db7034a88 229:47f77e6409f7
1 package IMPL::Web::Handler::RestController; 1 package IMPL::Web::Handler::RestController;
2 use strict; 2 use strict;
3 3
4 use IMPL::lang qw(:declare :constants); 4 use IMPL::lang qw(:declare :constants);
5
6
7 use IMPL::declare { 5 use IMPL::declare {
8 require => { 6 require => {
7 ResourceInterface => 'IMPL::Web::Application::ResourceInterface',
9 Exception => 'IMPL::Exception', 8 Exception => 'IMPL::Exception',
10 ArgumentExecption => '-IMPL::InvalidArgumentException', 9 ArgumentExecption => '-IMPL::InvalidArgumentException',
11 HttpException => 'IMPL::Web::Exception', 10 NotFoundException => 'IMPL::Web::NotFoundException'
12 NotFoundException => 'IMPL::Web::NotFoundException'
13 }, 11 },
14 base => { 12 base => {
15 'IMPL::Object' => undef, 13 'IMPL::Object' => undef,
16 'IMPL::Object::Autofill' => '@_', 14 'IMPL::Object::Autofill' => '@_',
17 'IMPL::Object::Serializable' => undef 15 'IMPL::Object::Serializable' => undef
18 } 16 },
17 props => [
18 rootResource => PROP_GET | PROP_OWNERSET,
19 trailingSlash => PROP_GET | PROP_OWNERSET
20 ]
19 }; 21 };
20
21 BEGIN {
22 public property root => PROP_GET | PROP_OWNERSET;
23 public property contract => PROP_GET | PROP_OWNERSET;
24 }
25 22
26 sub CTOR { 23 sub CTOR {
27 my ($this) = @_; 24 my ($this) = @_;
28 25
29 die ArgumentException->new("root") unless $this->root; 26 die ArgumentException->new(rootResource => "A web-resource is required")
30 die ArgumentException->new("contract") unless $this->contract; 27 unless eval { $this->rootResource->isa(ResourceInterface) };
28
31 } 29 }
30
31 sub GetResourcePath {
32 my ($this,$action) = @_;
33
34 my $pathInfo = $action->pathInfo;
35 my @segments;
36
37 if (length $pathInfo) {
38
39 @segments = split(/\//, $pathInfo, $this->trailingSlash ? -1 : 0);
40
41 # remove first segment since it's always empty
42 shift @segments;
43
44 my ($obj,$view) = (pop(@segments) =~ m/(.*?)(?:\.(\w+))?$/);
45 push @segments, $obj;
46
47 }
48
49 return @segments;
50 }
51
32 52
33 sub Invoke { 53 sub Invoke {
34 my ($this,$action) = @_; 54 my ($this,$action) = @_;
35 55
36 my $query = $action->query; 56 my $method = $action->requestMethod;
37 57
38 my $method = $query->request_method; 58 my @segments = $this->GetResourcePath($action);
39 59
40 #TODO: path_info is broken for IIS 60 my $res = $this->rootResource;
41 my $pathInfo = $query->path_info;
42 my @segments;
43
44 if (length $pathInfo) {
45
46 @segments = split /\//, $pathInfo, -1; # keep trailing empty string if present
47
48 # remove first segment since it's always empty
49 shift @segments;
50
51 my ($obj,$view) = (pop(@segments) =~ m/(.*?)(?:\.(\w+))?$/);
52 push @segments, $obj;
53
54 }
55
56
57 my $res = $this->contract->Transform($this->root, { id => '' } );
58 61
59 while(@segments) { 62 while(@segments) {
60 my $id = shift @segments; 63 my $id = shift @segments;
61 64
62 $res = $res->FetchChildResource($id,$action); 65 $res = $res->FetchChildResource($id);
63 66
64 die NotFoundException->new($pathInfo,$id) unless $res; 67 die NotFoundException->new($pathInfo,$id) unless $res;
65 } 68 }
66 69
67 $res = $res->InvokeHttpMethod($method,$action); 70 $res = $res->InvokeHttpVerb($method,$action);
68 } 71 }
69 72
70 1; 73 1;
71 74
72 __END__ 75 __END__
73 76
74 =pod 77 =pod
75 78
76 =head1 NAME 79 =head1 NAME
77 80
78 C<IMPL::Web::Handler::RestController> - Транслирует запросы к ресурсам в вызовы методов. 81 C<IMPL::Web::Handler::RestController> - Обрабатывает C<HTTP> запрос передавая
82 его соответствующему ресурсу.
79 83
80 =head1 SYNOPSIS 84 =head1 SYNOPSIS
81 85
82 Использует контракты для преобразования стандартных C<REST> запросов в вызовы методов объектов. 86 Используется в конфигурации приложения как элемент цепочки обработчиков.
83 C<$ENV{PATH_INFO}> используется как путь к нужному ресурсу у которого будет вызван метод указанный в запросе. 87 Как правило располагается на самом верхнем уровне.
88
89 =begin code xml
90
91 <handlers type="ARRAY">
92 <item type="IMPL::Web::Handler::RestController">
93 <rootResource type="My::App::Web::RootResource"/>
94 </item>
95 <item type="IMPL::Web::Handler::JSONView" />
96 <item type="IMPL::Web::Handler::SecureCookie" />
97 <item type="IMPL::Web::Handler::ErrorHandler" />
98 </handlers>
99
100 =end code xml
101
84 102
85 =head1 DESCRIPTION 103 =head1 DESCRIPTION
86 104
87 =head2 Resource model 105 Использует C<PATH_INFO> для определения нужного ресурса, затем предает
106 найденному ресурсу управление для обработки запроса.
88 107
89 Ресурсы имеют иерархическую структуру, аналогичную файлам и каталогам, которая описывается контрактом, также 108 Если ресурс не найден, то возникает исключение C<IMPL::Web::NotFoundException>.
90 контрак описывает то, как должны обрабатываться методы C<HTTP> запроса, такие как C<GET> и C<POST>.
91 109
92 За корректность реализации данных методов отвечает разработчик. 110 Для определения нужного ресурса контроллер разбивает C<PATH_INFO> на фрагменты
111 и использует каждый фрагмент для получения дочернего ресурса начиная с корневого.
112 Для чего используется метод
113 C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>.
93 114
94 Каждый ресурс представляет собой коллкецию вложенных ресурсов, путь указанный в C<HTTP> запросе разбивается на 115 =head1 MEMEBERS
95 части, затем каждый сегмент последовательно используется для поиска дочернего ресурса. При обработки
96 первого сегмента используется корневой ресурс. Корневой ресурс должен существовать всегда.
97 116
98 =head2 Contract 117 =head2 C<[get]rootResource>
99 118
100 Контрактом может быть любое преобразование которое определяет соответсвие между объектами приложения и 119 Корневой ресурс приложения, должен быть всегда и реализовывать интерфес ресурса
101 ресурсами, доступными через протокол C<HTTP>. 120 C<IMPL::Web::Application::ResourceInterface>.
102 121
122 =head2 C<[get]trailingSlash>
103 123
104 124 Если данная переменная имеет значение C<true>, то слеш в конце пути к ресурсу
125 будет интерпретироваться, как дочерний ресурс с пустым идентификатором.
105 126
106 =cut 127 =cut