Mercurial > pub > Impl
comparison Lib/IMPL/Web/Application/RestResource.pm @ 198:2ffe6f661605
Implemented IMPL::Web::Handler::RestController
fixes in IMPL::Serialization
completed IMPL::Web::Application::RestResource
added IMPL::Web::Handler::JSONView
added IMPL::Web::RestContract
author | cin |
---|---|
date | Fri, 20 Apr 2012 16:06:36 +0400 |
parents | 6b1dda998839 |
children | e743a8481327 |
comparison
equal
deleted
inserted
replaced
197:6b1dda998839 | 198:2ffe6f661605 |
---|---|
1 package IMPL::Web::Application::RestResource; | 1 package IMPL::Web::Application::RestResource; |
2 use strict; | 2 use strict; |
3 | 3 |
4 use IMPL::lang qw(:declare :constants); | 4 use IMPL::lang qw(:declare :constants is); |
5 use IMPL::Exception(); | |
6 | |
5 use IMPL::declare { | 7 use IMPL::declare { |
6 require => { | 8 require => { |
7 ForbiddenException => 'IMPL::Web::ForbiddenException' | 9 ForbiddenException => 'IMPL::Web::ForbiddenException', |
10 InvalidOpException => '-IMPL::InvalidOperationException', | |
11 ArgumentException => '-IMPL::InvalidArgumentException', | |
12 TTransform => '-IMPL::Transform' | |
8 }, | 13 }, |
9 base => { | 14 base => { |
10 'IMPL::Object' => undef | 15 'IMPL::Object' => undef, |
16 'IMPL::Object::Autofill' => '@_' | |
11 } | 17 } |
12 }; | 18 }; |
13 | 19 |
14 BEGIN { | 20 BEGIN { |
15 public property target => PROP_GET | PROP_OWNERSET; | 21 public property target => PROP_GET | PROP_OWNERSET; |
20 public property insert => PROP_GET | PROP_OWNERSET; | 26 public property insert => PROP_GET | PROP_OWNERSET; |
21 public property update => PROP_GET | PROP_OWNERSET; | 27 public property update => PROP_GET | PROP_OWNERSET; |
22 public property delete => PROP_GET | PROP_OWNERSET; | 28 public property delete => PROP_GET | PROP_OWNERSET; |
23 } | 29 } |
24 | 30 |
31 sub CTOR { | |
32 my ($this) = @_; | |
33 | |
34 die ArgumentException->new("target") unless $this->target; | |
35 } | |
36 | |
25 sub GetHttpImpl { | 37 sub GetHttpImpl { |
26 my($this,$method) = @_; | 38 my($this,$method) = @_; |
27 | 39 |
28 my %map = ( | 40 my %map = ( |
29 GET => 'GetImpl', | 41 GET => 'GetImpl', |
34 | 46 |
35 return $map{$method}; | 47 return $map{$method}; |
36 } | 48 } |
37 | 49 |
38 sub InvokeHttpMethod { | 50 sub InvokeHttpMethod { |
39 my ($this,$method,$child,$action) = @_; | 51 my ($this,$method,$childId,$action) = @_; |
40 | 52 |
41 my $impl = $this->GetHttpImpl($method) || 'FallbackImpl'; | 53 my $impl = $this->GetHttpImpl($method) || 'HttpFallbackImpl'; |
42 | 54 |
43 return $this->$impl($child,$action); | 55 return $this->$impl($childId,$action); |
44 } | 56 } |
45 | 57 |
46 sub GetImpl { | 58 sub GetImpl { |
47 my ($this,$id,$action) = @_; | 59 my ($this,$id,$action) = @_; |
48 | 60 |
49 my $rx; | 61 my $rx; |
50 my $method; | 62 my $method; |
51 if (length $id == 0) { | 63 if (length $id == 0) { |
52 $method = $this->list; | 64 $method = $this->list or die ForbiddenException->new(); |
53 } elsif ($method = $this->methods->{$id}) { | 65 } elsif ($this->methods and $method = $this->methods->{$id}) { |
54 if (ref $method eq 'HASH' and not $method->{allowGet}) { | 66 if (ref $method eq 'HASH' and not $method->{allowGet}) { |
55 die ForbiddenException->new(); | 67 die ForbiddenException->new(); |
56 } | 68 } |
57 } elsif($rx = $this->childRegex and $id =~ m/$rx/ ) { | 69 } elsif($rx = $this->childRegex and $id =~ m/$rx/ ) { |
58 $method = $this->fetch or die ForbiddenException->new(); | 70 $method = $this->fetch or die ForbiddenException->new(); |
60 $method = { | 72 $method = { |
61 method => $method, | 73 method => $method, |
62 parameters => [qw(id)] | 74 parameters => [qw(id)] |
63 } unless ref $method; | 75 } unless ref $method; |
64 | 76 |
65 } else { | |
66 die ForbiddenException->new(); | |
67 } | 77 } |
68 | 78 |
69 return $this->InvokeMember($method,$id,$action); | 79 return $this->InvokeMember($method,$id,$action); |
70 } | 80 } |
71 | 81 |
129 die ForbiddenException->new(); | 139 die ForbiddenException->new(); |
130 } | 140 } |
131 | 141 |
132 sub InvokeMember { | 142 sub InvokeMember { |
133 my ($this,$method,$id,$action) = @_; | 143 my ($this,$method,$id,$action) = @_; |
134 } | 144 |
145 #normalize method info | |
146 if (not ref $method) { | |
147 $method = { | |
148 method => $method | |
149 }; | |
150 } | |
151 | |
152 if (ref $method eq 'HASH') { | |
153 my @args; | |
154 my $member = $method->{method} or die InvalidOpException->new("A member name isn't specified"); | |
155 if (my $params = $method->{parameters}) { | |
156 if (ref $params eq 'HASH') { | |
157 @args = map { | |
158 $_, | |
159 $this->MakeParameter($params->{$_},$id,$action) | |
160 } keys %$params; | |
161 } elsif (ref $params eq 'ARRAY') { | |
162 @args = map $this->MakeParameter($_,$id,$action), @$params; | |
163 } else { | |
164 @args = ($this->MakeParameter($params,$id,$action)); | |
165 } | |
166 } | |
167 $this->target->$member(@args); | |
168 } else { | |
169 die InvalidOpException->new("Unsupported type of the method information", ref $method); | |
170 } | |
171 } | |
172 | |
173 sub MakeParameter { | |
174 my ($this,$param,$id,$action) = @_; | |
175 | |
176 if ($param) { | |
177 if (is $param, TTransform ) { | |
178 return $param->Transform($this,$action->query); | |
179 } elsif ($param and not ref $param) { | |
180 my %std = ( | |
181 id => $id, | |
182 action => $action, | |
183 query => $action->query | |
184 ); | |
185 | |
186 return $std{$param} || $action->query->param($param); | |
187 } | |
188 } else { | |
189 return undef; | |
190 } | |
191 } | |
192 | |
193 | |
135 | 194 |
136 | 195 |
137 1; | 196 1; |
138 | 197 |
139 __END__ | 198 __END__ |
193 | 252 |
194 my $cds = TRes->new( | 253 my $cds = TRes->new( |
195 DataContext->Default, | 254 DataContext->Default, |
196 { | 255 { |
197 methods => { | 256 methods => { |
198 get => { | 257 history => { |
199 | 258 allowGet => 1, |
259 method => 'GetHistory', | |
260 parameters => [qw(from to)] | |
200 }, | 261 }, |
201 post => { | |
202 | |
203 } | |
204 } | 262 } |
205 get => 'search', | 263 list => 'search', |
206 | 264 fetch => 'GetItemById' |
207 | |
208 } | 265 } |
209 ); | 266 ); |
210 | 267 |
211 =end code | 268 =end code |
212 | 269 |
239 | 296 |
240 =head3 C<POST> | 297 =head3 C<POST> |
241 | 298 |
242 Добавляет новый дочерний ресурс в коллекцию. | 299 Добавляет новый дочерний ресурс в коллекцию. |
243 | 300 |
301 =head3 C<POST {method}> | |
302 | |
303 Вызывает метод C<method>. | |
304 | |
244 =head2 HTTP METHOD MAPPING | 305 =head2 HTTP METHOD MAPPING |
245 | 306 |
246 =head3 C<POST {method}> | 307 =head3 C<POST {method}> |
247 | 308 |
248 Вызывает метод C<method>, в отличии от C<GET> методы опубликованные через C<POST> могут вносить | 309 Вызывает метод C<method>, в отличии от C<GET> методы опубликованные через C<POST> могут вносить |
254 | 315 |
255 Объект (также может быть и класс), обеспечивающий функционал ресурса. | 316 Объект (также может быть и класс), обеспечивающий функционал ресурса. |
256 | 317 |
257 =head2 C<[get]methods> | 318 =head2 C<[get]methods> |
258 | 319 |
320 Содержит описания методов, которые будут публиковаться как дочерние ресурсы. | |
321 | |
259 =head2 C<[get]childRegex> | 322 =head2 C<[get]childRegex> |
260 | 323 |
324 Содержит регулярное выражение для идентификаторов дочерних объектов. Если оно | |
325 не задано, то данный ресурс не является коллекцией. | |
326 | |
261 =head2 C<[get]fetch> | 327 =head2 C<[get]fetch> |
262 | 328 |
329 Содержит описание метода для получения дочернего объекта. Если данный метод | |
330 отсутствует, то дочерние ресурсы не получится адресовать относительно данного. | |
331 По умолчанию получает идентификатор дочернего ресурса первым параметром. | |
332 | |
263 =head2 C<[get]list> | 333 =head2 C<[get]list> |
264 | 334 |
335 Описание метода для получения списка дочерних объектов. По умолчанию не | |
336 получает параметров. | |
337 | |
265 =head2 C<[get]insert> | 338 =head2 C<[get]insert> |
266 | 339 |
340 Описание метода для добавление дочернего ресурса. По умолчанию получает | |
341 объект C<CGI> описывабщий текущий запрос первым параметром. | |
342 | |
267 =head2 C<[get]update> | 343 =head2 C<[get]update> |
268 | 344 |
345 Описание метода для обновления дочернего ресурса. По умолчанию получает | |
346 идентификатор дочернего ресурса и объект C<CGI> текущего запроса. | |
347 | |
269 =head2 C<[get]delete> | 348 =head2 C<[get]delete> |
270 | 349 |
350 Описание метода для удаления дочернего ресурса. По умолчанию получает | |
351 идентификатор дочернего ресурса. | |
352 | |
271 =head2 C<GetImpl($child,$action)> | 353 =head2 C<GetImpl($child,$action)> |
272 | 354 |
355 =over | |
356 | |
357 =item C<$child> | |
358 | |
359 Идентификатор дочернего ресутсра | |
360 | |
361 =item C<$action> | |
362 | |
363 Текущий запрос C<IMPL::Web::Application::Action>. | |
364 | |
365 =back | |
366 | |
367 Переадресует запрос нужному методу внутреннего объекта C<target> при | |
368 помощи C<InvokeMember>. | |
369 | |
273 =head2 C<PutImpl($child,$action)> | 370 =head2 C<PutImpl($child,$action)> |
274 | 371 |
372 =over | |
373 | |
374 =item C<$child> | |
375 | |
376 Идентификатор дочернего ресутсра | |
377 | |
378 =item C<$action> | |
379 | |
380 Текущий запрос C<IMPL::Web::Application::Action>. | |
381 | |
382 =back | |
383 | |
384 Переадресует запрос нужному методу внутреннего объекта C<target> при | |
385 помощи C<InvokeMember>. | |
386 | |
275 =head2 C<PostImpl($child,$action)> | 387 =head2 C<PostImpl($child,$action)> |
276 | 388 |
389 =over | |
390 | |
391 =item C<$child> | |
392 | |
393 Идентификатор дочернего ресутсра | |
394 | |
395 =item C<$action> | |
396 | |
397 Текущий запрос C<IMPL::Web::Application::Action>. | |
398 | |
399 =back | |
400 | |
401 Переадресует запрос нужному методу внутреннего объекта C<target> при | |
402 помощи C<InvokeMember>. | |
403 | |
277 =head2 C<DeleteImpl($child,$action)> | 404 =head2 C<DeleteImpl($child,$action)> |
278 | 405 |
406 =over | |
407 | |
408 =item C<$child> | |
409 | |
410 Идентификатор дочернего ресутсра | |
411 | |
412 =item C<$action> | |
413 | |
414 Текущий запрос C<IMPL::Web::Application::Action>. | |
415 | |
416 =back | |
417 | |
418 Переадресует запрос нужному методу внутреннего объекта C<target> при | |
419 помощи C<InvokeMember>. | |
420 | |
279 =head2 C<InvokeMember($memberInfo,$child,$action)> | 421 =head2 C<InvokeMember($memberInfo,$child,$action)> |
280 | 422 |
423 =over | |
424 | |
425 =item C<$memberInfo> | |
426 | |
427 Описание члена внутреннего объекта C<target>, который нужно вызвать. | |
428 | |
429 =item C<$child> | |
430 | |
431 Идентификатор дочернего ресутсра | |
432 | |
433 =item C<$action> | |
434 | |
435 Текущий запрос C<IMPL::Web::Application::Action>. | |
436 | |
437 =back | |
438 | |
439 Вызывает метод внутреннего объекта C<target>, предварительно подготовив | |
440 параметры на основе описания C<$memberInfo> и при помощи С<MakeParameter()>. | |
441 | |
442 =head2 C<MakeParameter($paramDef,$child,$action)> | |
443 | |
444 =over | |
445 | |
446 =item C<$paramDef> | |
447 | |
448 Описание параметра, может быть C<IMPL::Transform> или простая строка. | |
449 | |
450 Если описание параметра - простая строка, то ее имя либо | |
451 | |
452 =over | |
453 | |
454 =item C<id> | |
455 | |
456 Идентификатор дочернего ресурса | |
457 | |
458 =item C<query> | |
459 | |
460 Объект C<CGI> текущего запроса | |
461 | |
462 =item C<action> | |
463 | |
464 Текущий запрос C<IMPL::Web::Application::Action> | |
465 | |
466 =item C<любое другое значение> | |
467 | |
468 Интерпретируется как параметр текущего запроса. | |
469 | |
470 =back | |
471 | |
472 Если описание параметра - объект C<IMPL::Transform>, то будет выполнено это преобразование над C<CGI> | |
473 объектом текущего запроса C<< $paramDef->Transform($action->query) >>. | |
474 | |
475 =back | |
476 | |
281 =cut | 477 =cut |