Mercurial > pub > Impl
view Lib/IMPL/Web/Application/OperationContract.pm @ 308:47a09a8dc23a
sync
author | sergey |
---|---|
date | Thu, 18 Apr 2013 20:06:05 +0400 |
parents | 4abda21186cd |
children |
line wrap: on
line source
package IMPL::Web::Application::OperationContract; use strict; use IMPL::lang qw(:declare); use IMPL::declare { require => { Exception => 'IMPL::Exception', ArgumentException => '-IMPL::InvalidArgumentException', ResourceInterface => 'IMPL::Web::Application::ResourceInterface' }, base => [ 'IMPL::Object' => undef, 'IMPL::Object::Autofill' => '@_' ], props => [ binding => PROP_ALL, success => PROP_ALL, error => PROP_ALL ] }; sub Invoke { my ( $this, $resource, $request ) = @_; die ArgumentException->new( resource => 'A valid resource is required' ) unless eval { $resource->isa(ResourceInterface) }; my $result = eval { _InvokeDelegate($this->binding, $resource, $request) }; if (my $e = $@) { if ($this->error) { $result = _InvokeDelegate($this->error, $resource, $request, $e) ; } else { die $e; } } else { $result = _InvokeDelegate($this->success, $resource, $request, $result) if ($this->success); } return $result; } sub _InvokeDelegate { my $delegate = shift; return $delegate->(@_) if ref $delegate eq 'CODE'; return $delegate->Invoke(@_) if eval { $delegate->can('Invoke')}; } 1; __END__ =pod =head1 NAME C<IMPL::Web::Application::OperationContract> - Описание операции над веб-ресурсом. =head1 SYNOPSIS =begin code use IMPL::require { 'OperationContract' => 'IMPL::Web::Application::OperationContract', 'HttpReponse' => 'IMPL::Web::Application::HttpReponse' }; my $operation = OperationContract->new( binding => sub { my ($resource,$request) = @_; my $itemName = $request->param('itemName', qr/^(\w+)$/); return $model->FindItem($itemName); }, success => sub { my ($resource,$request,$result) = @_; return HttpReponse->Redirect(location => $resource->location->Child($result->id)); } ); my $response = $operation->InvokeOperation($resource); =end code =head1 DESCRIPTION Для описания контракта операции используется понятие делегата, тоесть объекта, представляющего собой функцию, либо объект, имеющий метод C<Invoke>. Поскольку предметная область должна быть отделена от контроллеров веб-сервиса, она ничего не знает про существование ресурсов и их организацию и тем более о протоколе C<HTTP>, поэтому все вещи, связанные с формированием ответов сервера, представлениями данных и т.п. должны выполняться самими контроллерами. Поведение контроллеров описывается контрактами, в которых указываются делегаты для реализации необходимого функционала, для корректного отображения ресурсов в объекты предметной области и обратно. Контракт операции состоит из нескольких свойств, осуществляющих привязку к предметной области: =over =item * C<binding> делегат для привязки операции над ресурсом к предметной области. =item * C<success> делегат для обработки результат операции, например для формирования ответа с перенаправлением. =item * C<error> делегат для обработки исключительной ситуации, может быть использован для формирования представления для повторного ввода данных на форме. =back =head1 MEMBERS =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