Mercurial > pub > Impl
comparison lib/IMPL/Web/View/Metadata/FormMeta.pm @ 407:c6e90e02dd17 ref20150831
renamed Lib->lib
author | cin |
---|---|
date | Fri, 04 Sep 2015 19:40:23 +0300 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
406:f23fcb19d3c1 | 407:c6e90e02dd17 |
---|---|
1 package IMPL::Web::View::Metadata::FormMeta; | |
2 use strict; | |
3 | |
4 use IMPL::lang; | |
5 use IMPL::Const qw(:prop); | |
6 use IMPL::declare { | |
7 require => { | |
8 Exception => 'IMPL::Exception', | |
9 ArgException => '-IMPL::InvalidArgumentException', | |
10 OpException => '-IMPL::InvalidOperationException', | |
11 SchemaNavigator => 'IMPL::DOM::Navigator::SchemaNavigator', | |
12 DOMNode => '-IMPL::DOM::Node' | |
13 }, | |
14 base => [ | |
15 'IMPL::Web::View::Metadata::BaseMeta' => '@_' | |
16 ], | |
17 props => [ | |
18 nodes => PROP_RO, | |
19 decl => PROP_RO, | |
20 schema => PROP_RO, | |
21 errors => PROP_RO, | |
22 group => PROP_RO | |
23 ] | |
24 }; | |
25 | |
26 use constant { | |
27 Meta => __PACKAGE__ | |
28 }; | |
29 | |
30 sub CTOR { | |
31 my ($this,$model,$type,$args) = @_; | |
32 | |
33 if ($args) { | |
34 $this->$_($args->{$_}) foreach grep $args->{$_}, qw(decl schema nodes errors group); | |
35 } | |
36 | |
37 $this->$_() || die ArgException->new($_ => "The $_ is required") | |
38 foreach qw(schema); | |
39 } | |
40 | |
41 sub GetSchemaProperty { | |
42 my ($this,$name) = @_; | |
43 | |
44 return $this->decl ? $this->decl->nodeProperty($name) || $this->schema->nodeProperty($name) : $this->schema->nodeProperty($name); | |
45 } | |
46 | |
47 sub template { | |
48 shift->GetSchemaProperty('template'); | |
49 } | |
50 | |
51 sub label { | |
52 shift->GetSchemaProperty('label'); | |
53 } | |
54 | |
55 sub inputType { | |
56 shift->GetSchemaProperty('inputType'); | |
57 } | |
58 | |
59 sub inputValue { | |
60 my ($this) = @_; | |
61 | |
62 if($this->isMultiple) { | |
63 return [ | |
64 map { | |
65 $_ ? $_->nodeValue || $_->nodeProperty('rawValue') : undef | |
66 } | |
67 @{$this->model || []} | |
68 ] | |
69 } else { | |
70 return $this->model ? $this->model->nodeValue || $this->model->nodeProperty('rawValue') : undef; | |
71 } | |
72 } | |
73 | |
74 sub isMultiple { | |
75 my ($this) = @_; | |
76 $this->decl && $this->decl->isMultiple; | |
77 } | |
78 | |
79 sub isOptional { | |
80 my ($this) = @_; | |
81 not($this->decl) || $this->decl->isOptional; | |
82 } | |
83 | |
84 sub GetOwnErrors { | |
85 my ($this) = @_; | |
86 | |
87 my $nodes = $this->nodes; | |
88 | |
89 my $errors = [ | |
90 grep _IsOwnError($nodes,$this->decl,$_), @{$this->errors || []} | |
91 ]; | |
92 | |
93 return $errors; | |
94 } | |
95 | |
96 sub _IsOwnError { | |
97 my ($nodes,$source,$err) = @_; | |
98 | |
99 return 1 if ($err->node && grep($err->node == $_, @$nodes)) || (not(@$nodes) && $err->schemaNode && $err->schemaNode == $source ); | |
100 | |
101 return 0; | |
102 } | |
103 | |
104 sub _IsErrorRelates { | |
105 my ($nodes,$source,$err) = @_; | |
106 | |
107 # this is an own error | |
108 return 1 if _IsOwnError($nodes,$source,$err); | |
109 | |
110 # this error relates to the child control | |
111 | |
112 return 0 unless @$nodes; | |
113 | |
114 for (my $n = $err->parent; $n ; $n = $n->parentNode) { | |
115 return 1 if grep($n == $_, @$nodes); | |
116 } | |
117 | |
118 return 0; | |
119 } | |
120 | |
121 sub PopulateProperties { | |
122 my ($this) = @_; | |
123 | |
124 my @props; | |
125 | |
126 # return empty list of properties in case of multiple values | |
127 return \@props if $this->isMultiple; | |
128 | |
129 my $navi = SchemaNavigator->new($this->schema); | |
130 | |
131 foreach my $decl (@{$this->schema->content->childNodes}) { | |
132 | |
133 my $schema = $navi->NavigateName($decl->name); | |
134 $navi->SchemaBack(); | |
135 | |
136 my @nodes = $this->model && $this->model->selectNodes( sub { $_->schemaNode == $decl } ); | |
137 | |
138 my %args = ( | |
139 name => $decl->name, | |
140 decl => $decl, | |
141 schema => $schema, | |
142 nodes => [@nodes], | |
143 errors => [grep _IsErrorRelates(\@nodes,$decl,$_), @{$this->errors || []}] | |
144 ); | |
145 | |
146 my ($model,$type); | |
147 | |
148 if ($decl->isMultiple) { | |
149 $model = [@nodes]; | |
150 $type = 'ARRAY'; | |
151 $args{holdingType} = $schema->type; | |
152 } else { | |
153 $model = shift @nodes; | |
154 $type = $schema->type; | |
155 } | |
156 | |
157 push @props, Meta->new($model,$type,\%args); | |
158 } | |
159 | |
160 return \@props; | |
161 } | |
162 | |
163 sub GetItems { | |
164 my ($this) = @_; | |
165 | |
166 die OpException->new("The operation must be performed on the container") | |
167 unless $this->isMultiple; | |
168 | |
169 my $i = 0; | |
170 | |
171 return [ | |
172 map $this->_GetItemMeta($_,$i++), @{$this->nodes} | |
173 ]; | |
174 } | |
175 | |
176 sub GetItem { | |
177 my ($this,$index) = @_; | |
178 | |
179 die OpException->new("The operation must be performed on the container") | |
180 unless $this->isMultiple; | |
181 | |
182 my $node = $this->nodes->[$index]; | |
183 | |
184 return $this->_GetItemMeta($node,$index); | |
185 } | |
186 | |
187 sub _GetItemMeta { | |
188 my ($this,$node,$index) = @_; | |
189 | |
190 my @nodes; | |
191 push @nodes,$node if $node; | |
192 | |
193 return Meta->new( | |
194 $node, | |
195 $this->schema->type, | |
196 { | |
197 name => $index, | |
198 schema => $this->schema, | |
199 errors => [grep _IsErrorRelates([$node],$this->decl,$_), @{$this->errors ||[]} ], | |
200 group => $this, | |
201 nodes => \@nodes | |
202 } | |
203 ); | |
204 } | |
205 | |
206 sub GetMetadataForModel { | |
207 my ($self,$model,$args) = @_; | |
208 | |
209 $args ||= {}; | |
210 | |
211 my $modelType = delete $args->{modelType}; | |
212 | |
213 if($model) { | |
214 die ArgException->new(model => "A node is required") | |
215 unless is($model,DOMNode); | |
216 | |
217 $args->{decl} ||= $model->schemaNode; | |
218 $args->{schema} ||= $model->schemaType; | |
219 } | |
220 | |
221 return $self->new( | |
222 $model, | |
223 $modelType, | |
224 $args | |
225 ); | |
226 } | |
227 | |
228 1; | |
229 | |
230 __END__ | |
231 | |
232 =pod | |
233 | |
234 =head1 NAME | |
235 | |
236 =head1 SYNOPSIS | |
237 | |
238 =head1 DESCRIPTION | |
239 | |
240 Расширенные метаданные модели для элементов формы, помимо стандартных свойств | |
241 сожержит в себе информацию о схеме. | |
242 | |
243 =head1 MEMBERS | |
244 | |
245 =head2 C<[get]errors> | |
246 | |
247 Ссылка на массив с ошибками при проверке схемы. Ошибки относятся ко всем | |
248 узлам в текущей модели, включая вложенные и т.п. | |
249 | |
250 =head2 C<[get]model> | |
251 | |
252 Ссылка на элемент документа, либо на массив с элементами для множественных | |
253 значений (C<isMultiple = true>). В том случае, когда документ был не | |
254 корректен и для не множественного элемента было передено несколько значений, | |
255 данное свойство будет содержать только первое. | |
256 | |
257 =head2 C<[get]nodes> | |
258 | |
259 Ссылка на массив с узлами документа. В теории количество узлов может быть | |
260 произвольным, поскольку документ может быть некорректным, т.е. их может | |
261 быть более одного в то время, как C<isMultiple = false> или, напротив, ни | |
262 одного при C<isOptional = false>. | |
263 | |
264 Как правило для построения формы данное свойство не требуется. | |
265 | |
266 =head2 C<[get]modelType> | |
267 | |
268 Название типа данных из схемы документа (C<< schema->name >>), если тип не имеет название, то это | |
269 C<ComplexNode> для сложных узлов и C<SimpleNode> для простых. | |
270 | |
271 Для моделей с множественными значениями это свойство не задано. Тип элементов | |
272 храниться в свойстве C<holdingType> | |
273 | |
274 =head2 C<[get]decl> | |
275 | |
276 Объявление элемента формы, объявление может совпадать со схемой в случае, | |
277 когда это был C<SimpleNode> или C<ComplexNode>, иначе это C<Node> ссылающийся | |
278 на заранее обпределенный тип. | |
279 | |
280 =head2 C<[get]schema> | |
281 | |
282 Схема текущего элемента, C<СomlexType>, C<SimpleType>, C<ComplexNode> или | |
283 C<SimpleNode>. | |
284 | |
285 =head2 C<[get]isOptional> | |
286 | |
287 Данный элемент может не иметь ни одного значения | |
288 | |
289 =head2 C<[get]isMultiple> | |
290 | |
291 Данный элемент может иметь более одного значения. Модель с множественными | |
292 значениями является сложным элементом, в котором дочерними моделями являются | |
293 не свойства а сами элементы, в данном случае они их именами будут индексы. | |
294 | |
295 =begin code | |
296 | |
297 for(my $i=0; $i< 10; $i++) { | |
298 display_for($i,'template'); | |
299 } | |
300 | |
301 sub display_for { | |
302 my ($index,$tmpl) = @_; | |
303 | |
304 if ($index =~ /^\d+$/) { | |
305 return render($tmpl, metadata => { $meta->GetItem($index) }); | |
306 } else { | |
307 return render($tmpl, metadata => { $meta->GetProperty($index) }); | |
308 } | |
309 } | |
310 | |
311 =end code | |
312 | |
313 =head2 C<GetOwnErrors()> | |
314 | |
315 Возвращает ошибки относящиеся к самому элементу C<model>, это принципиально | |
316 для контейнеров и в случаях, когда модель не корректна и в ней присутствуют | |
317 лишние значения. | |
318 | |
319 =cut |