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 |
