Mercurial > pub > Impl
comparison Lib/IMPL/Web/Application/Resource.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 | |
children | 6d8092d8ce1b |
comparison
equal
deleted
inserted
replaced
228:431db7034a88 | 229:47f77e6409f7 |
---|---|
1 package IMPL::Web::Application::Resource; | |
2 use strict; | |
3 | |
4 use IMPL::lang qw(:constants); | |
5 use IMPL::declare { | |
6 require => { | |
7 Exception => 'IMPL::Exception', | |
8 ArgumentException => '-IMPL::InvalidArgumentException', | |
9 OperationException => '-IMPL::InvalidOperationException', | |
10 NotAllowedException => 'IMPL::Web::NotAllowedException', | |
11 NotFoundException => 'IMPL::Web::NotFoundException' | |
12 }, | |
13 base => [ | |
14 'IMPL::Object' => undef, | |
15 'IMPL::Web::Application::ResourceInterface' => undef | |
16 ], | |
17 props => [ | |
18 parent => PROP_GET | PROP_OWNERSET, | |
19 model => PROP_GET | PROP_OWNERSET, | |
20 id => PROP_GET | PROP_OWNERSET, | |
21 contract => PROP_GET | PROP_OWNERSET, | |
22 location => PROP_GET | PROP_OWNERSET | |
23 ] | |
24 }; | |
25 | |
26 sub CTOR { | |
27 my ( $this, %args ) = @_; | |
28 | |
29 die ArgumentException->new( id => 'A resource identifier is required' ) | |
30 unless $args{id}; | |
31 die ArgumentException->new( contract => 'A contract is required' ) | |
32 unless $args{id}; | |
33 | |
34 $this->parent( $args{parent} ); | |
35 $this->model( $args{model} ); | |
36 $this->id( $args{id} ); | |
37 $this->contract( $args{contract} ); | |
38 | |
39 # если расположение явно не указано, что обычно делается для корневого | |
40 # ресурса, то оно вычисляется автоматически, либо остается не заданным | |
41 $this->location( $args{location} | |
42 || eval { $this->parent->location->Child( $this->id ) } ); | |
43 ) | |
44 | |
45 } | |
46 | |
47 sub InvokeHttpVerb { | |
48 my ( $this, $verb, $action ) = @_; | |
49 | |
50 my $verb = $this->contract->verbs->{ lc($verb) }; | |
51 | |
52 die NotAllowedException->new( | |
53 allow => join( ',' map( uc, keys %{ $this->contract->verbs } ) ) ) | |
54 unless $verb; | |
55 | |
56 return $verb->Invoke( $this, $action ); | |
57 } | |
58 | |
59 # это реализация по умолчанию, базируется информации о ресурсах, содержащийся | |
60 # в контракте. | |
61 sub FetchChildResource { | |
62 my ( $this, $childId ) = @_; | |
63 | |
64 my $info = $this->contract->FindChildResourceInfo($childId); | |
65 | |
66 die NotFoundException->new() unless $info; | |
67 | |
68 my $binding = $this->{binding}; | |
69 my $contract = $this->{contract} | |
70 or die OperationException->new("Can't fetch a contract for the resource", $childId); | |
71 | |
72 my %args = ( | |
73 parent => $this, | |
74 id => $childId | |
75 ); | |
76 | |
77 $args{model} = _InvokeDelegate($binding,$this); | |
78 | |
79 return $contract->CreateResource(%args); | |
80 } | |
81 | |
82 sub _InvokeDelegate { | |
83 my $delegate = shift; | |
84 | |
85 return $delegete->(@_) if ref $delegate eq 'CODE'; | |
86 return $delegate->Invoke(@_) if eval { $delegate->can('Invoke')}; | |
87 } | |
88 | |
89 1; | |
90 | |
91 __END__ | |
92 | |
93 =pod | |
94 | |
95 =head1 NAME | |
96 | |
97 C<IMPL::Web::Application::Resource> - Web-ресурс. | |
98 | |
99 =head1 SYNOPSIS | |
100 | |
101 Класс для внутреннего использования. Объединяет в себе контракт и модель данных. | |
102 Основная задача - обработать поступающий от контроллера запрос на вызов C<HTTP> | |
103 метода. | |
104 | |
105 Экземпляры данного класса передаются в качестве параметров делегатам | |
106 осуществляющим привязку к модели в C<IMPL::Web::Application::ResourceContract> | |
107 и C<IMPL::Web::Application::OperationContract>. | |
108 | |
109 =head1 DESCRIPTION | |
110 | |
111 Весь функционал ресурса, поддерживаемые им C<HTTP> методы определяются | |
112 контрактом. Однако можно реализовывать ресурсы, которые не имеют контракта | |
113 или он отличается от того, что предоставляется стандартно | |
114 C<IMPL::Web::Application::ResourceContract>. | |
115 | |
116 Каждый ресурс является контейнером, тоесть позволяет получить дочерний ресурс | |
117 по идентифифкатору, если таковой имеется, тоесть ресурс, у которого нет дочерних | |
118 ресурсов на самом деле рассматривается как пустой контейнер. | |
119 | |
120 С ресурсом непосредственно взаимодействует котроллер запросов | |
121 C<IMPL::Web::Handler::RestController>, вызывая два метода. | |
122 | |
123 =over | |
124 | |
125 =item * C<FetchChildResource($childId)> | |
126 | |
127 Данный метод возвращает дочерний ресурс, соответствующий C<$childId>. | |
128 Текущая реализация использует метод C<FindChildResourceInfo> контракта текущего | |
129 ресурса, после чего создает дочерний ресурс. | |
130 | |
131 Если дочерний ресурс не найден, вызывается исключение | |
132 C<IMPL::Web::NotFoundException>. | |
133 | |
134 =item * C<InvokeHttpVerb($verb,$action)> | |
135 | |
136 Обрабатывает запрос к ресурсу. Для этого используется контракт ресурса, в | |
137 нем выбирается соответсвующий C<IMPL::Web::Application::OperationContract>. | |
138 Затем найденный контракт для указанной операции используется для обработки | |
139 запроса. | |
140 | |
141 =back | |
142 | |
143 Если объект реализует два вышеуказанных метода, он является веб-ресурсом, а | |
144 детали его реализации, котнракт и прочее уже не важно, поэтому можно реализовать | |
145 собственный класс ресурса, например унаследованный от | |
146 C<IMPL::Web::Application::CustomResource>. | |
147 | |
148 =cut |