diff lib/IMPL/DOM/Transform/QueryToDOM.pm @ 407:c6e90e02dd17 ref20150831

renamed Lib->lib
author cin
date Fri, 04 Sep 2015 19:40:23 +0300
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/IMPL/DOM/Transform/QueryToDOM.pm	Fri Sep 04 19:40:23 2015 +0300
@@ -0,0 +1,185 @@
+package IMPL::DOM::Transform::QueryToDOM;
+use strict;
+
+use IMPL::Const qw(:prop);
+use IMPL::declare {
+    require => {
+        OutOfRangeException => '-IMPL::OutOfRangeException'
+    },
+	base => [
+	   'IMPL::DOM::Transform::ObjectToDOM' => '@_'
+	],
+	props => [
+	   prefix => PROP_RO,
+	   delimiter => PROP_RO
+	]
+};
+
+our $MAX_INDEX = 1024;
+
+sub CTOR {
+	my ($this) = @_;
+	
+	$this->templates->{'CGI'} = 'TransformCGI';
+	$this->templates->{'IMPL::Web::Application::Action'} = 'TransformAction';
+
+	$this->delimiter('[.]');
+	$this->prefix('');
+}
+
+# inflate simple properties
+sub TransformPlain {
+    my ($this,$data) = @_;
+    
+    $this->currentNode->nodeProperty( rawValue => $data );
+    $this->currentNode->nodeValue( $data );
+    return $this->currentNode;
+}
+
+# do not store complex data as node values
+sub StoreObject {
+    my ($this,$node,$data) = @_;
+    
+    return $node;
+}
+
+#TODO: support a.b[0][1].c[1]
+
+sub TransformCGI {
+	my ($this,$query) = @_;
+	
+    my $data={};
+    
+    my $prefix = $this->prefix;
+    my $delim = $this->delimiter;
+    
+    foreach my $param (grep index($_,$prefix) >= 0 , $query->param()) {
+        
+        my @value = grep length($_), $query->param($param) or next;
+        
+        my @parts = split /$delim/,$param;
+        
+        my $node = $data;
+        while ( my $part = shift @parts ) {
+            if (my ($name,$index) = ($part =~ m/^(\w+)(?:\[(\d+)\])?$/) ) {
+                if (@parts) {
+                    if(defined $index) {
+                        $this->ValidateIndex($index);
+                        $node = ($node->{$name}[$index] ||= {});
+                    } else {
+                        $node = ($node->{$name} ||= {});
+                    }
+                } else {
+                    if(defined $index) {
+                        $this->ValidateIndex($index);
+                        $node->{$name}[$index] = (@value == 1 ? $value[0] : \@value);
+                    } else {
+                        $node->{$name} = (@value == 1 ? $value[0] : \@value);
+                    }
+                }
+            }
+        }  
+    }
+    
+    return $this->Transform($data);
+}
+
+sub ValidateIndex {
+    my ($this,$index) = @_;
+    
+    die OutOfRangeException->new()
+        unless $index >= 0 and $index <= $MAX_INDEX;
+}
+
+sub TransformAction {
+	my ($this,$action) = @_;
+	
+	return $this->Transform($action->isJson ? $action->jsonData : $action->query);
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::DOM::Transform::QueryToDOM> - преобразование CGI запроса в DOM документ.
+
+=head1 SYNOPSIS
+
+=begin code
+
+use CGI();
+use IMPL::require {
+    Schema => 'IMPL::DOM::Schema',
+    Config => 'IMPL::Config',
+    QueryToDOM => 'IMPL::DOM::Transform::QueryToDOM'
+}
+
+my $q = CGI->new();
+
+my $schema = Schema->LoadSchema(Config->AppBase('schemas','person.xml'));
+my $transorm = QueryToDOM->new('edit', $schema);
+
+my $form = $transform->Transform($q);
+
+my @errors;
+    
+push @errors, $transform->buildErrors;
+push @errors, $schema->Validate($doc);
+
+
+=end code
+
+=head1 DESCRIPTION
+
+Наследует C<IMPL::DOM::Transform::ObjectToDOM>. Добавляет метод
+C<TransformCGI> который применятеся к объектам типа C<CGI> (и производных).
+
+Запрос C<CGI> сначала приводится к хешу, затем полученный хеш преобразуется
+в DOM документ при помощи вызова метода C<Transform>.
+
+Для этого выбираются параметры запроса, затем, имя каждого параметра
+рассматривается в виде пути к свойству, создается структура из хешей и массивов
+в которую по указанному пути кладется значение.
+
+Если параметр имеет несколько значений, значит свойство является массивом.
+
+Также изменено поведение некоторых методов преобразования.
+
+=over
+
+=item * C<TransformPlain($value)>
+
+Преобразование для простого значения свойства. Посокльку в запросе передаются
+строковые значения, а схема документа может предполпгать другие типы, при
+преобразовании значения параметра из запроса к значению узла используется
+метод C<< $this->inflateNodeValue($value) >>, также помимо значения
+C<< $this->currentNode->nodeValue >> задается атрибут
+C<< $this->currentNode->nodeProperty( rawValue => $value) >>, для того, чтобы
+была возможность получить оригинальное значение параметра запроса (например,
+в случае когда его формат был не верным и C<nodeValue> будет C<undef>).
+
+=item * C<StoreObject($node,$object)>
+
+Данный метод вызывается если текущий узел (переданный в параметре C<$node>)
+предполагает простое значение, однако в запросе для него было передано сложное
+содержимое. Данная реализация просто игнорирует переданный объект C<$object>
+и возвращает C<$node> без изменений. 
+
+=back
+
+=head1 MEMBERS
+
+=head2 C<[get]delimiter>
+
+REGEX. Разделитель свойств в имени параметра, по-умолчанию C<'[.]'> 
+
+=head2 C<[get]prefix>
+
+Строка, префикс имен параметров, которые участвуют в формировании документа.
+По-умолчанию пусто.
+
+=cut
\ No newline at end of file