changeset 244:a02b110da931

refactoring fixed binding to CGI query parameters with multiple values
author sergey
date Mon, 22 Oct 2012 04:09:27 +0400
parents cd2b1f121029
children 7c517134c42f
files Lib/IMPL/DOM/Transform/QueryToDOM.pm Lib/IMPL/Web/Application.pm Lib/IMPL/Web/Application/Action.pm Lib/IMPL/Web/Application/Resource.pm Lib/IMPL/Web/AutoLocator.pm Lib/IMPL/Web/CGIApplication.pm Lib/IMPL/Web/CGIWrapper.pm Lib/IMPL/Web/Handler/RestController.pm Lib/IMPL/Web/Handler/TTView.pm Lib/IMPL/Web/QueryHandler/JsonFormat.pm Lib/IMPL/Web/QueryHandler/PageFormat.pm Lib/IMPL/Web/QueryHandler/PathInfoRewrite.pm Lib/IMPL/Web/QueryHandler/SecureCookie.pm Lib/IMPL/Web/QueryHandler/UrlController.pm Lib/IMPL/Web/TT/Collection.pm Lib/IMPL/Web/TT/Control.pm Lib/IMPL/Web/TT/Document.pm Lib/IMPL/Web/TT/Form.pm Lib/IMPL/Web/View/TemplateView.pm Lib/IMPL/Web/ViewResult.pm
diffstat 20 files changed, 218 insertions(+), 1329 deletions(-) [+]
line wrap: on
line diff
--- a/Lib/IMPL/DOM/Transform/QueryToDOM.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/DOM/Transform/QueryToDOM.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -16,8 +16,7 @@
 	my ($this) = @_;
 	
 	$this->templates->{'CGI'} = \&TransformCGI;
-	$this->templates->{'CGIWrapper'} = \&TransformCGI;
-	
+
 	$this->delimiter('[.]');
 	$this->prefix('');
 }
@@ -31,7 +30,8 @@
     my $delim = $this->delimiter;
     
     foreach my $param (grep index($_,$prefix) >= 0 , $query->param()) {
-        length (my $value = $query->param($param)) or next;
+        
+        my @value = grep length($_), $query->param($param) or next;
         
         my @parts = split /$delim/,$param;
         
@@ -46,9 +46,9 @@
                     }
                 } else {
                     if(defined $index) {
-                        $node->{$name}[$index] = $value;
+                        $node->{$name}[$index] = (@value == 1 ? $value[0] : \@value);
                     } else {
-                        $node->{$name} = $value;
+                        $node->{$name} = (@value == 1 ? $value[0] : \@value);
                     }
                 }
             }
--- a/Lib/IMPL/Web/Application.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/Application.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -8,6 +8,7 @@
 
 use IMPL::declare {
 	require => {
+	    Locator                   => 'IMPL::Web::AutoLocator',
 		TAction                   => 'IMPL::Web::Application::Action',
 		HttpResponse              => 'IMPL::Web::HttpResponse',
 		TFactory                  => '-IMPL::Object::Factory',
@@ -20,13 +21,14 @@
 		'IMPL::Object::Singleton' => '@_'
 	  ],
 	  props => [
+	    baseUrl            => PROP_RW,
 		actionFactory      => PROP_RW,
 		handlers           => PROP_RW | PROP_LIST,
 		security           => PROP_RW,
 		options            => PROP_RW,
 		requestCharset     => PROP_RW,
-		fetchRequestMethod => PROP_RW,
-		output             => PROP_RW
+		output             => PROP_RW,
+		location           => PROP_RO
 	  ]
 };
 
@@ -37,9 +39,10 @@
 		"At least one handler should be supplied" )
 	  unless $this->handlers->Count;
 
+    $this->baseUrl('/') unless $this->baseUrl;
+    
 	$this->actionFactory(TAction) unless $this->actionFactory;
-	$this->fetchRequestMethod( \&defaultFetchRequest )
-	  unless $this->fetchRequestMethod;
+	$this->location(Locator->new(base => $this->baseUrl));
 }
 
 sub Run {
@@ -125,86 +128,8 @@
 }
 
 sub FetchRequest {
-	my ($this) = @_;
-
-	if ( ref $this->fetchRequestMethod eq 'CODE' ) {
-		return $this->fetchRequestMethod->($this);
-	}
-	else {
-		die new IMPL::Exception(
-			"Unknown fetchRequestMethod type",
-			ref $this->fetchRequestMethod
-		);
-	}
-}
-
-{
-	my $hasFetched = 0;
-
-	sub defaultFetchRequest {
-		my ($this) = @_;
-		return undef if $hasFetched;
-		$hasFetched = 1;
-		$this->output(*STDOUT);
-		my $query = CGIWrapper->new();
-		$query->charset($this->requestCharset) if $this->requestCharset;
-		return $query;
-	}
-}
-
-sub defaultErrorHandler {
-	my ( $this, $action, $e ) = @_;
-	warn $e;
-	if ( eval { $action->ReinitResponse(); 1; } ) {
-		$action->response->contentType('text/plain');
-		$action->response->charset( $this->responseCharset );
-		$action->response->status(500);
-		my $hout = $action->response->streamBody;
-		print $hout $e;
-		$action->response->Complete();
-	}
-}
-
-package CGIWrapper;
-use parent qw(CGI);
-
-use Encode;
-
-our $NO_DECODE = 0;
-
-sub param {
-	my $this = shift;
-
-	return $this->SUPER::param(@_) if $NO_DECODE;
-
-	if (wantarray) {
-		my @result = $this->SUPER::param(@_);
-
-		return map Encode::is_utf8($_)
-		  ? $_
-		  : Encode::decode( $this->charset, $_, Encode::LEAVE_SRC ), @result;
-	}
-	else {
-		my $result = $this->SUPER::param(@_);
-
-		return Encode::is_utf8($result)
-		  ? $result
-		  : Encode::decode( $this->charset, $result, Encode::LEAVE_SRC );
-	}
-
-}
-
-sub upload {
-	my $this = shift;
-
-	local $NO_DECODE = 1;
-	my $oldCharset = $this->charset();
-	$this->charset('ISO-8859-1');
-
-	my $fh = $this->SUPER::upload(@_);
-
-	$this->charset($oldCharset);
-	return $fh;
+    
+    return;
 }
 
 1;
@@ -215,7 +140,7 @@
 
 =head1 NAME
 
-C<IMPL::Web::Application> Класс для создания экземпляров приложения
+C<IMPL::Web::Application> Базовай класс для создания экземпляров приложения
 
 =head1 SYNOPSIS
 
@@ -241,4 +166,6 @@
 обработчиков. Цепочка обработчиков вызывается снизу вверх, при этом каждый
 обработчик самостоятельно рекурсивно вызывает следующий (более высокого уровня).
 
+См. также C<IMPL::Web::CGIApplication>
+
 =cut
--- a/Lib/IMPL/Web/Application/Action.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/Application/Action.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -12,12 +12,15 @@
     ],
     props => [
         application => PROP_RO,
-        query => PROP_RO
+        query => PROP_RO,
+        context => PROP_RW
     ]
 };
 
 sub CTOR {
     my ($this) = @_;
+    
+    $this->context({});
 }
 
 sub cookie {
--- a/Lib/IMPL/Web/Application/Resource.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/Application/Resource.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -4,6 +4,7 @@
 use IMPL::Const qw(:prop);
 use IMPL::declare {
     require => {
+        ViewResult          => 'IMPL::Web::ViewResult',
         Exception           => 'IMPL::Exception',
         ArgumentException   => '-IMPL::InvalidArgumentException',
         OperationException  => '-IMPL::InvalidOperationException',
@@ -50,6 +51,8 @@
           allow => join( ',', map( uc, keys %{ $this->contract->verbs } ) )
       )
         unless $operation;
+        
+      $action->context->{resourceLocation} = $this->location; 
 
       return $operation->Invoke( $this, $action );
 }
--- a/Lib/IMPL/Web/AutoLocator.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/AutoLocator.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -1,8 +1,11 @@
 package IMPL::Web::AutoLocator;
 use strict;
 
+use overload '""' => 'toString';
+
 use IMPL::Const qw(:prop);
-use IMPL::lang qw( :hash );
+use IMPL::lang qw(:hash);
+use IMPL::clone qw(clone);
 use URI;
 use URI::Escape;
 use IMPL::declare {
@@ -23,6 +26,12 @@
 	]
 };
 
+sub Clone {
+    my $this = shift;
+    
+    return clone($this);
+}
+
 sub Child {
 	my $this = shift;
 	my $child = shift or die ArgumentException->new("a child resource identifier is required");
@@ -64,6 +73,10 @@
 	return $url;
 }
 
+sub toString {
+    shift->url->as_string();
+}
+
 sub AUTOLOAD {
 	our $AUTOLOAD;
 	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/IMPL/Web/CGIApplication.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -0,0 +1,37 @@
+package IMPL::Web::CGIApplication;
+use strict;
+
+use IMPL::Const qw(:prop);
+use IMPL::declare {
+    require => {
+        CGIWrapper => 'IMPL::Web::CGIWrapper'        
+    },
+    base => [
+        'IMPL::Web::Application' => '@_'
+    ],
+    props => [
+        _queryFetched => PROP_RW
+    ]
+};
+
+sub CTOR {
+    my ($this) = @_;
+    
+    $this->output(\*STDOUT) unless $this->output;
+}
+
+sub FetchRequest {
+    my ($this) = @_;
+    
+    return if $this->_queryFetched;
+    
+    my $query = CGIWrapper->new();
+    
+    $query->charset($this->requestCharset) if $this->requestCharset;
+    
+    $this->_queryFetched(1);
+    
+    return $query;
+}
+
+1;
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/IMPL/Web/CGIWrapper.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -0,0 +1,75 @@
+package IMPL::Web::CGIWrapper;
+use strict;
+
+use parent qw(CGI);
+use Encode;
+
+our $NO_DECODE = 0;
+
+sub param {
+    my $this = shift;
+
+    return $this->SUPER::param(@_) if $NO_DECODE;
+
+    if (wantarray) {
+        my @result = $this->SUPER::param(@_);
+
+        return map Encode::is_utf8($_)
+          ? $_
+          : Encode::decode( $this->charset, $_, Encode::LEAVE_SRC ), @result;
+    }
+    else {
+        my $result = $this->SUPER::param(@_);
+
+        return Encode::is_utf8($result)
+          ? $result
+          : Encode::decode( $this->charset, $result, Encode::LEAVE_SRC );
+    }
+
+}
+
+sub upload {
+    my $this = shift;
+
+    local $NO_DECODE = 1;
+    my $oldCharset = $this->charset();
+    $this->charset('ISO-8859-1');
+
+    my $fh = $this->SUPER::upload(@_);
+
+    $this->charset($oldCharset);
+    return $fh;
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Web::CGIWrapper> - обетрка вокруг стандартного объекта C<CGI>
+
+=head1 DESCRIPTION
+
+Наследуется от C<CGI>, и переопределяет метод C<param> для декодирования
+строковых параметров. В остальном функциональность аналогична стандартному
+модулю C<CGI>.
+
+=head1 MEMBERS
+
+=head2 C<$NO_DECODE>
+
+Глобальная переменная для отключения декодирования параметров.
+
+=begin code
+
+{
+    local $IMPL::Web::CGIWrapper::NO_DECODE = 1;
+    my $raw = $q->param('binary');
+}
+
+=end code 
+
+=cut
\ No newline at end of file
--- a/Lib/IMPL/Web/Handler/RestController.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/Handler/RestController.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -4,6 +4,7 @@
 use IMPL::Const qw(:prop);
 use IMPL::declare {
 	require => {
+	    Locator => 'IMPL::Web::AutoLocator',
 	    ResourceInterface => 'IMPL::Web::Application::ResourceInterface', 
 		Exception => 'IMPL::Exception',
 		ArgumentExecption => '-IMPL::InvalidArgumentException',
@@ -15,7 +16,7 @@
 		'IMPL::Object::Serializable' => undef
 	},
 	props => [
-	   rootResource => PROP_RO,
+	   resourceFactory => PROP_RO,
 	   trailingSlash => PROP_RO
 	]	
 };
@@ -23,8 +24,9 @@
 sub CTOR {
 	my ($this) = @_;
 	
-	die ArgumentException->new(rootResource => "A web-resource is required")
-	   unless eval { $this->rootResource->isa(ResourceInterface) };
+	die ArgumentException->new(resourceFactory => "A web-resource is required")
+	   unless $this->resourceFactory;
+	   #unless eval { $this->resourceFacotry->isa(ResourceInterface) };
 	 
 }
 
@@ -59,7 +61,10 @@
 	
 	my @segments = $this->GetResourcePath($action);
 	
-	my $res = $this->rootResource;
+	my $res = $this->resourceFactory->new(
+	   id => 'root',
+	   location => Locator->new(base => $action->application->baseUrl)
+	);
 	
 	while(@segments) {
 		my $id = shift @segments;
--- a/Lib/IMPL/Web/Handler/TTView.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/Handler/TTView.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -48,7 +48,8 @@
         $view = ViewResult->new(model => $model);
     }
     
-
+    $view->location($action->context->{resourceLocation}) unless $view->location;
+    
     my $vars = {
         view        => $view,
         model       => $model,
--- a/Lib/IMPL/Web/QueryHandler/JsonFormat.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-use strict;
-package IMPL::Transform::Json;
-
-package IMPL::Web::QueryHandler::JsonFormat;
-use parent qw(IMPL::Web::QueryHandler);
-use Error qw(:try);
-use JSON;
-
-sub Process {
-    my ($this,$action,$nextHandler) = @_;
-    
-    my $result;
-    
-    try {
-        $result = $nextHandler->();
-        $result = [$result] unless ref $result;
-    } otherwise {
-        my $err = shift;
-        $result = { error => $err };
-    };
-    
-    my $t = new IMPL::Transform::Json($action->context->{json});
-    
-    if ($action->context->{transactionType} and $action->context->{transactionType} eq 'form') {
-        delete @$result{qw(formData formSchema)};
-        my $errors = @$result{formErrors};
-        
-        $result->{formErrors} = [ map $_->Message, @$errors ] if $errors;
-    }
-    
-    $action->response->contentType('text/javascript');
-    
-    my $hout = $action->response->streamBody;
-    print $hout to_json( $t->Transform($result), {pretty => 1} );
-} 
-
-package IMPL::Transform::Json;
-
-use parent qw(IMPL::Transform);
-use IMPL::Class::Property;
-use IMPL::Class::Property::Direct;
-use Scalar::Util qw(refaddr);
-
-BEGIN {
-    private _direct property _visited => prop_none;
-}
-
-my %propListCache;
-
-our %CTOR = (
-    'IMPL::Transform' => sub {
-        my $options = shift;
-        (
-            $options ? %{$options} : ()
-        ),
-        ARRAY => sub {
-            my ($this,$object) = @_;
-            
-            return [
-                map { $this->Transform($_) } @$object
-            ];    
-        },
-        HASH => sub {
-            my ($this,$object) = @_;
-            
-            return {
-                map { $_, $this->Transform($object->{$_}) } keys %$object
-            };
-        },
-        'IMPL::Object::List' => sub {
-            my ($this,$object) = @_;
-            
-            return [
-                map { $this->Transform($_) } @$object
-            ]; 
-        },
-        -plain => sub {
-            $_[1];
-        },
-        -default => sub {
-            my ($this,$object) = @_;
-            
-            return "$object" unless $object->isa('IMPL::Object::Abstract');
-            
-            if ( $object->isa(typeof IMPL::Exception) ) {
-                return {
-                    type => $object->typeof,
-                    message => $object->Message,
-                    arguments => $this->Transform(scalar $object->Args)
-                };
-            }
-            
-            my $propList = $propListCache{ref $object};
-            unless ( $propList ) {
-                my %props = map {
-                    $_->Name, (ref $_->Mutators ? 0 : ($_->Mutators & prop_list))
-                } $object->get_meta('IMPL::Class::PropertyInfo',sub { $_->Access == IMPL::Class::Member::MOD_PUBLIC and $_->Name !~ /^_/}, 1 );
-                
-                $propListCache{ref $object} = $propList = \%props;
-            }
-            
-            return {
-                map {
-                    $_, $propList->{$_} ? $this->Transform([$object->$_()]) : $this->Transform(scalar $object->$_());
-                } keys %$propList
-            };
-        }
-    }
-);
-
-sub Transform {
-    my ($this,$object) = @_;
-    
-    # small hack to prevent cycling
-    
-    return $this->SUPER::Transform($object) unless ref $object;
-    
-    if (exists $this->{$_visited}{refaddr $object}) {
-        return $this->{$_visited}{refaddr $object};
-    } else {
-        $this->{$_visited}{refaddr $object} = undef;
-        return $this->{$_visited}{refaddr $object} = $this->SUPER::Transform($object);
-    }
-}
-
-1;
--- a/Lib/IMPL/Web/QueryHandler/PageFormat.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,202 +0,0 @@
-package IMPL::Web::QueryHandler::PageFormat;
-use parent qw(IMPL::Web::QueryHandler IMPL::Object::Autofill);
-use strict;
-
-__PACKAGE__->PassThroughArgs;
-
-use JSON;
-use IMPL::Class::Property;
-use IMPL::Web::TT::Document;
-use Template::Plugin::URL;
-use IMPL::Security::Context();
-use File::Spec();
-use HTML::TreeBuilder();
-use URI();
-use Error qw(:try);
-use Encode();
-
-$Template::Plugin::URL::JOINT = '&';
-
-BEGIN {
-    public property templatesCharset => prop_all;
-    public property templatesBase => prop_all;
-    public property includes => prop_all | prop_list;
-    public property pathinfoPrefix => prop_all;
-    public property cache => prop_all;
-    public property preprocess => prop_all;
-    public property formatOutput => prop_all;
-    public property template => prop_all;
-}
-
-sub CTOR {
-    my ($this) = @_;
-    
-    $this->templatesCharset('utf-8') unless $this->templatesCharset;
-    $this->cache(File::Spec->rel2abs($this->cache)) if $this->cache;
-    $this->templatesBase(File::Spec->rel2abs($this->templatesBase)) if $this->templatesBase;
-}
-
-sub Process {
-    my ($this,$action,$nextHandler) = @_;
-    
-    my $doc = new IMPL::Web::TT::Document(cache => $this->cache, preprocess => $this->preprocess);
-    
-    try {
-
-        $this->templatesBase($ENV{DOCUMENT_ROOT}) unless $this->templatesBase;
-        
-        my ($requestUri) = split( /\?/, $ENV{REQUEST_URI} );
-        
-        my $pathInfo;
-        my @root = ('');
-        my @base;
-        
-        if ( $requestUri eq $ENV{SCRIPT_NAME}.$ENV{PATH_INFO} ) {
-            # CGI with path info, for example
-            # /base/cgi-bin/myscript.cgi/path/info
-            # PATH_INFO will be /path/info
-            $pathInfo = $ENV{PATH_INFO};
-        } else {
-            # usual url, for exmaple
-            # /base/script.cgi will have PATH_INFO /base/script.cgi
-            # /base/ will have PATH_INFO /base/index.cgi (if index.cgi is a DirectoryIndex)
-            $pathInfo = $ENV{PATH_INFO};
-            
-            if (my $rx = $this->pathinfoPrefix) {
-                $requestUri =~ s/^($rx)//;
-                $pathInfo =~ s/^($rx)//;
-                push @root, grep $_, split /\//, $1 if $1;
-            }
-        }
-        
-        @base = grep $_, split /\//, ($pathInfo ? substr $requestUri,0, -length($pathInfo) : $requestUri);
-        
-        local $ENV{PATH_INFO} = $pathInfo;
-        
-        my @path = grep $_, split /\//, ($ENV{PATH_INFO} || '') or die new IMPL::Exception("PATH_INFO is empty and no defaultTarget specified" );
-        
-        my @pathContainer = @path;
-        pop @pathContainer;
-        
-        $doc->LoadFile (
-            ($this->template || File::Spec->catfile($this->templatesBase,@path)),
-            $this->templatesCharset,
-            [$this->templatesBase, $this->includes],
-            {
-                result => scalar($nextHandler->()),
-                action => $action,
-                app => $action->application,
-        
-                absoluteUrl => sub { new URI(join ('/', @root, $_[0]) ) },
-                baseUrl => sub { new URI (join ('/', @root, @base, $_[0]) ) },
-                relativeUrl => sub { new URI(join ('/', @root, @base, @pathContainer,$_[0]) ) },
-        
-                user => IMPL::Security::Context->current->principal,
-                session => IMPL::Security::Context->current,
-        
-                to_json => \&to_json,
-                escape_string => sub { $_[0] =~ s/"/&quot;/g; $_[0] },
-            }
-        );
-        
-        $action->response->contentType('text/html');
-        my $hOut = $action->response->streamBody;
-        if ($this->formatOutput == 1) {
-            my $tree = new HTML::TreeBuilder();
-            try {
-                $tree->parse_content($doc->Render());
-                print $hOut $tree->as_HTML('<>&',"    ",{});
-            } finally {
-                $tree->delete;
-            };
-        } elsif ($this->formatOutput() == 2 ) {
-            (my $data = $doc->Render()) =~ s/\s+/ /g;
-            print $hOut $data;
-        } else {
-            print $hOut $doc->Render();
-        }
-    } finally {
-        $doc->Dispose;
-    };
-}
-
-sub URI::_query::new_params {
-    my ($this,$params) = @_;
-    
-    my $clone = $this->clone;
-    if (ref $params eq 'HASH' ) {
-        my %newParams = ($clone->query_form , %$params);
-        $clone->query_form(map { $_, ( Encode::is_utf8( $newParams{$_} ) ? Encode::encode('utf-8', $newParams{$_}) : $newParams{$_} ) } sort keys %newParams );
-    }
-    return $clone;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 NAME
-
-C<IMPL::Web::QueryHandler::PageFormat> - Выдача результатов в виде HTML страницы, построенной из шаблона.
-
-=head1 SYNOPSIS
-
-В файле конфигурации приложения
-
-=begin code xml
-
-<handlersQuery type="IMPL::Object::List">
-    <item type="IMPL::Web::QueryHandler::PageFormat">
-        <charsetTemplates>utf-8</charsetTemplates>
-    </item>
-</handlersQuery>
-
-=end code xml
-
-Программно
-
-=begin code
-
-my $app = new IMPL::Web::Application();
-$app->handlersQuery->Add(
-    new IMPL::Web::QueryHandler::PageFormat( charsetTemplates=> 'utf-8' );
-);
-
-=end
-
-=head1 DESCRIPTION
-
-Обработчик запроса для веб приложения. Загружает шаблон, путь к котрому берется
-из C<ENV{PATH_INFO}> относительно пути из свойства C<templatesBase>.
-
-Наследуется от C<IMPL::Web::QueryHandler> для реализации функционала
-обработчика запроса и переопределяет метод C<Process>.
-
-C<Serializable>
-
-=head1 MEMBERS
-
-=over
-
-=item C<CTOR(%props)>
-
-Создает новый экземпляр и заполняет свойства.
-
-=item C<[get,set] templatesCharset>
-
-Кодировка шаблонов. По умолчанию utf-8.
-
-=item C<[get,set] templatesBase>
-
-Каталог относительно которого ищется шаблон.
-
-=item C<[override] Process($action,$nextHandler)>
-
-Метод, переопределяющий C<IMPL::Web::QueryHandler->Process> и которому передается управление
-для выполнения действий.
-
-=back
-
-=cut
--- a/Lib/IMPL/Web/QueryHandler/PathInfoRewrite.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,26 +0,0 @@
-package IMPL::Web::QueryHandler::PathInfoRewrite;
-use strict;
-
-use parent qw(IMPL::Web::QueryHandler);
-__PACKAGE__->PassThroughArgs;
-
-use IMPL::Class::Property;
-
-BEGIN {
-    public property pathinfoPrefix => prop_all;
-}
-
-sub Process {
-    my ($this,$query,$nextHandler) = @_;
-    
-    my $pathInfo = $ENV{PATH_INFO};
-    if (my $rx = $this->pathinfoPrefix) {
-        $pathInfo =~ s/^($rx)//;
-    }
-    
-    local $ENV{PATH_INFO} = $pathInfo;
-    
-    scalar $nextHandler->();
-}
-
-1;
--- a/Lib/IMPL/Web/QueryHandler/SecureCookie.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-package IMPL::Web::QueryHandler::SecureCookie;
-use strict;
-
-use parent qw(IMPL::Web::QueryHandler);
-use Digest::MD5 qw(md5_hex);
-
-use IMPL::Class::Property;
-use IMPL::Security::Auth qw(:Const);
-use IMPL::Security;
-
-BEGIN {
-    public property salt => prop_all;
-}
-
-sub CTOR {
-    my ($this) = @_;
-    
-    $this->salt('DeadBeef') unless $this->salt;
-}
-
-sub Process {
-    my ($this,$action,$nextHandler) = @_;
-    
-    return undef unless $nextHandler;
-    
-    local $IMPL::Security::authority = $this;
-    
-    my $method = $action->query->cookie('method') || 'simple';
-    
-    if ($method eq 'simple') {
-        
-        my $sid = $action->query->cookie('sid'); 
-        my $cookie = $action->query->cookie('sdata');
-        my $sign = $action->query->cookie('sign'); 
-        
-        if (
-            $sid and
-            $cookie and
-            $sign and
-            $sign eq md5_hex(
-                $this->salt,
-                $sid,
-                $cookie,
-                $this->salt
-            )
-        ) {
-            # TODO: add a DefferedProxy to deffer a request to a data source
-            my $context = $action->application->security->sourceSession->find(
-                { id => $sid }
-            ) or return $nextHandler->();
-            
-            my ($result,$challenge) = $context->auth->ValidateSession($cookie);
-            
-            if ($result == AUTH_SUCCESS) {
-                $context->authority($this);
-                return $context->Impersonate($nextHandler);                
-            } else {
-                return $nextHandler->();
-            }
-        } else {
-            return $nextHandler->();
-        }
-    } else {
-        return $nextHandler->();
-    }
-}
-
-sub WriteResponse {
-    my ($this,$response,$sid,$cookie,$method) = @_;
-
-    my $sign = md5_hex(
-        $this->salt,
-        $sid,
-        $cookie,
-        $this->salt
-    );
-    
-    $response->setCookie(sid => $sid);
-    $response->setCookie(sdata => $cookie);
-    $response->setCookie(sign => $sign);
-    $response->setCookie(method => $method) if $method;
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 NAME
-
-C<IMPL::Web::QueryHandler::SecureCookie>
-
-=head1 DESCRIPTION
-
-C<use parent qw(IMPL::Web::QueryHandler)>
-
-Возобновляет сессию пользователя на основе информации переданной через Cookie.
-
-Использует механизм подписи информации для проверки верности входных данных перед
-началом каких-либо действий.
-
-Данный обработчик возвращает результат выполнения следдующего обработчика.
-
-=head1 MEMBERS
-
-=over
-
-=item C<[get,set] salt>
-
-Скаляр, использующийся для подписи данных.
-
-=back
-
-=cut
--- a/Lib/IMPL/Web/QueryHandler/UrlController.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-package IMPL::Web::QueryHandler::UrlController;
-use strict;
-use parent qw(IMPL::Web::QueryHandler);
-
-use IMPL::Class::Property;
-use IMPL::Exception;
-use Carp qw(croak);
-use Scalar::Util qw(tainted);
-
-BEGIN {
-    public property namespace => prop_all;
-}
-
-__PACKAGE__->PassThroughArgs;
-
-sub Process {
-    my ($this,$action,$nextHandler) = @_;
-    
-    my $namespace = $this->namespace || $action->application->typeof;
-    
-    my @target = grep $_, split /\//, ($ENV{PATH_INFO} || '') or die new IMPL::Exception("No target specified");
-    
-    my $method = pop @target;
-    if ( $method =~ /^(\w+)/ ) {
-        $method = $1;
-    } else {
-        die new IMPL::Exception("Invalid method name",$method);
-    }
-    
-    (/^(\w+)$/ or die new IMPL::Exception("Invalid module name part", $_)) and $_=$1 foreach @target;
-    
-    my $module = join '::',$namespace,@target;
-    
-    die new IMPL::Exception("A module name is untrusted", $module) if tainted($module);
-    
-    eval "require $module; 1;" unless eval{ $module->can('InvokeAction'); };
-    if (my $err = $@ ) {
-        die new IMPL::Exception("Failed to load module",$module,$err);
-    }
-    
-    if(UNIVERSAL::can($module,'InvokeAction')) {
-        $module->InvokeAction($method,$action);
-    } else {
-        die new IMPL::InvalidOperationException("Failed to invoke action",$ENV{PATH_INFO},$module,$method);
-    }
-}
-
-1;
-
-__END__
-
-=pod
-
-=head1 NAME
-
-C<IMPL::Web::QueryHandler::UrlController> - вызов метода на основе C<url> запроса.
-
-=head1 DESCRIPTION
-
-Использует переменную C<$ENV{PATH_INFO}> для получения имени и метода модуля.
-Например запрос C<http://localhost/User/register.html> интерпретируется как вызов метода C<register>
-у модуля C<User>. 
-
-=head1 MEMBERS
-
-=head2 PROPERTIES
-
-=over
-
-=item C<[get,set] namespace>
-
-Пространство имен в котором находится модуль. по умолчению совпадает с именем класса приложения, например C<My::App>
-
-=back
-
-=cut
--- a/Lib/IMPL/Web/TT/Collection.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,41 +0,0 @@
-package IMPL::Web::TT::Collection;
-use strict;
-
-use parent qw(IMPL::DOM::Node);
-
-__PACKAGE__->PassThroughArgs;
-
-our $AUTOLOAD;
-sub AUTOLOAD {
-    my $this = shift;
-    my ($method) = ($AUTOLOAD =~ /(\w+)$/);
-    
-    return if $method eq 'DESTROY';
-    
-    if ( @_ >= 1 ) {
-        # set
-        
-        if ($method =~ /^add(\w+)/) {
-            my ($name,$args) = @_;
-            return $this->appendChild($this->document->CreateControl($name,$1,$args));
-        }
-        
-        # we can't assing a node, so this is a dynamic property
-        return $this->nodeProperty($method,@_);
-    } else {
-        # get
-        # try a dynamic property first 
-        if ( my $val = $this->nodeProperty($method) ) {
-            return $val;
-        } else {
-        # and return a first child node as last opportunity
-            my @result = $this->selectNodes($method);
-    
-            return $result[0] if @result;
-        }
-    }
-    
-    return;
-}
-
-1;
--- a/Lib/IMPL/Web/TT/Control.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-package IMPL::Web::TT::Control;
-
-use parent qw(IMPL::Web::TT::Collection);
-
-
-use IMPL::Class::Property;
-use IMPL::DOM::Property qw(_dom);
-
-__PACKAGE__->PassThroughArgs;
-
-BEGIN {
-    public property controlClass => prop_all;
-    public property template => prop_all;
-    public property id => prop_all;
-}
-
-my $nextId = 1;
-
-sub CTOR {
-    my ($this,%args) = @_;
-    
-    if ($this->document) {
-        # load a template
-        $this->template( $this->document->context->template($args{template})) if ($args{template} and not ref $args{template});
-    }
-    #$this->template($args{template}) if $args{template};
-
-    $this->id($this->nodeName . '-' . $nextId++);
-    $this->controlClass('Control') unless $this->controlClass;
-}
-
-sub Render {
-    my ($this) = @_;
-    
-    if ($this->document) {
-        if ($this->template) {
-            return $this->document->context->include($this->template,{ this => $this }) ;
-        } elsif ($this->document->presenter) {
-            return $this->document->presenter->print($this);
-        } else {
-            return $this->toString().": ".$this->controlClass() . ": ".$this->path;
-        }
-    }
-}
-1;
--- a/Lib/IMPL/Web/TT/Document.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,381 +0,0 @@
-package IMPL::Web::TT::Document;
-use strict;
-use warnings;
-
-use parent qw(IMPL::DOM::Document IMPL::Object::Disposable);
-use Template::Context;
-use Template::Provider;
-use IMPL::Class::Property;
-use File::Spec;
-use Scalar::Util qw(blessed);
-use IMPL::Web::TT::Collection;
-use IMPL::Web::TT::Control;
-use Carp;
-use Encode();
-use Data::Dumper;
-
-BEGIN {
-    private property _provider => prop_all;
-    private property _context => prop_all;
-    public property cache => prop_all;
-    public property template => prop_get | owner_set;
-    public property presenter => prop_all, { validate => \&_validatePresenter };
-    public property preprocess => prop_all | prop_list,
-    public property title => prop_all;
-    private property _controlClassMap => prop_all;
-}
-
-our %CTOR = (
-    'IMPL::DOM::Document' => sub { nodeName => 'document' }
-);
-
-sub CTOR {
-    my ($this,%args) = @_;
-    
-    $this->_controlClassMap({});
-    $this->registerControlClass( Control => 'IMPL::Web::TT::Control' );
-    $this->appendChild( $this->Create(body => 'IMPL::Web::TT::Collection') );
-    $this->appendChild( $this->Create(head => 'IMPL::Web::TT::Collection') );
-    $this->cache($args{cache}) if $args{cache};
-    $this->preprocess($args{preprocess}) if $args{preprocess};
-}
-
-sub CreateControl {
-    my ($this,$name,$class,$args) = @_;
-    
-    $args = {} unless ref $args eq 'HASH';
-    
-    if (my $info = $this->_controlClassMap->{$class}) {
-        my %nodeArgs = (%{$info->{args}},%$args);
-        $nodeArgs{controlClass} = $class;
-        
-        return $this->Create($name,$info->{type},\%nodeArgs);
-    } else {
-        die new IMPL::Exception('A control is\'t registered', $class, $name);
-    }
-}
-
-sub provider {
-    my ($this,%args) = @_;
-    
-    if (my $provider = $this->_provider) {
-        return $provider;
-    } else {
-        return $this->_provider(new Template::Provider(
-            \%args
-        ));
-    }
-}
-
-sub context {
-    my ($this) = @_;
-    
-    if (my $ctx = $this->_context) {
-        return $ctx;
-    } else {
-        return $this->_context (
-            new Template::Context(
-                VARIABLES => {
-                    document => $this,
-                    this => $this,
-                    render => sub {
-                        $this->_process(@_);
-                    },
-                    encode => sub {
-                        Encode::encode('utf8',shift);
-                    },
-                    dump => sub {
-                        Dumper(shift);
-                    },
-                    as_list => sub {
-                        [ map ref($_) eq 'ARRAY' ? @$_ : $_, @_ ]
-                    }
-                },
-                RECURSION => 1,
-                LOAD_TEMPLATES => [$this->provider]
-            )
-        )
-    }
-}
-
-sub resolveVar {
-    my ($this,$var) = @_;
-    
-    return $this->context->stash->get($var);
-}
-
-sub registerControlClass {
-    my ($this, $controlClass, $type, $args) = @_;
-    
-    $type ||= 'IMPL::Web::TT::Control';
-    
-    die new IMPL::InvalidArgumentException("A controlClass must be a single word",$controlClass) unless $controlClass =~ /^\w+$/;
-    
-    eval "require $type; 1;" or die new IMPL::Exception("Failed to load a module",$type,"$@") unless eval { $type->can('new') };
-    
-    die new IMPL::InvalidArgumentException("A type must be subclass of IMPL::DOM::Node",$type) unless $type->isa('IMPL::DOM::Node');
-    
-    # resolve template name to a real template
-    $args->{template} = $this->context->template($args->{template}) if $args->{template};
-    
-    $this->_controlClassMap->{$controlClass} = {
-        controlClass => $controlClass,
-        type => $type,
-        args => ref $args eq 'HASH' ? $args : {}
-    };
-}
-
-sub require {
-    my ($this,$template) = @_;
-    
-    my $doc = $this->context->template($template);
-    
-    die new IMPL::InvalidOperationException("A specified template isn't a document",$template) unless eval{ $doc -> isa('Template::Document') };
-    
-    my $controlClass = $doc->class;
-    my $type = $doc->nativeType;
-    my $controlTemplate;
-    my $out = "";
-    
-    die new IMPL::InvalidOperationException("A specified template isn't a control",$template) unless $controlClass;
-    
-    if (not $this->isControlClass($controlClass)) {
-        if ($doc->template) {
-            $controlTemplate = $doc->blocks()->{$doc->template} || $this->context->template($doc->template);
-            $out = $this->context->include($doc);
-        } else {
-            $controlTemplate = $doc;
-        }
-        $this->registerControlClass($controlClass,$type,{ template => $controlTemplate } );
-    }
-    
-    return $out;
-}
-
-sub isControlClass {
-    my ($this,$name) = @_;
-    return $this->_controlClassMap->{$name} ? 1 : 0;
-}
-
-sub _getControls {
-    my ($this) = @_;
-    
-    my ($node) = $this->selectNodes('controls');
-    return $node;
-}
-
-sub _validatePresenter {
-    my ($this,$value) = @_;
-    
-    die new IMPL::InvalidArgumentException("A view object is required") unless blessed($value) and $value->isa('Template::View');
-}
-
-sub LoadFile {
-    my ($this,$src,$encoding,$includes,$vars) = @_;
-    
-    die new IMPL::InvalidArgumentException("A template parameter is required") unless $src;
-    
-    $includes = [$includes] if $includes and not ref $includes;
-    
-    $encoding ||= 'utf8';
-    
-    $this->_context(undef);
-    $this->_provider(undef);
-    
-    if (not ref $src) {
-        my ($vol,$dir,$fileName) = File::Spec->splitpath($src);
-        unshift @$includes, File::Spec->catpath($vol,$dir,'');
-        $src = $fileName;
-    }
-    
-    $this->provider(
-        ENCODING => $encoding,
-        INTERPOLATE => 1,
-        PRE_CHOMP => 1,
-        POST_CHOMP => 1,
-        TRIM => 0,
-        COMPILE_EXT => $this->cache ? '.ttc' : undef,
-        COMPILE_DIR => $this->cache,
-        INCLUDE_PATH => $includes 
-    );
-    
-    if ($vars) {
-        while ( my ($var,$val) = each %$vars ) {
-            $this->AddVar($var,$val);
-        }
-    }
-    
-    $this->context->process($_) foreach $this->preprocess;
-    
-    my $template = $this->context->template($src);
-    $this->title($template->title);
-    if ( $template->template ) {
-        $this->context->process($template);
-        $this->template($template->template);
-    } else {
-        $this->template($template);
-    }
-    
-}
-
-sub AddVar {
-    my ($this,$name,$value) = @_;
-    
-    $this->context->stash->set($name,$value);
-}
-
-sub Render {
-    my ($this) = @_;
-    
-    return $this->context->process($this->template);
-}
-
-# Формирует представление для произвольных объектов 
-sub _process {
-    my ($this,@items) = @_;
-    
-    my @result;
-    
-    foreach my $item (@items) {
-        if (blessed($item) and $item->isa('IMPL::Web::TT::Control')) {
-            push @result, $item->Render();    
-        } elsif(blessed($item)) {
-            if ($this->presenter) {
-                push @result, $this->presenter->print($item);
-            } else {
-                push @result, $this->toString;
-            }
-        } else {
-            push @result, $item;
-        }
-    }
-    
-    return join '',@result;
-}
-
-our $AUTOLOAD;
-sub AUTOLOAD {
-    my $this = shift;
-    my ($method) = ($AUTOLOAD =~ /(\w+)$/);
-    
-    if($method =~ /^create(\w+)/) {
-        my ($name,$args) = @_;
-        return $this->CreateControl($name,$1,$args);
-    }
-    
-    my @result = $this->selectNodes($method);
-    
-    return $result[0] if @result;
-    carp "Looks like you have a mistake, the document doesn't have a such property or child: $method";
-    return;
-}
-
-sub Dispose {
-    my ($this) = @_;
-    
-    $this->template(undef);
-    $this->_context(undef);
-    $this->_provider(undef);
-    
-    $this->supercall::Dispose();
-}
-
-1;
-__END__
-=pod
-
-=head1 NAME
-
-C<IMPL::Web::TT::Document> - Документ, позволяющий строить представление по шаблону
-
-=head1 SYNOPSIS
-
-=begin code 
-
-// create new document
-my $doc = new IMPL::Web::TT::Document;
-
-// load template
-$doc->loadFile('Templates/index.tt');
-
-// render file
-print $doc->Render();
-
-=end code
-
-=head1 DESCRIPTION
-
-C<use parent qw(IMPL::DOM::Document)>
-
-Документ, основанный на шаблоне Template::Toolkit. Позволяет загрузить шаблон,
-и сформировать окончательный документ. Является наследником C<IMPL::DOM::Node>,
-т.о. может быть использован для реализации DOM модели.
-
-Внутри шаблона переменная C<document> ссылается на объект документа. По этой
-причине образуется циклическая ссылка между объектами шаблона и документом, что
-требует вызова метода C<Dispose> для освобождения документа.
-
-=head1 METHODS
-
-=over
-
-=item C<CTOR()>
-
-Создает новый экземпляр документа, свойство C<nodeName> устанавливается в 'C<document>'
-
-=item C<$doc->LoadFile($fileName,$encoding)>
-
-Загружает шаблон из файла C<$fileName>, используя кодировку C<$encoding>. Если
-кодировка не указана, использует utf-8.
-
-=item C<$doc->Render()>
-
-Возвращает данные построенные на основе загруженного шаблона.
-
-=item C<$doc->Dispose()>
-
-Освобождает ресурсы и помечает объект как освобожденный.
-
-=back
-
-=head1 DOM
-
-Документ представляет собой DOM документ, состоящий из узлов, которые представляют собой данные
-для отображения. Для форматированого вывода используется C<template>.
-
-В качестве элементов документа могут присутсвовать специальные объекты C<IMPL::Web::TT::Control>,
-которые внутри содержат шаблон для форматирования собственного содержимого.
-
-
-
-Документ предоставляет ряд фнукций для работы с элементами управления.
-
-=head1 TEMPLATE
-
-=begin code html
-
-[% CALL document.registerClass( 'Table', 'My::TableClass', template => 'tables/pretty.tt' ) %]
-[% CALL document.registerClass( 'Form' )%]
-
-[% table = document.сreateTable('env') %]
-
-[% FOEACH item in document.result %]
-    [% table.rows.Add( item.get('name','value') ) %]
-[% END %]
-
-[% form = document.createForm('login') %]
-[% form.template = 'LOGIN_FORM'%]
-
-[% FOREACH item IN document.childNodes %]
-    [%render(item)%]
-[% END %]
-    
-[% BLOCK LOGIN_FORM %]
-<form method="POST" action='/login.pl'>
-    user: [% render(this.item('name')) %] password: [% render(this.item('password')) %] <input type="submit"/>
-</form>
-[% END %]
-
-=end code html
-
-=cut
--- a/Lib/IMPL/Web/TT/Form.pm	Fri Oct 19 02:23:15 2012 +0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,218 +0,0 @@
-use strict;
-package IMPL::Web::TT::Form;
-
-use parent qw(IMPL::Web::TT::Control);
-
-use IMPL::Class::Property;
-use IMPL::DOM::Navigator::SchemaNavigator();
-
-__PACKAGE__->PassThroughArgs;
-
-BEGIN {
-    public property base => prop_all;
-    public property schema => prop_all;
-    public property errors => prop_all;
-    public property data => prop_all;
-    public property state => prop_all;
-    public property formResult => prop_all;
-}
-
-sub CTOR {
-    my ($this) = @_;
-    
-    if (my $form = $this->formResult) {
-        $this->base($form->{formName});
-        $this->errors($form->{formErrors});
-        $this->data($form->{formData});
-        $this->schema($form->{formSchema});
-        $this->state($form->{state});
-    } else {
-    
-        $this->base($this->nodeName) unless $this->base;
-        
-        die new IMPL::InvalidArgumentException('A schema is required for a form',$this->nodeName)
-            unless eval { $this->schema->isa( typeof IMPL::DOM::Schema ) };
-        
-        die new IMPL::InvalidOperationException('Can\'t find a form definition in a schema',$this->nodeName,$this->base)
-            unless $this->schema->selectNodes(sub { $_->nodeName eq 'ComplexNode' and $_->name eq $this->base });
-    }
-            
-    $this->errors([]) unless $this->errors;
-}
-
-sub fillContents {
-    my ($this) = @_;
-    
-    my $schema = $this->schema->selectSingleNode(sub { $_->nodeName eq 'ComplexNode' and $_->name eq $this->base });
-    
-    $this->buildContainer(
-        $schema,
-        $schema,
-        $this->data->isComplex ? $this->data : undef,
-        $this
-    );
-}
-
-sub buildContainer {
-    my ($this,$schemaSource,$schema,$domNode,$container,$path) = @_;
-    
-    $path = [@{$path || []},{node => $domNode, schemaSource => $schemaSource}];
-    
-    $container ||= $this->document->Create($schemaSource->name,'IMPL::Web::TT::Collection');
-    
-    foreach my $schemaItem ( $schema->content->childNodes ) {
-        my $schemaItemSource = $schemaItem;
-        
-        $schemaItem = $this->schema->resolveType($schemaItem->type)
-            if typeof $schemaItem eq typeof IMPL::DOM::Schema::Node;
-            
-        my @nodesData = $domNode->selectNodes(sub { $_->schemaSource == $schemaItemSource } ) if $domNode;
-        
-        push @nodesData, undef unless @nodesData;
-            
-        if ($schemaItem->isa(typeof IMPL::DOM::Schema::ComplexNode) ) {
-            $this->appendChild( $this->buildContainer($schemaItemSource,$schemaItem,$_,undef,$path) ) foreach @nodesData;
-        } elsif ($schemaItem->isa(typeof IMPL::DOM::Schema::SimpleNode)) {
-            $this->appendChild( $this->buildControl($schemaItemSource,$schemaItem,$_,$path) ) foreach @nodesData;
-        }
-    }
-    
-    return $container;
-}
-
-sub buildControl {
-    my ($this,$schemaSource,$schema,$node,$path) = @_;
-    
-    my @errors;
-    
-    if ($node) {
-        @errors = grep { ($_->Node || $_->Parent) == $node } @{$this->errors}; 
-    } else {
-        @errors = grep $_->Schema == $schemaSource, @{$this->errors};
-    }
-    
-    return $this->document->CreateControl(
-        $schemaSource->name,
-        $this->mapType($schemaSource),
-        {
-            schema => $schema,
-            sourceSchema => $schemaSource,
-            errors => \@errors,
-            data => $node,
-            inputType => $schemaSource->nodeProperty('inputType') || $schema->nodeProperty('inputType'),
-            nodeValue => $node && $node->nodeValue, # small hack set a non dom class property through
-            queryParameter => $this->makeParameterName([@$path,{ node => $node, schemaSource => $schemaSource}])
-        }
-    );
-}
-
-sub mapType {
-    my ($this,$schema) = @_;
-    
-    $schema->nodeProperty('control') ||
-    ( $schema->type && $this->schema->resolveType($schema->type)->nodeProperty('control') )
-        or die new IMPL::Exception("Unable to get control class for the form element",$schema->path);
-}
-
-sub makeParameterName {
-    my ($this,$path) = @_;
-    
-    join '/', map {
-        $_->{node} ?
-            (
-                $_->{node}->nodeProperty('instanceId') ?
-                    $_->{node}->nodeName . '['. ']' :
-                    $_->{node}->nodeName
-            ) :
-            (
-                $_->{schemaSource}->maxOccur eq 'unbounded' || $_->{schemaSource}->maxOccur > 1 ?
-                    $_->{schemaSource}->name . '[0]' :
-                    $_->{schemaSource}->name
-            ) 
-    } @$path;
-}
-
-sub makeControlArgs{
-    my ($this,$path) = @_;
-    
-    my $navi = new IMPL::DOM::Navigator::SchemaNavigator($this->schema);
-    my @path = ($this->base, split(/\./,$path) ); 
-    
-    $navi->NavigateName($_) or die new IMPL::InvalidArgumentException(
-        "Can't find a definition for an element",
-        $_,
-        $path,
-        $this->element,
-    ) foreach @path;
-    
-    my $schema = $navi->Current;
-    my $sourceSchema = $navi->SourceSchemaNode;
-    my $queryParameter = join '/', @path;
-    shift @path;
-    my $node = $this->data ? $this->data->selectSingleNode(@path) : undef;
-    
-    my @errors;
-    
-    if ($node) {
-        @errors = grep { ($_->Node || $_->Parent) == $node } @{$this->errors}; 
-    } else {
-        @errors = grep $_->Schema == $sourceSchema, @{$this->errors};
-    }
-    
-    return {
-        schema => $schema,
-        sourceSchema => $sourceSchema,
-        errors => \@errors,
-        data => $node,
-        nodeValue => $node && $node->nodeValue, # small hack set a non dom class property through
-        queryParameter => $queryParameter,
-        inputType => $sourceSchema->nodeProperty('inputType') || $schema->nodeProperty('inputType')
-    };
-}
-
-sub makeContent {
-    my ($this,$mappings) = @_;
-    
-    my $formSchema = $this->schema->selectSingleNode(sub { $_->nodeName eq 'ComplexNode' and $_->name eq $this->base } )
-        or die new Exception("Cant find a schema element for the specified form", $this->base);
-
-    my $doc = $this->document;        
-    foreach my $itemSchema ( $formSchema->content->childNodes ) {
-        my $itemName = $itemSchema->name; 
-        if (my $controlClass = $mappings->{$itemName} ) {
-            my $contorl = $doc->CreateControl($itemName,$controlClass,$this->makeControlArgs($itemName));
-            $this->appendChild($contorl);
-        }
-    }
-    return;
-}
-
-sub formErrors {
-    my ($this) = @_;
-    
-    if (my $node = $this->data ) {
-        return [
-            grep {
-                ( $_->Node || $_->Parent) == $node
-            } @{$this->errors}
-        ];
-    } else {
-        return [];
-    }
-}
-
-1;
-__END__
-
-=pod
-
-=head1 NAME
-
-C<IMPL::Web::TT::Form> - Форма с элементами
-
-=head1 DESCRIPTION
-
-Является элементом управления, тоесть для своего преобразования ипользует
-шаблон 
-
-=cut
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Lib/IMPL/Web/View/TemplateView.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -0,0 +1,15 @@
+package IMPL::Web::View::TemplateView;
+use strict;
+
+use IMPL::Const qw(:prop);
+use IMPL::declare {
+    base => [
+        'IMPL::Web::ViewResult' => '@_'
+    ],
+    props => [
+        template => PROP_RW,
+        defaultTemplate => PROP_RW
+    ]
+};
+
+1;
\ No newline at end of file
--- a/Lib/IMPL/Web/ViewResult.pm	Fri Oct 19 02:23:15 2012 +0400
+++ b/Lib/IMPL/Web/ViewResult.pm	Mon Oct 22 04:09:27 2012 +0400
@@ -9,8 +9,48 @@
         'IMPL::Object::Autofill' => '@_'
     ],
     props => [
-        model => PROP_RW
+        model => PROP_RW,
+        location => PROP_RW
     ]
 };
 
-1;
\ No newline at end of file
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Web::ViewResult> - описание представления результата.
+
+=head1 SYNOPSIS
+
+=begin code
+
+sub HttpGet {
+    my ($this, $action) = @_;
+    
+    return IMPL::Web::ViewResult->new(
+        model => $model,
+        location => $this->location
+    );
+}
+
+=end code
+
+=head1 DESCRIPTION
+
+Сожержит в себе информацию для представления модели.
+
+=head1 MEMBERS
+
+=head2 C<[get,set]model>
+
+Модель ресурса, как правило это результат выполнения C<Http> метода.
+
+=head2 C<[get,set]location>
+
+Текущий абсолютный адрес ресурса.   
+
+=cut