comparison Lib/IMPL/Web/Application/ControllerUnit.pm @ 194:4d0e1962161c

Replaced tabs with spaces IMPL::Web::View - fixed document model, new features (control classes, document constructor parameters)
author cin
date Tue, 10 Apr 2012 20:08:29 +0400
parents d1676be8afcc
children c6d0f889ef87
comparison
equal deleted inserted replaced
193:8e8401c0aea4 194:4d0e1962161c
8 use Class::Inspector; 8 use Class::Inspector;
9 use File::Spec; 9 use File::Spec;
10 use Sub::Name; 10 use Sub::Name;
11 11
12 use constant { 12 use constant {
13 CONTROLLER_METHODS => 'controller_methods', 13 CONTROLLER_METHODS => 'controller_methods',
14 STATE_CORRECT => 'correct', 14 STATE_CORRECT => 'correct',
15 STATE_NEW => 'new', 15 STATE_NEW => 'new',
16 STATE_INVALID => 'invalid', 16 STATE_INVALID => 'invalid',
17 TTYPE_FORM => 'form', 17 TTYPE_FORM => 'form',
18 TTYPE_TRANS => 'tran' 18 TTYPE_TRANS => 'tran'
19 }; 19 };
20 20
21 BEGIN { 21 BEGIN {
22 public property action => prop_get | owner_set; 22 public property action => prop_get | owner_set;
23 public property application => prop_get | owner_set; 23 public property application => prop_get | owner_set;
24 public property query => prop_get | owner_set; 24 public property query => prop_get | owner_set;
25 public property response => prop_get | owner_set; 25 public property response => prop_get | owner_set;
26 public property formData => prop_get | owner_set; 26 public property formData => prop_get | owner_set;
27 public property formSchema => prop_get | owner_set; 27 public property formSchema => prop_get | owner_set;
28 public property formErrors => prop_get | owner_set; 28 public property formErrors => prop_get | owner_set;
29 } 29 }
30 30
31 my %publicProps = map {$_->Name , 1} __PACKAGE__->get_meta(typeof IMPL::Class::PropertyInfo); 31 my %publicProps = map {$_->Name , 1} __PACKAGE__->get_meta(typeof IMPL::Class::PropertyInfo);
32 32
33 __PACKAGE__->class_data(CONTROLLER_METHODS,{}); 33 __PACKAGE__->class_data(CONTROLLER_METHODS,{});
34 34
35 our @schemaInc; 35 our @schemaInc;
36 36
37 sub CTOR { 37 sub CTOR {
38 my ($this,$action,$args) = @_; 38 my ($this,$action,$args) = @_;
39 39
40 $this->action($action); 40 $this->action($action);
41 $this->application($action->application); 41 $this->application($action->application);
42 $this->query($action->query); 42 $this->query($action->query);
43 $this->response($action->response); 43 $this->response($action->response);
44 44
45 $this->$_($args->{$_}) foreach qw(formData formSchema formErrors); 45 $this->$_($args->{$_}) foreach qw(formData formSchema formErrors);
46 } 46 }
47 47
48 sub unitNamespace() { 48 sub unitNamespace() {
49 "" 49 ""
50 } 50 }
51 51
52 sub transactions { 52 sub transactions {
53 my ($self,%methods) = @_; 53 my ($self,%methods) = @_;
54 54
55 while (my ($method,$info) = each %methods) { 55 while (my ($method,$info) = each %methods) {
56 if ($info and ref $info ne 'HASH') { 56 if ($info and ref $info ne 'HASH') {
57 warn "Bad transaction $method description"; 57 warn "Bad transaction $method description";
58 $info = {}; 58 $info = {};
59 } 59 }
60 60
61 $info->{wrapper} = 'TransactionWrapper'; 61 $info->{wrapper} = 'TransactionWrapper';
62 $info->{method} ||= $method; 62 $info->{method} ||= $method;
63 $info->{context}{transactionType} = TTYPE_TRANS; 63 $info->{context}{transactionType} = TTYPE_TRANS;
64 $self->class_data(CONTROLLER_METHODS)->{$method} = $info; 64 $self->class_data(CONTROLLER_METHODS)->{$method} = $info;
65 } 65 }
66 } 66 }
67 67
68 sub forms { 68 sub forms {
69 my ($self,%forms) = @_; 69 my ($self,%forms) = @_;
70 70
71 while ( my ($method,$info) = each %forms ) { 71 while ( my ($method,$info) = each %forms ) {
72 die new IMPL::Exception("A method doesn't exists in the controller",$self,$method) unless $self->can($method); 72 die new IMPL::Exception("A method doesn't exists in the controller",$self,$method) unless $self->can($method);
73 if ( not ref $info ) { 73 if ( not ref $info ) {
74 $self->class_data(CONTROLLER_METHODS)->{$method} = { 74 $self->class_data(CONTROLLER_METHODS)->{$method} = {
75 wrapper => 'FormWrapper', 75 wrapper => 'FormWrapper',
76 schema => $info, 76 schema => $info,
77 method => $method, 77 method => $method,
78 context => { transactionType => TTYPE_FORM } 78 context => { transactionType => TTYPE_FORM }
79 }; 79 };
80 } elsif (ref $info eq 'HASH') { 80 } elsif (ref $info eq 'HASH') {
81 $info->{wrapper} = 'FormWrapper'; 81 $info->{wrapper} = 'FormWrapper';
82 $info->{method} ||= $method; 82 $info->{method} ||= $method;
83 $info->{context}{transactionType} = TTYPE_FORM; 83 $info->{context}{transactionType} = TTYPE_FORM;
84 84
85 $self->class_data(CONTROLLER_METHODS)->{$method} = $info; 85 $self->class_data(CONTROLLER_METHODS)->{$method} = $info;
86 } else { 86 } else {
87 die new IMPL::Exception("Unsupported method information",$self,$method); 87 die new IMPL::Exception("Unsupported method information",$self,$method);
88 } 88 }
89 } 89 }
90 } 90 }
91 91
92 sub InvokeAction { 92 sub InvokeAction {
93 my ($self,$method,$action) = @_; 93 my ($self,$method,$action) = @_;
94 94
95 if (my $methodInfo = $self->class_data(CONTROLLER_METHODS)->{$method}) { 95 if (my $methodInfo = $self->class_data(CONTROLLER_METHODS)->{$method}) {
96 if (my $ctx = $methodInfo->{context}) { 96 if (my $ctx = $methodInfo->{context}) {
97 $action->context->{$_} = $ctx->{$_} foreach keys %$ctx; 97 $action->context->{$_} = $ctx->{$_} foreach keys %$ctx;
98 } 98 }
99 if (my $wrapper = $methodInfo->{wrapper}) { 99 if (my $wrapper = $methodInfo->{wrapper}) {
100 return $self->$wrapper($method,$action,$methodInfo); 100 return $self->$wrapper($method,$action,$methodInfo);
101 } else { 101 } else {
102 return $self->TransactionWrapper($method,$action,$methodInfo); 102 return $self->TransactionWrapper($method,$action,$methodInfo);
103 } 103 }
104 } else { 104 } else {
105 die new IMPL::InvalidOperationException("Invalid method call",$self,$method); 105 die new IMPL::InvalidOperationException("Invalid method call",$self,$method);
106 } 106 }
107 } 107 }
108 108
109 sub MakeParams { 109 sub MakeParams {
110 my ($this,$methodInfo) = @_; 110 my ($this,$methodInfo) = @_;
111 111
112 my $params; 112 my $params;
113 if ($params = $methodInfo->{parameters} and ref $params eq 'ARRAY') { 113 if ($params = $methodInfo->{parameters} and ref $params eq 'ARRAY') {
114 return map $this->ResolveParam($_,$methodInfo->{inflate}{$_}), @$params; 114 return map $this->ResolveParam($_,$methodInfo->{inflate}{$_}), @$params;
115 } 115 }
116 return(); 116 return();
117 } 117 }
118 118
119 sub ResolveParam { 119 sub ResolveParam {
120 my ($this,$param,$inflate) = @_; 120 my ($this,$param,$inflate) = @_;
121 121
122 if ( $param =~ /^::(\w+)$/ and $publicProps{$1}) { 122 if ( $param =~ /^::(\w+)$/ and $publicProps{$1}) {
123 return $this->$1(); 123 return $this->$1();
124 } else { 124 } else {
125 my $value; 125 my $value;
126 if ( my $rx = $inflate->{rx} ) { 126 if ( my $rx = $inflate->{rx} ) {
127 $value = $this->action->param($param,$rx); 127 $value = $this->action->param($param,$rx);
128 } else { 128 } else {
129 $value = $this->query->param($param); 129 $value = $this->query->param($param);
130 } 130 }
131 131
132 if (my $method = $inflate->{method}) { 132 if (my $method = $inflate->{method}) {
133 $value = $this->$method($value); 133 $value = $this->$method($value);
134 } 134 }
135 return $value; 135 return $value;
136 } 136 }
137 } 137 }
138 138
139 sub TransactionWrapper { 139 sub TransactionWrapper {
140 my ($self,$method,$action,$methodInfo) = @_; 140 my ($self,$method,$action,$methodInfo) = @_;
141 141
142 my $unit = $self->new($action); 142 my $unit = $self->new($action);
143 my $handler = $methodInfo->{method}; 143 my $handler = $methodInfo->{method};
144 return $unit->$handler($unit->MakeParams($methodInfo)); 144 return $unit->$handler($unit->MakeParams($methodInfo));
145 } 145 }
146 146
147 sub FormWrapper { 147 sub FormWrapper {
148 my ($self,$method,$action,$methodInfo) = @_; 148 my ($self,$method,$action,$methodInfo) = @_;
149 149
150 my $schema = $methodInfo->{schema} ? $self->loadSchema($methodInfo->{schema}) : $self->unitSchema; 150 my $schema = $methodInfo->{schema} ? $self->loadSchema($methodInfo->{schema}) : $self->unitSchema;
151 151
152 my $process = $action->query->param('process') || 0; 152 my $process = $action->query->param('process') || 0;
153 my $form = $methodInfo->{form} 153 my $form = $methodInfo->{form}
154 || $action->query->param('form') 154 || $action->query->param('form')
155 || $method; 155 || $method;
156 156
157 my %result; 157 my %result;
158 158
159 my $transform = IMPL::DOM::Transform::PostToDOM->new( 159 my $transform = IMPL::DOM::Transform::PostToDOM->new(
160 undef, 160 undef,
161 $schema, 161 $schema,
162 $form 162 $form
163 ); 163 );
164 164
165 my $handler = $methodInfo->{method}; 165 my $handler = $methodInfo->{method};
166 166
167 $result{formName} = $form; 167 $result{formName} = $form;
168 $result{formSchema} = $schema; 168 $result{formSchema} = $schema;
169 169
170 if ($process) { 170 if ($process) {
171 $result{formData} = $transform->Transform($action->query); 171 $result{formData} = $transform->Transform($action->query);
172 $result{formErrors} = $transform->Errors->as_list; 172 $result{formErrors} = $transform->Errors->as_list;
173 if ($transform->Errors->Count) { 173 if ($transform->Errors->Count) {
174 $result{state} = STATE_INVALID; 174 $result{state} = STATE_INVALID;
175 } else { 175 } else {
176 $result{state} = STATE_CORRECT; 176 $result{state} = STATE_CORRECT;
177 my $unit = $self->new($action,\%result); 177 my $unit = $self->new($action,\%result);
178 178
179 eval { 179 eval {
180 $result{result} = $unit->$handler($unit->MakeParams($methodInfo)); 180 $result{result} = $unit->$handler($unit->MakeParams($methodInfo));
181 }; 181 };
182 if (my $err = $@) { 182 if (my $err = $@) {
183 $result{state} = STATE_INVALID; 183 $result{state} = STATE_INVALID;
184 if (eval { $err->isa(typeof IMPL::WrongDataException) } ) { 184 if (eval { $err->isa(typeof IMPL::WrongDataException) } ) {
185 $result{formErrors} = $err->Args; 185 $result{formErrors} = $err->Args;
186 } else { 186 } else {
187 die $err; 187 die $err;
188 } 188 }
189 } 189 }
190 } 190 }
191 } else { 191 } else {
192 if (my $initMethod = $methodInfo->{init}) { 192 if (my $initMethod = $methodInfo->{init}) {
193 my $unit = $self->new($action,\%result); 193 my $unit = $self->new($action,\%result);
194 $result{formData} = $transform->Transform( $unit->$initMethod($unit->MakeParams($methodInfo)) ); 194 $result{formData} = $transform->Transform( $unit->$initMethod($unit->MakeParams($methodInfo)) );
195 } else { 195 } else {
196 $result{formData} = $transform->Transform($action->query); 196 $result{formData} = $transform->Transform($action->query);
197 } 197 }
198 198
199 # ignore errors for new forms 199 # ignore errors for new forms
200 #$result{formErrors} = $transform->Errors->as_list; 200 #$result{formErrors} = $transform->Errors->as_list;
201 $result{state} = STATE_NEW; 201 $result{state} = STATE_NEW;
202 } 202 }
203 203
204 return \%result; 204 return \%result;
205 } 205 }
206 206
207 sub loadSchema { 207 sub loadSchema {
208 my ($self,$name) = @_; 208 my ($self,$name) = @_;
209 209
210 foreach my $path (map File::Spec->catfile($_,$name) ,@schemaInc) { 210 foreach my $path (map File::Spec->catfile($_,$name) ,@schemaInc) {
211 return IMPL::DOM::Schema->LoadSchema($path) if -f $path; 211 return IMPL::DOM::Schema->LoadSchema($path) if -f $path;
212 } 212 }
213 213
214 die new IMPL::Exception("A schema isn't found", $name); 214 die new IMPL::Exception("A schema isn't found", $name);
215 } 215 }
216 216
217 sub unitSchema { 217 sub unitSchema {
218 my ($self) = @_; 218 my ($self) = @_;
219 219
220 my $class = ref $self || $self; 220 my $class = ref $self || $self;
221 221
222 my @parts = split(/:+/, $class); 222 my @parts = split(/:+/, $class);
223 223
224 my $file = pop @parts; 224 my $file = pop @parts;
225 $file = "${file}.schema.xml"; 225 $file = "${file}.schema.xml";
226 226
227 foreach my $inc ( @schemaInc ) { 227 foreach my $inc ( @schemaInc ) {
228 my $path = File::Spec->catfile($inc,@parts,$file); 228 my $path = File::Spec->catfile($inc,@parts,$file);
229 229
230 return IMPL::DOM::Schema->LoadSchema($path) if -f $path; 230 return IMPL::DOM::Schema->LoadSchema($path) if -f $path;
231 } 231 }
232 232
233 return undef; 233 return undef;
234 } 234 }
235 235
236 sub discover { 236 sub discover {
237 my ($this) = @_; 237 my ($this) = @_;
238 238
239 my $methods = $this->class_data(CONTROLLER_METHODS); 239 my $methods = $this->class_data(CONTROLLER_METHODS);
240 240
241 my $namespace = $this->unitNamespace; 241 my $namespace = $this->unitNamespace;
242 (my $module = typeof $this) =~ s/^$namespace//; 242 (my $module = typeof $this) =~ s/^$namespace//;
243 243
244 my %smd = ( 244 my %smd = (
245 module => [grep $_, split /::/, $module ], 245 module => [grep $_, split /::/, $module ],
246 ); 246 );
247 247
248 while (my ($method,$info) = each %$methods) { 248 while (my ($method,$info) = each %$methods) {
249 my %methodInfo = ( 249 my %methodInfo = (
250 name => $method 250 name => $method
251 ); 251 );
252 $methodInfo{parameters} = [ grep /^[^\:]/, @{ $info->{parameters} } ] if ref $info->{parameters} eq 'ARRAY'; 252 $methodInfo{parameters} = [ grep /^[^\:]/, @{ $info->{parameters} } ] if ref $info->{parameters} eq 'ARRAY';
253 push @{$smd{methods}},\%methodInfo; 253 push @{$smd{methods}},\%methodInfo;
254 } 254 }
255 return \%smd; 255 return \%smd;
256 } 256 }
257 257
258 __PACKAGE__->transactions( 258 __PACKAGE__->transactions(
259 discover => undef 259 discover => undef
260 ); 260 );
261 261
262 1; 262 1;
263 263
264 __END__ 264 __END__
297 выглядит следующим образом 297 выглядит следующим образом
298 298
299 =begin code 299 =begin code
300 300
301 { 301 {
302 state => '{ new | correct | invalid }', 302 state => '{ new | correct | invalid }',
303 result => $transactionResult, 303 result => $transactionResult,
304 formData => $formDOM, 304 formData => $formDOM,
305 formSchema => $formSchema, 305 formSchema => $formSchema,
306 formErrors => @errors 306 formErrors => @errors
307 } 307 }
308 308
309 =end code 309 =end code
310 310
311 =over 311 =over
401 401
402 =begin code 402 =begin code
403 403
404 # SMD structure 404 # SMD structure
405 { 405 {
406 module => ['Foo','Bar'], 406 module => ['Foo','Bar'],
407 methods => [ 407 methods => [
408 { 408 {
409 name => 'search', 409 name => 'search',
410 parameters => ['text','limit'] #optional 410 parameters => ['text','limit'] #optional
411 } 411 }
412 ] 412 ]
413 } 413 }
414 414
415 =end code 415 =end code
416 416
417 =back 417 =back
427 __PACKAGE__->PassThroughArgs; 427 __PACKAGE__->PassThroughArgs;
428 428
429 sub unitDataClass { 'My::Books' } 429 sub unitDataClass { 'My::Books' }
430 430
431 __PACKAGE__->transactions( 431 __PACKAGE__->transactions(
432 find => { 432 find => {
433 parameters => [qw(author)] 433 parameters => [qw(author)]
434 }, 434 },
435 info => { 435 info => {
436 parameters => [qw(id)] 436 parameters => [qw(id)]
437 } 437 }
438 ); 438 );
439 __PACKAGE__->forms( 439 __PACKAGE__->forms(
440 create => 'books.create.xml' 440 create => 'books.create.xml'
441 ); 441 );
442 442
443 sub find { 443 sub find {
444 my ($this,$author) = @_; 444 my ($this,$author) = @_;
445 445
446 return $this->ds->find({author => $author}); 446 return $this->ds->find({author => $author});
447 } 447 }
448 448
449 sub info { 449 sub info {
450 my ($this,$id) = @_; 450 my ($this,$id) = @_;
451 451
452 return $this->ds->find({id => $id}); 452 return $this->ds->find({id => $id});
453 } 453 }
454 454
455 sub create { 455 sub create {
456 my ($this) = @_; 456 my ($this) = @_;
457 457
458 my %book = map { 458 my %book = map {
459 $_->nodeName, $_->nodeValue 459 $_->nodeName, $_->nodeValue
460 } $this->formData->selectNodes([qw(author_id title year ISBN)]); 460 } $this->formData->selectNodes([qw(author_id title year ISBN)]);
461 461
462 return $this->ds->create(\%book); 462 return $this->ds->create(\%book);
463 } 463 }
464 464
465 =end code 465 =end code
466 466
467 =cut 467 =cut