Mercurial > pub > Impl
diff Lib/IMPL/Web/Application/OperationContract.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 | 431db7034a88 |
children | 6d8092d8ce1b |
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/OperationContract.pm Thu Sep 13 17:55:01 2012 +0400 +++ b/Lib/IMPL/Web/Application/OperationContract.pm Sat Sep 29 02:34:47 2012 +0400 @@ -1,22 +1,48 @@ package IMPL::Web::Application::OperationContract; use strict; +use IMPL::lang qw(:declare); use IMPL::declare { - base => [ - 'IMPL::Object' => undef, - 'IMPL::Object::Autofill' => '@_' - ], - props => [ - binding => PROP_ALL, - response => PROP_ALL - ] + require => { + 'Exception' => 'IMPL::Exception', + 'ArgumentException' => '-IMPL::ArgumentException', + 'ResourceBaseClass' => 'IMPL::Web::Application::ResourceBase' + }, + base => [ + 'IMPL::Object' => undef, + 'IMPL::Object::Autofill' => '@_' + ], + props => [ + binding => PROP_ALL, + success => PROP_ALL, + error => PROP_ALL + ] }; sub Invoke { - my ($this, $resource, $httpAction) = @_; + my ( $this, $resource, $request ) = @_; + + die ArgumentException( resource => 'A valid resource is required' ) + unless eval { $resource->isa(ResourceBaseClass) }; + + my $result = eval { + _InvokeDelegate($this->binding, $resource, $request) + }; - if ($this->) + if (my $e = $@) { + $result = _InvokeDelegate($this->error, $resource, $request, $e); + } else { + $result = _InvokeDelegate($this->success, $resource, $request, $result); + } + + return $result; +} + +sub _InvokeDelegate { + my $delegate = shift; + return $delegete->(@_) if ref $delegate eq 'CODE'; + return $delegate->Invoke(@_) if eval { $delegate->can('Invoke')}; } 1; @@ -40,14 +66,17 @@ }; my $operation = OperationContract->new( - bind => sub { - my ($resource,$model,$itemName) = @_; + binding => sub { + my ($resource,$request) = @_; + + my $itemName = $request->param('itemName', qr/^(\w+)$/); - return $model->findItem($itemName); + return $model->FindItem($itemName); }, - response => RedirectResponse->new( - locator => $relativeLocator - ) + success => sub { + my ($resource,$request,$result) = @_; + return HttpReponse->Redirect(location => $resource->location->Child($result->id)); + } ); my $response = $operation->InvokeOperation($resource); @@ -56,23 +85,89 @@ =head1 DESCRIPTION -Связывает методы предметной области с операциями над ресурсами. Для связи с -моделью используется функция, которой будут переданы параметры: +Для орисания контракта операции используется понятие делегата, тоесть объекта, +представляющего собой функцию, либо объект, имеющий метод C<Invoke>. + +Поскольку предметная область должна быть отделена от +контроллеров веб-сервиса, она ничего не знает про существование ресурсов и их +организацию и тем более о протоколе C<HTTP>, поэтому все вещи, связанные с +формированием ответов сервера, представлениями данных и т.п. должны выполняться +самими контроллерами. Поведение контроллеров описывается контрактами, в которых +указываются делегаты для реализации необходимого функционала, для корректного +отображения ресурсов в объекты предметной области и обратно. + +Контракт операции состоит из нескольких свойств, осуществляющих привязку к +предметной области: =over -=item C<$reousrce> Ресурс для которого выполняется операция +=item * C<binding> -=item C<$model> Объект модели данных, связанный с данным ресурсом, тоже, что -и C<<>$resource->model>> только для краткости +делегат для привязки операции над ресурсом к предметной области. + +=item * C<success> -=item C<$action> Контекст текущего C<HTTP> запроса. +делегат для обработки результат операции, например для формирования ответа с +перенаправлением. + +=item * C<error> -=back +делегат для обработки исключительной ситуации, может быть использован для +формирования представления для повторного ввода данных на форме. -Результат выполнения будет передан дополнительному обработчику C<response>, -который выполнит необходимое преобразование. +=back =head1 MEMBERS -=cut \ No newline at end of file +=head2 C<[get,set] binding> + +Привязка операции к ресурсу, например + +=begin code + +$operationContract->binding(sub { + my ($resource,$action) = @_; + $resource->model +}) + +=end code + +Может быть как ссылка на процедуру, так и ссылкой на объект, имеющий метод +C<Invoke>. + +=head2 C<[get,set] success> + +Обрабатывает результат привязки к предметной области. + +=begin code + +# redirect (for example after POST) +$operationContract->success(sub { + my ($resource,$action,$result) = @_; + + return IMPL::Web::HttpResponse + ->Redirect($resource->location->Child($result->id)); +}) + +=end code + +Может быть как ссылка на процедуру, так и ссылкой на объект, имеющий метод +C<Invoke>. + +=head2 C<[get,set] error> + +Обрабатывает ошибку возникшую при выполнении привязки к предметной области. + +=begin + +$operationContract->error(sub { + my ($resource,$action,$error) = @_; + + $action->form->errors->{''} = $error; + + return $resource->model; +}); + +=end + +=cut