Mercurial > pub > Impl
comparison Lib/IMPL/Web/Application/RestResource.pm @ 201:0c018a247c8a
Reworked REST resource classes to be more transparent and intuitive
author | sergey |
---|---|
date | Tue, 24 Apr 2012 19:52:07 +0400 |
parents | a9dbe534d236 |
children | 5146e17a7b76 |
comparison
equal
deleted
inserted
replaced
200:a9dbe534d236 | 201:0c018a247c8a |
---|---|
13 TTransform => '-IMPL::Transform', | 13 TTransform => '-IMPL::Transform', |
14 TResolve => '-IMPL::Config::Resolve', | 14 TResolve => '-IMPL::Config::Resolve', |
15 CustomResource => 'IMPL::Web::Application::CustomResource' | 15 CustomResource => 'IMPL::Web::Application::CustomResource' |
16 }, | 16 }, |
17 base => { | 17 base => { |
18 'IMPL::Web::Application::RestBaseResource' => '@_' | 18 'IMPL::Web::Application::RestCustomResource' => '@_' |
19 } | 19 } |
20 }; | 20 }; |
21 | 21 |
22 BEGIN { | 22 BEGIN { |
23 public property target => PROP_GET | PROP_OWNERSET; | 23 public property target => PROP_GET | PROP_OWNERSET; |
24 public property index => PROP_GET | PROP_OWNERSET; | |
25 public property fetch => PROP_GET | PROP_OWNERSET; | |
24 | 26 |
25 public property methods => PROP_GET | PROP_OWNERSET; | 27 public property methods => PROP_GET | PROP_OWNERSET; |
26 | 28 |
27 public property childRegex => PROP_GET | PROP_OWNERSET; | 29 public property childRegex => PROP_GET | PROP_OWNERSET; |
28 public property enableForms => PROP_GET | PROP_OWNERSET; | 30 public property enableForms => PROP_GET | PROP_OWNERSET; |
29 public property orphan => PROP_GET | PROP_OWNERSET; | 31 |
30 | |
31 public property listChildren => PROP_GET | PROP_OWNERSET; | |
32 public property fetchChild => 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; | |
36 } | 32 } |
37 | 33 |
38 sub CTOR { | 34 sub CTOR { |
39 my ($this) = @_; | 35 my ($this) = @_; |
40 | 36 |
41 die ArgumentException->new("id","Identifier is required for non-root resources") if $this->id and not length $this->id; | |
42 die ArgumentException->new("target") unless $this->target; | 37 die ArgumentException->new("target") unless $this->target; |
43 die ArgumentException->new("A contract is required") unless $this->contract; | 38 |
39 $this->final($this->childRegex ? 0 : 1); | |
44 | 40 |
45 if ($this->enableForms) { | 41 if ($this->enableForms) { |
42 $this->methods->{create} = { | |
43 get => \&_ParentGet, | |
44 post => \&_ParentPost, | |
45 final => 1 # this resource doesn't have any children | |
46 }; | |
47 | |
48 $this->methods->{edit} = { | |
49 get => \&_ParentGet, | |
50 post => \&_ParentPut, | |
51 final => 1 # this resource doesn't have any children | |
52 }; | |
53 | |
54 $this->methods->{delete} { | |
55 get => \&_ParentGet, | |
56 post => \&_ParentDelete | |
57 final => 1 # this resource doesn't have any children | |
58 } | |
59 } | |
60 } | |
61 | |
62 sub _ParentGet { | |
63 my ($this,$action) = @_; | |
64 return $this->parent->GetImpl($action); | |
65 } | |
66 | |
67 sub _ParentPut { | |
68 my ($this,$action) = @_; | |
69 return $this->parent->PutImpl($action); | |
70 } | |
71 | |
72 sub _ParentPost { | |
73 my ($this,$action) = @_; | |
74 return $this->parent->PostImpl($action); | |
75 } | |
76 | |
77 sub _ParentDelete { | |
78 my ($this,$action) = @_; | |
79 return $this->parent->DeleteImpl($action); | |
80 } | |
81 | |
82 sub FetchChildResource { | |
83 my ($this,$id,$action) = @_; | |
84 | |
85 my $rx = $this->childRegex; | |
86 | |
87 my $res; | |
88 | |
89 if (length $id == 0) { | |
46 | 90 |
47 } | 91 my $method = $this->index; |
48 } | 92 die ForbiddenException->new() unless $method; |
49 | |
50 sub GetImpl { | |
51 my ($this,$action) = @_; | |
52 | |
53 return $this->target; | |
54 } | |
55 | |
56 sub PutImpl { | |
57 my ($this,$action) = @_; | |
58 | |
59 die ForbiddenException->new() if $this->orhpan; | |
60 | |
61 $this->parent->UpdateImpl($this->id,$action); | |
62 } | |
63 | |
64 sub PostImpl { | |
65 my ($this,$id,$action) = @_; | |
66 | |
67 my $method; | |
68 | |
69 if (length $id == 0) { | |
70 $method = $this->insert or die ForbiddenException->new(); | |
71 | 93 |
72 $method = { | 94 $res = $this->InvokeMember($method,$action); |
73 method => $method, | 95 |
74 parameters => [qw(query)] | 96 } elsif (my $resource = $this->methods->{$id}) { |
75 } unless ref $method; | 97 return CustomResource->new( |
76 } elsif ($this->methods and $method = $this->methods->{$id}->{post}) { | 98 get => $resource->{get}, |
77 # we got method info | 99 post => $resource->{post}, |
100 put => $resource->{put}, | |
101 delete => $resource->{delete}, | |
102 parent => $this, | |
103 id => $id, | |
104 target => $this->target | |
105 ); | |
106 | |
107 } elsif ($rx and $id =~ m/^$rx$/ and $method = $this->fetch) { | |
108 $res = $this->InvokeMember($method,$action, { id => $id } ); | |
78 } else { | 109 } else { |
79 die ForbiddenException->new(); | 110 die ForbiddenException->new(); |
80 } | 111 } |
81 | 112 |
82 return $this->InvokeMemeber($method,$id,$action); | |
83 } | |
84 | |
85 sub DeleteImpl { | |
86 my ($this,$id,$action) = @_; | |
87 | |
88 my $rx = $this->childRegex; | |
89 if ($rx and $id =~ m/$rx/ and my $method = $this->delete) { | |
90 | |
91 $method = { | |
92 method => $method, | |
93 parameters => [qw(id)] | |
94 } unless ref $method; | |
95 | |
96 return $this->InvokeMember($method,$id,$action); | |
97 } else { | |
98 die ForbiddenException->new(); | |
99 } | |
100 } | |
101 | |
102 sub HttpFallbackImpl { | |
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; | 113 die NotFoundException->new() unless defined $res; |
146 | 114 |
147 return $this->contract->Transform($res, {parent => $this, id => $id} ); | 115 return $this->contract->Transform($res, {parent => $this, id => $id} ); |
148 } | 116 } |
149 | |
150 sub InvokeMember { | |
151 my ($this,$method,$id,$action) = @_; | |
152 | |
153 die ArgumentException->new("method","No method information provided") unless $method; | |
154 | |
155 #normalize method info | |
156 if (not ref $method) { | |
157 $method = { | |
158 method => $method | |
159 }; | |
160 } | |
161 | |
162 if (ref $method eq 'HASH') { | |
163 my $member = $method->{method} or die InvalidOpException->new("A member name isn't specified"); | |
164 my @args; | |
165 | |
166 if (my $params = $method->{parameters}) { | |
167 if (ref $params eq 'HASH') { | |
168 @args = map { | |
169 $_, | |
170 $this->MakeParameter($params->{$_},$id,$action) | |
171 } keys %$params; | |
172 } elsif (ref $params eq 'ARRAY') { | |
173 @args = map $this->MakeParameter($_,$id,$action), @$params; | |
174 } else { | |
175 @args = ($this->MakeParameter($params,$id,$action)); | |
176 } | |
177 } | |
178 return $this->target->$member(@args); | |
179 } elsif (ref $method eq TResolve) { | |
180 return $method->Invoke($this->target); | |
181 } elsif (ref $method eq 'CODE') { | |
182 return $method->($this,$id,$action); | |
183 } else { | |
184 die InvalidOpException->new("Unsupported type of the method information", ref $method); | |
185 } | |
186 } | |
187 | |
188 sub MakeParameter { | |
189 my ($this,$param,$id,$action) = @_; | |
190 | |
191 if ($param) { | |
192 if (is $param, TTransform ) { | |
193 return $param->Transform($this,$action->query); | |
194 } elsif ($param and not ref $param) { | |
195 my %std = ( | |
196 id => $id, | |
197 action => $action, | |
198 query => $action->query | |
199 ); | |
200 | |
201 return $std{$param} || $action->query->param($param); | |
202 } | |
203 } else { | |
204 return undef; | |
205 } | |
206 } | |
207 | |
208 | |
209 | |
210 | 117 |
211 1; | 118 1; |
212 | 119 |
213 __END__ | 120 __END__ |
214 | 121 |