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