Mercurial > pub > Impl
comparison Lib/IMPL/Web/Application/RestResource.pm @ 200:a9dbe534d236
sync
author | sergey |
---|---|
date | Tue, 24 Apr 2012 02:34:49 +0400 |
parents | e743a8481327 |
children | 0c018a247c8a |
comparison
equal
deleted
inserted
replaced
199:e743a8481327 | 200:a9dbe534d236 |
---|---|
5 use IMPL::Exception(); | 5 use IMPL::Exception(); |
6 | 6 |
7 use IMPL::declare { | 7 use IMPL::declare { |
8 require => { | 8 require => { |
9 ForbiddenException => 'IMPL::Web::ForbiddenException', | 9 ForbiddenException => 'IMPL::Web::ForbiddenException', |
10 NotFoundException => 'IMPL::Web::NotFoundException', | |
10 InvalidOpException => '-IMPL::InvalidOperationException', | 11 InvalidOpException => '-IMPL::InvalidOperationException', |
11 ArgumentException => '-IMPL::InvalidArgumentException', | 12 ArgumentException => '-IMPL::InvalidArgumentException', |
12 TTransform => '-IMPL::Transform', | 13 TTransform => '-IMPL::Transform', |
13 TResolve => '-IMPL::Config::Resolve' | 14 TResolve => '-IMPL::Config::Resolve', |
15 CustomResource => 'IMPL::Web::Application::CustomResource' | |
14 }, | 16 }, |
15 base => { | 17 base => { |
16 'IMPL::Object' => undef, | 18 'IMPL::Web::Application::RestBaseResource' => '@_' |
17 'IMPL::Object::Autofill' => '@_' | |
18 } | 19 } |
19 }; | 20 }; |
20 | 21 |
21 BEGIN { | 22 BEGIN { |
22 public property id => PROP_GET | PROP_OWNERSET; | |
23 public property target => PROP_GET | PROP_OWNERSET; | 23 public property target => PROP_GET | PROP_OWNERSET; |
24 public property parent => PROP_GET | PROP_OWNERSET; | 24 |
25 public property methods => PROP_GET | PROP_OWNERSET; | 25 public property methods => PROP_GET | PROP_OWNERSET; |
26 | |
26 public property childRegex => PROP_GET | PROP_OWNERSET; | 27 public property childRegex => PROP_GET | PROP_OWNERSET; |
27 public property enableForms => PROP_GET | PROP_OWNERSET; | 28 public property enableForms => PROP_GET | PROP_OWNERSET; |
28 public property list => PROP_GET | PROP_OWNERSET; | 29 public property orphan => PROP_GET | PROP_OWNERSET; |
29 public property fetch => PROP_GET | PROP_OWNERSET; | 30 |
30 public property insert => PROP_GET | PROP_OWNERSET; | 31 public property listChildren => PROP_GET | PROP_OWNERSET; |
31 public property update => PROP_GET | PROP_OWNERSET; | 32 public property fetchChild => PROP_GET | PROP_OWNERSET; |
32 public property delete => PROP_GET | PROP_OWNERSET; | 33 public property createChild => PROP_GET | PROP_OWNERSET; |
34 public property updateChild => PROP_GET | PROP_OWNERSET; | |
35 public property deleteChild => PROP_GET | PROP_OWNERSET; | |
33 } | 36 } |
34 | 37 |
35 sub CTOR { | 38 sub CTOR { |
36 my ($this) = @_; | 39 my ($this) = @_; |
37 | 40 |
38 die ArgumentException->new("id","Identifier is required for non-root resources") if $this->id and not length $this->id; | 41 die ArgumentException->new("id","Identifier is required for non-root resources") if $this->id and not length $this->id; |
39 die ArgumentException->new("target") unless $this->target; | 42 die ArgumentException->new("target") unless $this->target; |
40 | 43 die ArgumentException->new("A contract is required") unless $this->contract; |
41 if ($this->enableForms && $this->parent) { | 44 |
42 $this->methods({}) unless $this->methods; | 45 if ($this->enableForms) { |
43 | 46 |
44 if ($this->insert) { | 47 } |
45 $this->methods->{create} = { | |
46 get => sub { | |
47 my ($that,$id,$action) = @_; | |
48 return $that->target; | |
49 } | |
50 }; | |
51 } | |
52 | |
53 if ($this->parent->update) { | |
54 $this->methods->{edit} = { | |
55 get => sub { | |
56 my ($that,$id,$action) = @_; | |
57 return $that->target; | |
58 }, | |
59 post => sub { | |
60 my ($that,$id,$action) = @_; | |
61 return $that->parent->PutImpl($that->id,$action); | |
62 } | |
63 }; | |
64 } | |
65 | |
66 if ($this->parent->delete) { | |
67 $this->methods->{delete} = { | |
68 get => sub { | |
69 my ($that,$id,$action) = @_; | |
70 return $that->target; | |
71 }, | |
72 post => sub { | |
73 my ($that,$id,$action) = @_; | |
74 return $that->parent->DeleteImpl($that->id,$action); | |
75 } | |
76 }; | |
77 } | |
78 } | |
79 } | |
80 | |
81 sub GetHttpImpl { | |
82 my($this,$method) = @_; | |
83 | |
84 my %map = ( | |
85 GET => 'GetImpl', | |
86 PUT => 'PutImpl', | |
87 POST => 'PostImpl', | |
88 DELETE => 'DeleteImpl' | |
89 ); | |
90 | |
91 return $map{$method}; | |
92 } | |
93 | |
94 sub InvokeHttpMethod { | |
95 my ($this,$method,$childId,$action) = @_; | |
96 | |
97 my $impl = $this->GetHttpImpl($method) || 'HttpFallbackImpl'; | |
98 | |
99 return $this->$impl($childId,$action); | |
100 } | 48 } |
101 | 49 |
102 sub GetImpl { | 50 sub GetImpl { |
103 my ($this,$id,$action) = @_; | 51 my ($this,$action) = @_; |
104 | 52 |
105 my $rx; | 53 return $this->target; |
106 my $method; | |
107 if (length $id == 0) { | |
108 $method = $this->list or die ForbiddenException->new(); | |
109 } elsif ($this->methods and $method = $this->methods->{$id}->{get}) { | |
110 # we got method info | |
111 } elsif($rx = $this->childRegex and $id =~ m/$rx/ ) { | |
112 $method = $this->fetch or die ForbiddenException->new(); | |
113 | |
114 $method = { | |
115 method => $method, | |
116 parameters => [qw(id)] | |
117 } unless ref $method; | |
118 | |
119 } else { | |
120 die ForbiddenException->new(); | |
121 } | |
122 | |
123 return $this->InvokeMember($method,$id,$action); | |
124 } | 54 } |
125 | 55 |
126 sub PutImpl { | 56 sub PutImpl { |
127 my ($this,$id,$action) = @_; | 57 my ($this,$action) = @_; |
128 | 58 |
129 my $rx = $this->childRegex; | 59 die ForbiddenException->new() if $this->orhpan; |
130 if ( $rx and $id =~ m/$rx/ and $this->update ) { | 60 |
131 my $method = $this->update or die ForbiddenException->new(); | 61 $this->parent->UpdateImpl($this->id,$action); |
132 | |
133 $method = { | |
134 method => $method, | |
135 parameters => [qw(id query)] | |
136 } unless ref $method; | |
137 | |
138 return $this->InvokeMember($method,$id,$action); | |
139 } else { | |
140 die ForbiddenException->new(); | |
141 } | |
142 } | 62 } |
143 | 63 |
144 sub PostImpl { | 64 sub PostImpl { |
145 my ($this,$id,$action) = @_; | 65 my ($this,$id,$action) = @_; |
146 | 66 |
179 } | 99 } |
180 } | 100 } |
181 | 101 |
182 sub HttpFallbackImpl { | 102 sub HttpFallbackImpl { |
183 die ForbiddenException->new(); | 103 die ForbiddenException->new(); |
104 } | |
105 | |
106 sub UpdateImpl { | |
107 my ($this,$id,$action) = @_; | |
108 | |
109 my $method = $this->updateChild or die ForbiddenException->new(); | |
110 $this->InvokeMember($method,$action); | |
111 } | |
112 | |
113 sub FetchChildResource { | |
114 my ($this,$id,$action) = @_; | |
115 | |
116 my $rx = $this->childRegex; | |
117 my $method; | |
118 my %params = ( | |
119 parent => $this, | |
120 id => $id | |
121 ); | |
122 | |
123 if (length $id == 0) { | |
124 | |
125 $method = $this->list; | |
126 die ForbiddenException->new() unless $method; | |
127 | |
128 return $this->contract->Transform( $this->InvokeMember($method,$id,$action), \%params ); | |
129 | |
130 } elsif ($method = $this->methods->{$id}) { | |
131 # поскольку данный объект был получен не как дочерний объект, | |
132 # а как выполнение метода, то для него не определены операции | |
133 # put и delete по умолчанию. | |
134 $params{orphan} = 1; | |
135 | |
136 return $this->contract->Transform( $this->InvokeMember($method,$id,$action), \%params ); | |
137 | |
138 } elsif ($rx and $id =~ m/^$rx$/ and $method = $this->fetch) { | |
139 # ok | |
140 } else { | |
141 die ForbiddenException->new(); | |
142 } | |
143 | |
144 my $res = $this->InvokeMember($method,$id,$action); | |
145 die NotFoundException->new() unless defined $res; | |
146 | |
147 return $this->contract->Transform($res, {parent => $this, id => $id} ); | |
184 } | 148 } |
185 | 149 |
186 sub InvokeMember { | 150 sub InvokeMember { |
187 my ($this,$method,$id,$action) = @_; | 151 my ($this,$method,$id,$action) = @_; |
188 | 152 |
330 | 294 |
331 =head1 DESCRIPTION | 295 =head1 DESCRIPTION |
332 | 296 |
333 Каждый ресурс представляет собой коллекцию и реализует методы C<HTTP> C<GET,POST,PUT,DELETE>. | 297 Каждый ресурс представляет собой коллекцию и реализует методы C<HTTP> C<GET,POST,PUT,DELETE>. |
334 | 298 |
299 Ресурсы выстраиваются в иерархию, на основе пути. Поиск конечного реурса происходит последовательным | |
300 вызовом метода GET с именем очередного ресурса. | |
301 | |
302 | |
335 =head2 HTTP METHODS | 303 =head2 HTTP METHODS |
336 | 304 |
337 =head3 C<GET> | 305 =head3 C<GET> |
338 | 306 |
339 Возвращает коллекцию дочерних ресурсов. | 307 Возвращает коллекцию дочерних ресурсов. |
371 изменения в объекты. | 339 изменения в объекты. |
372 | 340 |
373 =head1 BROWSER COMPATIBILITY | 341 =head1 BROWSER COMPATIBILITY |
374 | 342 |
375 Однако существует проблема с браузерами, поскольку тег C<< <form> >> реализет только методы | 343 Однако существует проблема с браузерами, поскольку тег C<< <form> >> реализет только методы |
376 C<GET,POST>. Для решения данной проблемы используется режим совместимости C<compatible>. В | 344 C<GET,POST>. Для решения данной проблемы используется режим совместимости C<enableForms>. В |
377 случае когда данный режим активен, автоматически публикуются дочерние C<create,edit,delete>. | 345 случае когда данный режим активен, автоматически публикуются дочерние ресурсы C<create,edit,delete>. |
378 | 346 |
379 =head2 C<GET create> | 347 =head2 C<GET create> |
380 | 348 |
381 Возвращает C<target>. | 349 Возвращает C<target>. |
382 | 350 |