Mercurial > pub > Impl
comparison Lib/IMPL/Web/Application/Resource.pm @ 229:47f77e6409f7
heavily reworked the resource model of the web application:
*some ResourcesContraact functionality moved to Resource
+Added CustomResource
*Corrected action handlers
| author | sergey |
|---|---|
| date | Sat, 29 Sep 2012 02:34:47 +0400 |
| parents | |
| children | 6d8092d8ce1b |
comparison
equal
deleted
inserted
replaced
| 228:431db7034a88 | 229:47f77e6409f7 |
|---|---|
| 1 package IMPL::Web::Application::Resource; | |
| 2 use strict; | |
| 3 | |
| 4 use IMPL::lang qw(:constants); | |
| 5 use IMPL::declare { | |
| 6 require => { | |
| 7 Exception => 'IMPL::Exception', | |
| 8 ArgumentException => '-IMPL::InvalidArgumentException', | |
| 9 OperationException => '-IMPL::InvalidOperationException', | |
| 10 NotAllowedException => 'IMPL::Web::NotAllowedException', | |
| 11 NotFoundException => 'IMPL::Web::NotFoundException' | |
| 12 }, | |
| 13 base => [ | |
| 14 'IMPL::Object' => undef, | |
| 15 'IMPL::Web::Application::ResourceInterface' => undef | |
| 16 ], | |
| 17 props => [ | |
| 18 parent => PROP_GET | PROP_OWNERSET, | |
| 19 model => PROP_GET | PROP_OWNERSET, | |
| 20 id => PROP_GET | PROP_OWNERSET, | |
| 21 contract => PROP_GET | PROP_OWNERSET, | |
| 22 location => PROP_GET | PROP_OWNERSET | |
| 23 ] | |
| 24 }; | |
| 25 | |
| 26 sub CTOR { | |
| 27 my ( $this, %args ) = @_; | |
| 28 | |
| 29 die ArgumentException->new( id => 'A resource identifier is required' ) | |
| 30 unless $args{id}; | |
| 31 die ArgumentException->new( contract => 'A contract is required' ) | |
| 32 unless $args{id}; | |
| 33 | |
| 34 $this->parent( $args{parent} ); | |
| 35 $this->model( $args{model} ); | |
| 36 $this->id( $args{id} ); | |
| 37 $this->contract( $args{contract} ); | |
| 38 | |
| 39 # если расположение явно не указано, что обычно делается для корневого | |
| 40 # ресурса, то оно вычисляется автоматически, либо остается не заданным | |
| 41 $this->location( $args{location} | |
| 42 || eval { $this->parent->location->Child( $this->id ) } ); | |
| 43 ) | |
| 44 | |
| 45 } | |
| 46 | |
| 47 sub InvokeHttpVerb { | |
| 48 my ( $this, $verb, $action ) = @_; | |
| 49 | |
| 50 my $verb = $this->contract->verbs->{ lc($verb) }; | |
| 51 | |
| 52 die NotAllowedException->new( | |
| 53 allow => join( ',' map( uc, keys %{ $this->contract->verbs } ) ) ) | |
| 54 unless $verb; | |
| 55 | |
| 56 return $verb->Invoke( $this, $action ); | |
| 57 } | |
| 58 | |
| 59 # это реализация по умолчанию, базируется информации о ресурсах, содержащийся | |
| 60 # в контракте. | |
| 61 sub FetchChildResource { | |
| 62 my ( $this, $childId ) = @_; | |
| 63 | |
| 64 my $info = $this->contract->FindChildResourceInfo($childId); | |
| 65 | |
| 66 die NotFoundException->new() unless $info; | |
| 67 | |
| 68 my $binding = $this->{binding}; | |
| 69 my $contract = $this->{contract} | |
| 70 or die OperationException->new("Can't fetch a contract for the resource", $childId); | |
| 71 | |
| 72 my %args = ( | |
| 73 parent => $this, | |
| 74 id => $childId | |
| 75 ); | |
| 76 | |
| 77 $args{model} = _InvokeDelegate($binding,$this); | |
| 78 | |
| 79 return $contract->CreateResource(%args); | |
| 80 } | |
| 81 | |
| 82 sub _InvokeDelegate { | |
| 83 my $delegate = shift; | |
| 84 | |
| 85 return $delegete->(@_) if ref $delegate eq 'CODE'; | |
| 86 return $delegate->Invoke(@_) if eval { $delegate->can('Invoke')}; | |
| 87 } | |
| 88 | |
| 89 1; | |
| 90 | |
| 91 __END__ | |
| 92 | |
| 93 =pod | |
| 94 | |
| 95 =head1 NAME | |
| 96 | |
| 97 C<IMPL::Web::Application::Resource> - Web-ресурс. | |
| 98 | |
| 99 =head1 SYNOPSIS | |
| 100 | |
| 101 Класс для внутреннего использования. Объединяет в себе контракт и модель данных. | |
| 102 Основная задача - обработать поступающий от контроллера запрос на вызов C<HTTP> | |
| 103 метода. | |
| 104 | |
| 105 Экземпляры данного класса передаются в качестве параметров делегатам | |
| 106 осуществляющим привязку к модели в C<IMPL::Web::Application::ResourceContract> | |
| 107 и C<IMPL::Web::Application::OperationContract>. | |
| 108 | |
| 109 =head1 DESCRIPTION | |
| 110 | |
| 111 Весь функционал ресурса, поддерживаемые им C<HTTP> методы определяются | |
| 112 контрактом. Однако можно реализовывать ресурсы, которые не имеют контракта | |
| 113 или он отличается от того, что предоставляется стандартно | |
| 114 C<IMPL::Web::Application::ResourceContract>. | |
| 115 | |
| 116 Каждый ресурс является контейнером, тоесть позволяет получить дочерний ресурс | |
| 117 по идентифифкатору, если таковой имеется, тоесть ресурс, у которого нет дочерних | |
| 118 ресурсов на самом деле рассматривается как пустой контейнер. | |
| 119 | |
| 120 С ресурсом непосредственно взаимодействует котроллер запросов | |
| 121 C<IMPL::Web::Handler::RestController>, вызывая два метода. | |
| 122 | |
| 123 =over | |
| 124 | |
| 125 =item * C<FetchChildResource($childId)> | |
| 126 | |
| 127 Данный метод возвращает дочерний ресурс, соответствующий C<$childId>. | |
| 128 Текущая реализация использует метод C<FindChildResourceInfo> контракта текущего | |
| 129 ресурса, после чего создает дочерний ресурс. | |
| 130 | |
| 131 Если дочерний ресурс не найден, вызывается исключение | |
| 132 C<IMPL::Web::NotFoundException>. | |
| 133 | |
| 134 =item * C<InvokeHttpVerb($verb,$action)> | |
| 135 | |
| 136 Обрабатывает запрос к ресурсу. Для этого используется контракт ресурса, в | |
| 137 нем выбирается соответсвующий C<IMPL::Web::Application::OperationContract>. | |
| 138 Затем найденный контракт для указанной операции используется для обработки | |
| 139 запроса. | |
| 140 | |
| 141 =back | |
| 142 | |
| 143 Если объект реализует два вышеуказанных метода, он является веб-ресурсом, а | |
| 144 детали его реализации, котнракт и прочее уже не важно, поэтому можно реализовать | |
| 145 собственный класс ресурса, например унаследованный от | |
| 146 C<IMPL::Web::Application::CustomResource>. | |
| 147 | |
| 148 =cut |
