Mercurial > pub > Impl
view Lib/IMPL/Web/View/Metadata/FormMeta.pm @ 369:7c784144d2f1
Implemented object metadata class, cleanup
author | cin |
---|---|
date | Mon, 09 Dec 2013 17:35:34 +0400 |
parents | 010ceafd0c5a |
children | d5c8b955bf8d |
line wrap: on
line source
package IMPL::Web::View::Metadata::FormMeta; use strict; use IMPL::Const qw(:prop); use IMPL::declare { require => { Exception => 'IMPL::Exception', ArgException => '-IMPL::InvalidArgumentException', OpException => '-IMPL::InvalidOperationException', SchemaNavigator => 'IMPL::DOM::Navigator::SchemaNavigator' }, base => [ 'IMPL::Web::View::Metadata::BaseMeta' => '@_' ], props => [ nodes => PROP_RO, decl => PROP_RO, schema => PROP_RO, errors => PROP_RO, group => PROP_RO ] }; use constant { Meta => __PACKAGE__ }; sub CTOR { my ($this,$model,$type,$args) = @_; if ($args) { $this->$_($args->{$_}) foreach grep $args->{$_}, qw(decl schema nodes errors group); } $this->$_() || die ArgException->new($_ => "The $_ is required") foreach qw(schema); } sub isMultiple { my ($this) = @_; $this->decl && $this->decl->isMultiple; } sub isOptional { my ($this) = @_; not($this->decl) || $this->decl->isOptional; } sub GetOwnErrors { my ($this) = @_; my $nodes = $this->nodes; return [ grep _IsOwnError($nodes,$this->decl,$_), @{$this->errors || []} ]; } sub _IsOwnError { my ($nodes,$source,$err) = @_; return 1 if ($err->node && grep($err->node == $_, @$nodes)) || (not(@$nodes) && $err->schema == $source ); return 0; } sub _IsErrorRelates { my ($nodes,$source,$err) = @_; # this is an own error return 1 if _IsOwnError($nodes,$source,$err); # this error relates to the child control return 0 unless @$nodes; for (my $n = $err->parent; $n ; $n = $n->parentNode) { return 1 if grep($n == $_, @$nodes); } return 0; } sub PopulateProperties { my ($this) = @_; my @props; # return empty list of properties in case of multiple values return \@props if $this->isMultiple; my $navi = SchemaNavigator->new($this->schema); foreach my $decl (@{$this->schema->content->childNodes}) { my $schema = $navi->NavigateName($decl->name); $navi->SchemaBack(); my @nodes = $this->model && $this->model->selectNodes( sub { $_->schemaSource == $decl } ); my %args = ( name => $decl->name, decl => $decl, schema => $schema, nodes => \@nodes, errors => [grep _IsErrorRelates(\@nodes,$decl,$_), @{$this->errors || []}] ); my ($model,$type); if ($decl->isMultiple) { $model = \@nodes; $type = 'ARRAY'; $args{holdingType} = $schema->type; } else { $model = shift @nodes; $type = $schema->type; } push @props, Meta->new($model,$type,\%args); } return \@props; } sub GetItems { my ($this) = @_; die OpException->new("The operation must be performed on the container") unless $this->isMultiple; my $i = 0; return [ map $this->_GetItemMeta($_,$i++), @{$this->nodes} ]; } sub GetItem { my ($this,$index) = @_; die OpException->new("The operation must be performed on the container") unless $this->isMultiple; my $node = $this->nodes->[$index]; return $this->_GetItemMeta($node,$index); } sub _GetItemMeta { my ($this,$node,$index) = @_; my @nodes; push @nodes,$node if $node; return Meta->new( $node, $this->schema->type, { name => $index, schema => $this->schema, errors => [grep _IsErrorRelates([$node],$this->decl,$_), @{$this->errors ||[]} ], group => $this, nodes => \@nodes } ); } 1; __END__ =pod =head1 NAME =head1 SYNOPSIS =head1 DESCRIPTION Расширенные метаданные модели для элементов формы, помимо стандартных свойств сожержит в себе информацию о схеме. =head1 MEMBERS =head2 C<[get]errors> Ссылка на массив с ошибками при проверке схемы. Ошибки относятся ко всем узлам в текущей модели, включая вложенные и т.п. =head2 C<[get]model> Ссылка на элемент документа, либо на массив с элементами для множественных значений (C<isMultiple = true>). В том случае, когда документ был не корректен и для не множественного элемента было передено несколько значений, данное свойство будет содержать только первое. =head2 C<[get]nodes> Ссылка на массив с узлами документа. В теории количество узлов может быть произвольным, поскольку документ может быть некорректным, т.е. их может быть более одного в то время, как C<isMultiple = false> или, напротив, ни одного при C<isOptional = false>. Как правило для построения формы данное свойство не требуется. =head2 C<[get]modelType> Название типа данных из схемы документа (C<< schema->name >>), если тип не имеет название, то это C<ComplexNode> для сложных узлов и C<SimpleNode> для простых. Для моделей с множественными значениями это свойство не задано. Тип элементов храниться в свойстве C<holdingType> =head2 C<[get]decl> Объявление элемента формы, объявление может совпадать со схемой в случае, когда это был C<SimpleNode> или C<ComplexNode>, иначе это C<Node> ссылающийся на заранее обпределенный тип. =head2 C<[get]schema> Схема текущего элемента, C<СomlexType>, C<SimpleType>, C<ComplexNode> или C<SimpleNode>. =head2 C<[get]isOptional> Данный элемент может не иметь ни одного значения =head2 C<[get]isMultiple> Данный элемент может иметь более одного значения. Модель с множественными значениями является сложным элементом, в котором дочерними моделями являются не свойства а сами элементы, в данном случае они их именами будут индексы. =begin code for(my $i=0; $i< 10; $i++) { display_for($i,'template'); } sub display_for { my ($index,$tmpl) = @_; if ($index =~ /^\d+$/) { return render($tmpl, meta => { $meta->GetItem($index) }); } else { return render($tmpl, meta => { $meta->GetProperty($index) }); } } =end code =head2 C<GetOwnErrors()> Возвращает ошибки относящиеся к самому элементу C<model>, это принципиально для контейнеров и в случаях, когда модель не корректна и в ней присутствуют лишние значения. =cut