Mercurial > pub > Impl
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 |