comparison 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
comparison
equal deleted inserted replaced
228:431db7034a88 229:47f77e6409f7
1 package IMPL::Web::Application::OperationContract; 1 package IMPL::Web::Application::OperationContract;
2 use strict; 2 use strict;
3 3
4 use IMPL::lang qw(:declare);
4 use IMPL::declare { 5 use IMPL::declare {
5 base => [ 6 require => {
6 'IMPL::Object' => undef, 7 'Exception' => 'IMPL::Exception',
7 'IMPL::Object::Autofill' => '@_' 8 'ArgumentException' => '-IMPL::ArgumentException',
8 ], 9 'ResourceBaseClass' => 'IMPL::Web::Application::ResourceBase'
9 props => [ 10 },
10 binding => PROP_ALL, 11 base => [
11 response => PROP_ALL 12 'IMPL::Object' => undef,
12 ] 13 'IMPL::Object::Autofill' => '@_'
14 ],
15 props => [
16 binding => PROP_ALL,
17 success => PROP_ALL,
18 error => PROP_ALL
19 ]
13 }; 20 };
14 21
15 sub Invoke { 22 sub Invoke {
16 my ($this, $resource, $httpAction) = @_; 23 my ( $this, $resource, $request ) = @_;
24
25 die ArgumentException( resource => 'A valid resource is required' )
26 unless eval { $resource->isa(ResourceBaseClass) };
27
28 my $result = eval {
29 _InvokeDelegate($this->binding, $resource, $request)
30 };
17 31
18 if ($this->) 32 if (my $e = $@) {
33 $result = _InvokeDelegate($this->error, $resource, $request, $e);
34 } else {
35 $result = _InvokeDelegate($this->success, $resource, $request, $result);
36 }
37
38 return $result;
39 }
40
41 sub _InvokeDelegate {
42 my $delegate = shift;
19 43
44 return $delegete->(@_) if ref $delegate eq 'CODE';
45 return $delegate->Invoke(@_) if eval { $delegate->can('Invoke')};
20 } 46 }
21 47
22 1; 48 1;
23 49
24 __END__ 50 __END__
38 'OperationContract' => 'IMPL::Web::Application::OperationContract', 64 'OperationContract' => 'IMPL::Web::Application::OperationContract',
39 'RedirectResponse' => 'IMPL::Web::Application::RedirectResponse' 65 'RedirectResponse' => 'IMPL::Web::Application::RedirectResponse'
40 }; 66 };
41 67
42 my $operation = OperationContract->new( 68 my $operation = OperationContract->new(
43 bind => sub { 69 binding => sub {
44 my ($resource,$model,$itemName) = @_; 70 my ($resource,$request) = @_;
45 71
46 return $model->findItem($itemName); 72 my $itemName = $request->param('itemName', qr/^(\w+)$/);
73
74 return $model->FindItem($itemName);
47 }, 75 },
48 response => RedirectResponse->new( 76 success => sub {
49 locator => $relativeLocator 77 my ($resource,$request,$result) = @_;
50 ) 78 return HttpReponse->Redirect(location => $resource->location->Child($result->id));
79 }
51 ); 80 );
52 81
53 my $response = $operation->InvokeOperation($resource); 82 my $response = $operation->InvokeOperation($resource);
54 83
55 =end code 84 =end code
56 85
57 =head1 DESCRIPTION 86 =head1 DESCRIPTION
58 87
59 Связывает методы предметной области с операциями над ресурсами. Для связи с 88 Для орисания контракта операции используется понятие делегата, тоесть объекта,
60 моделью используется функция, которой будут переданы параметры: 89 представляющего собой функцию, либо объект, имеющий метод C<Invoke>.
90
91 Поскольку предметная область должна быть отделена от
92 контроллеров веб-сервиса, она ничего не знает про существование ресурсов и их
93 организацию и тем более о протоколе C<HTTP>, поэтому все вещи, связанные с
94 формированием ответов сервера, представлениями данных и т.п. должны выполняться
95 самими контроллерами. Поведение контроллеров описывается контрактами, в которых
96 указываются делегаты для реализации необходимого функционала, для корректного
97 отображения ресурсов в объекты предметной области и обратно.
98
99 Контракт операции состоит из нескольких свойств, осуществляющих привязку к
100 предметной области:
61 101
62 =over 102 =over
63 103
64 =item C<$reousrce> Ресурс для которого выполняется операция 104 =item * C<binding>
65 105
66 =item C<$model> Объект модели данных, связанный с данным ресурсом, тоже, что 106 делегат для привязки операции над ресурсом к предметной области.
67 и C<<>$resource->model>> только для краткости
68 107
69 =item C<$action> Контекст текущего C<HTTP> запроса. 108 =item * C<success>
70 109
71 =back 110 делегат для обработки результат операции, например для формирования ответа с
111 перенаправлением.
72 112
73 Результат выполнения будет передан дополнительному обработчику C<response>, 113 =item * C<error>
74 который выполнит необходимое преобразование. 114
115 делегат для обработки исключительной ситуации, может быть использован для
116 формирования представления для повторного ввода данных на форме.
117
118 =back
75 119
76 =head1 MEMBERS 120 =head1 MEMBERS
77 121
122 =head2 C<[get,set] binding>
123
124 Привязка операции к ресурсу, например
125
126 =begin code
127
128 $operationContract->binding(sub {
129 my ($resource,$action) = @_;
130 $resource->model
131 })
132
133 =end code
134
135 Может быть как ссылка на процедуру, так и ссылкой на объект, имеющий метод
136 C<Invoke>.
137
138 =head2 C<[get,set] success>
139
140 Обрабатывает результат привязки к предметной области.
141
142 =begin code
143
144 # redirect (for example after POST)
145 $operationContract->success(sub {
146 my ($resource,$action,$result) = @_;
147
148 return IMPL::Web::HttpResponse
149 ->Redirect($resource->location->Child($result->id));
150 })
151
152 =end code
153
154 Может быть как ссылка на процедуру, так и ссылкой на объект, имеющий метод
155 C<Invoke>.
156
157 =head2 C<[get,set] error>
158
159 Обрабатывает ошибку возникшую при выполнении привязки к предметной области.
160
161 =begin
162
163 $operationContract->error(sub {
164 my ($resource,$action,$error) = @_;
165
166 $action->form->errors->{''} = $error;
167
168 return $resource->model;
169 });
170
171 =end
172
78 =cut 173 =cut