110
|
1 package IMPL::Web::Application::ControllerUnit;
|
112
|
2 use strict;
|
110
|
3 use base qw(IMPL::Object);
|
|
4
|
|
5 use IMPL::Class::Property;
|
112
|
6 use IMPL::DOM::Transform::PostToDOM;
|
|
7 use IMPL::DOM::Schema;
|
|
8
|
|
9 use constant {
|
|
10 CONTROLLER_METHODS => 'controller_methods',
|
|
11 STATE_CORRECT => 'correct',
|
|
12 STATE_NEW => 'new',
|
|
13 STATE_INVALID => 'invalid'
|
|
14 };
|
110
|
15
|
|
16 BEGIN {
|
|
17 public property action => prop_get | owner_set;
|
|
18 public property application => prop_get | owner_set;
|
|
19 public property query => prop_get | owner_set;
|
111
|
20 public property formData => prop_get | owner_set;
|
|
21 public property formSchema => prop_get | owner_set;
|
|
22 public property formErrors => prop_get | owner_set;
|
110
|
23 }
|
|
24
|
|
25 sub CTOR {
|
112
|
26 my ($this,$action,$args) = @_;
|
110
|
27
|
|
28 $this->action($action);
|
|
29 $this->application($action->application);
|
|
30 $this->query($action->query);
|
112
|
31
|
|
32 $this->$_($args->{$_}) foreach qw(formData formSchema formErrors);
|
|
33 }
|
|
34
|
|
35 sub forms {
|
|
36 my ($self,%forms) = @_;
|
|
37
|
|
38 while ( my ($method,$info) = each %forms ) {
|
|
39 die new IMPL::Exception("A method doesn't exists in the controller",$self,$method) unless $self->can($method);
|
|
40 if ( not ref $info ) {
|
|
41 $self->class_data(CONTROLLER_METHODS)->{$method} = {
|
|
42 wrapper => 'FormWrapper',
|
|
43 schema => $info
|
|
44 };
|
|
45 } elsif (ref $info eq 'HASH') {
|
|
46 die new IMPL::Exception("A schema must be specified",$self,$method) unless $info->{schema};
|
|
47
|
|
48 $self->class_data(CONTROLLER_METHODS)->{$method} = {
|
|
49 wrapper => 'FormWrapper',
|
|
50 schema => $info->{schema}
|
|
51 };
|
|
52 } else {
|
|
53 die new IMPL::Exception("Unsupported method information",$self,$method);
|
|
54 }
|
|
55 }
|
|
56 }
|
|
57
|
|
58 sub transactions {
|
|
59
|
110
|
60 }
|
|
61
|
|
62 sub InvokeAction {
|
|
63 my ($self,$method,$action) = @_;
|
|
64
|
112
|
65 if (my $methodInfo = $self->class_data(CONTROLLER_METHODS)->{$method}) {
|
|
66 if (my $wrapper = $methodInfo->{wrapper}) {
|
|
67 return $self->$wrapper($method,$action,$methodInfo);
|
|
68 } else {
|
|
69 return $self->TransactionWrapper($method,$action,$methodInfo);
|
|
70 }
|
110
|
71 } else {
|
|
72 die new IMPL::InvalidOperationException("Invalid method call",$self,$method);
|
|
73 }
|
111
|
74 }
|
|
75
|
112
|
76 sub TransactionWrapper {
|
|
77 my ($self,$method,$action,$methodInfo) = @_;
|
|
78
|
|
79 my $unit = $self->new($action);
|
|
80 return $unit->$method();
|
|
81 }
|
|
82
|
|
83 sub FormWrapper {
|
|
84 my ($this,$method,$action,$methodInfo) = @_;
|
|
85
|
|
86 my $schema = $this->loadSchema($methodInfo->{schema});
|
|
87
|
|
88 my $process = $this->query->param('process') || 0;
|
|
89
|
|
90
|
|
91
|
|
92 my %result = (
|
|
93
|
|
94 );
|
|
95 }
|
|
96
|
111
|
97 1;
|
|
98
|
|
99 __END__
|
|
100
|
|
101 =pod
|
|
102
|
|
103 =head1 NAME
|
|
104
|
|
105 C<IMPL::Web::Application::ControllerUnit> - базовый класс для обработчика транзакций в модели контроллера.
|
|
106
|
|
107 =head1 DESCRIPTION
|
|
108
|
|
109 Классы, наследуемые от данного класса используются для выполнения транзакций, которые приходят
|
|
110 через контроллер запросов. Как правило один класс представляет собой пакет транзакций, каждая
|
|
111 из которых является независимой от другой.
|
|
112
|
|
113 Перед выполнением транзакции создается экземпляр объекта, в рамках которого будет выполнена транзакция.
|
|
114 Для этого вызывается метод C<InvokeAction($method,$action)>, который создает/восстанавливает контекст
|
|
115 транзакции.
|
|
116
|
|
117 Транзакции на данный момент делятся на простые и формы.
|
|
118
|
|
119 =head2 Простые транзакции
|
|
120
|
|
121 Простые транзакции получаю только запрос, без предварительной обработки, и возвращенный результат напрямую
|
|
122 передается пользователю.
|
|
123
|
|
124 =head2 Формы
|
|
125
|
|
126 При использовании форм запрос предварительно обрабатывается, для получения DOM документа с данными формы.
|
|
127 Для постороенния DOM документа используется схема. При этом становятся доступны дополнительные свойства
|
|
128 C<formData>, C<formSchema>, C<formErrors>.
|
|
129
|
|
130 Результат выполнения транзакции не возвращается напрямую пользователю, а включается в общий ответ, который
|
|
131 выглядит следующим образом
|
|
132
|
|
133 =begin code
|
|
134
|
|
135 {
|
|
136 state => '{ new | correct | invalid }',
|
|
137 result => $transactionResult,
|
|
138 formData => $formDOM,
|
|
139 formSchema => $formSchema,
|
|
140 formErrors => @errors
|
|
141 }
|
|
142
|
|
143 =end code
|
|
144
|
|
145 =over
|
|
146
|
|
147 =item C<state>
|
|
148
|
|
149 Состояние верификации формы.
|
|
150
|
|
151 =over
|
|
152
|
|
153 =item C<new>
|
|
154
|
|
155 Первоначальное содержимое формы, оно может быть некорректным, но это нормально.
|
|
156 В данном состоянии транзакция обычно не выполняется.
|
|
157
|
|
158 =item C<correct>
|
|
159
|
|
160 Данные формы корректны, транзакция выполнена, и ее результат доступен через поле C<result>
|
|
161
|
|
162 =item C<invalid>
|
|
163
|
|
164 Содержимое формы не прошло верификацию, ошибки доступны через поле C<formErrors>. Транзакция
|
|
165 не выполнялась.
|
|
166
|
|
167 =back
|
|
168
|
|
169 =item C<result>
|
|
170
|
|
171 Результат выполнения транзакции, если конечно таковая выполнялась.
|
|
172
|
|
173 =item C<formData>
|
|
174
|
|
175 ДОМ документ с данными формами. Документ существует всегда, не зависимо от его корректности,
|
|
176 может быть использован для построения формы, уже заполненную параметрами.
|
|
177
|
|
178 =item C<formSchema>
|
|
179
|
|
180 Схема данных формы, может использоваться для построения динамических форм.
|
|
181
|
|
182 =item C<formErrors>
|
|
183
|
|
184 Ошибки верификации данных, если таковые были
|
|
185
|
|
186 =back
|
|
187
|
|
188 =head1 MEMBERS
|
|
189
|
|
190 =over
|
|
191
|
|
192 =item C<[get] application>
|
|
193
|
|
194 =item C<[get] query>
|
|
195
|
|
196 =item C<[get] response>
|
|
197
|
|
198 =item C<[get] formData>
|
|
199
|
|
200 =item C<[get] formSchema>
|
|
201
|
|
202 =item C<[get] formErrors>
|
|
203
|
|
204 =item C<InvokeAction($method,$action)>
|
|
205
|
|
206 Конструирует контекст выполнения транзакции, может быть переопределен для конструирования контекста по
|
112
|
207 своим правилам.
|
|
208
|
|
209 =item C<TransactionWrapper($method,$action,$methodInfo)>
|
|
210
|
|
211 Обертка для конструирования простых транзакций, может быть переопределен для конструирования контекста по
|
|
212 своим правилам.
|
|
213
|
|
214 =item C<FormWrapper($method,$action,$methodInfo)>
|
|
215
|
|
216 Обертка для конструирования форм, может быть переопределен для конструирования контекста по
|
|
217 своим правилам.
|
111
|
218
|
|
219 =back
|
|
220
|
|
221 =head1 EXAMPLE
|
|
222
|
|
223 =begin code
|
|
224
|
|
225 package MyBooksUnit;
|
|
226 use strict;
|
|
227 use base qw(IMPL::Web::Application::ControllerUnit);
|
|
228
|
|
229 __PACKAGE__->PassThroughArgs;
|
|
230
|
|
231 __PACKAGE__->transactions(qw(
|
|
232 find
|
|
233 info
|
|
234 ));
|
|
235 __PACKAGE__->forms(
|
|
236 create => 'books.create.xml'
|
|
237 );
|
|
238
|
|
239 sub find {
|
|
240 my ($this) = @_;
|
|
241
|
|
242 return $this->application->dataSource->resultset('Books')->find({author => $this->query->param('author')});
|
|
243 }
|
|
244
|
|
245 sub info {
|
|
246 my ($this) = @_;
|
|
247
|
|
248 return $this->application->dataSource->resultset('Books')->find({id => $this->query->param('id')});
|
|
249 }
|
|
250
|
|
251 sub create {
|
|
252 my ($this) = @_;
|
|
253
|
|
254 my %book = map {
|
|
255 $_ => $this->formData->selectSingleNode($_)->nodeValue
|
|
256 } qw(author_id title year ISBN);
|
|
257
|
|
258 return $this->application->datasource->resultset('Books')->create(\%book);
|
|
259 }
|
|
260
|
|
261 =end code
|
|
262
|
|
263 =cut |