changeset 256:32aceba4ee6d

corrected ViewHandlers to handle cookies and headers. Dirty hacks to handle binary data RestController doesn't deal with file extensions anymore.
author sergey
date Wed, 12 Dec 2012 04:29:50 +0400
parents 827cf96faa1c
children 299af584c05f 91bae9f41a9c
files Lib/IMPL/Web/Application/Action.pm Lib/IMPL/Web/Application/Resource.pm Lib/IMPL/Web/AutoLocator.pm Lib/IMPL/Web/Handler/ErrorHandler.pm Lib/IMPL/Web/Handler/JSONView.pm Lib/IMPL/Web/Handler/RestController.pm Lib/IMPL/Web/Handler/TTView.pm Lib/IMPL/Web/HttpResponse.pm Lib/IMPL/Web/ViewResult.pm Lib/IMPL/declare.pm
diffstat 10 files changed, 110 insertions(+), 49 deletions(-) [+]
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/Action.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/Application/Action.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -4,6 +4,7 @@
 use Carp qw(carp);
 
 use IMPL::Const qw(:prop);
+use IMPL::Web::CGIWrapper();
 
 use IMPL::declare {
     base => [
@@ -49,11 +50,26 @@
     $this->_launder($value, $rx );
 }
 
+sub rawData {
+    my ($this) = @_;
+    
+    local $IMPL::Web::CGIWrapper::NO_DECODE = 1;
+    if ($this->requestMethod eq 'POST') {
+        return $this->query->param('POSTDATA');
+    } elsif($this->requestMethod eq 'PUT') {
+        return $this->query->param('PUTDATA');
+    }
+}
+
 sub requestMethod {
     my ($this) = @_;
     return $this->query->request_method;
 }
 
+sub contentType {
+    return shift->query->content_type();
+}
+
 sub pathInfo {
     my ($this) = @_;
     return $this->query->path_info;
--- a/Lib/IMPL/Web/Application/Resource.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/Application/Resource.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -1,6 +1,7 @@
 package IMPL::Web::Application::Resource;
 use strict;
 
+use URI;
 use IMPL::Const qw(:prop);
 use IMPL::declare {
     require => {
@@ -19,7 +20,6 @@
         parent   => PROP_RO,
         model    => PROP_RO,
         id       => PROP_RO,
-        name     => PROP_RO,
         contract => PROP_RO,
         location => PROP_RO,
       ]
@@ -32,18 +32,15 @@
       unless $args{id};
     die ArgumentException->new( contract => 'A contract is required' )
       unless $args{contract};
-    die ArgumentException->new( name => 'A name is required' )
-      if $args{parent} && not(length $args{name});
 
     $this->parent( $args{parent} );
     $this->model( $args{model} );
     $this->id( $args{id} );
     $this->contract( $args{contract} );
-    $this->name($args{name});
 
     # если расположение явно не указано, то оно вычисляется автоматически,
     # либо остается не заданным
-    $this->location( $args{location} || eval { $this->parent->location->Child( $this->name ) } );
+    $this->location( $args{location} || eval { $this->parent->location->Child( $this->id ) } );
 }
 
 sub InvokeHttpVerb {
@@ -172,13 +169,6 @@
 Обязательное свойство ресурса, идентифицирует его в родительском контейнере,
 для корневого ресурса может иметь произвольное значение.
 
-=head2 C<[get]name>
-
-Имя ресурса в адресной строке. При разборе адреса идентификаторы ресурсов могут
-не всегда совпадать с именами, например C<http://audio/sonar.mp3> может иметь
-идентификатор C<sonar>, а его имя будет C<sonar.mp3>. Однако за частую имя
-совпадает с идентификатором.
-
 =head2 C<[get]parent>
 
 Ссылка на родительский ресурс, для корневого ресурса не определена.
--- a/Lib/IMPL/Web/AutoLocator.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/AutoLocator.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -73,6 +73,12 @@
 	return $url;
 }
 
+sub ToAbsolute {
+    my ($this,$baseUrl) = @_;
+    
+    return URI->new_abs( $this->url, $baseUrl );
+}
+
 sub toString {
     shift->url->as_string();
 }
--- a/Lib/IMPL/Web/Handler/ErrorHandler.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/Handler/ErrorHandler.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -43,7 +43,9 @@
 	};
 	
 	if (my $err = $@) {
-		
+	    
+	    warn "$err";
+	    
 		my $vars = {
 			error => $err
 		};
--- a/Lib/IMPL/Web/Handler/JSONView.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/Handler/JSONView.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -2,6 +2,7 @@
 use strict;
 use JSON;
 
+use IMPL::lang qw(is);
 use IMPL::declare {
     require => {
         HttpResponse => 'IMPL::Web::HttpResponse',
@@ -24,17 +25,27 @@
 	my $result = $next ? $next->($action) : undef;
 	
 	
-	my $model = ( ref $result and eval { $result->isa(ViewResult) } )
+	my $model = ( ref $result and is($result,ViewResult) )
 	   ? $result->model
 	   : $result;
 	
 	$model = [$model] unless ref $model;
 	
-    return HttpResponse->new({
+	my %params = (
         type => $this->contentType,
         charset => 'utf-8',             
         body => JSON->new->utf8->pretty->encode($model)
-    });
+	);
+	
+	if(is($result,ViewResult)) {
+    	$params{status} = $result->status if $result->status;
+    	$params{headers} = $result->headers if $result->headers;
+    	$params{cookies} = $result->cookies if $result->cookies;
+	}
+	
+    return HttpResponse->new(
+        %params
+    );
 }
 
 1;
--- a/Lib/IMPL/Web/Handler/RestController.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/Handler/RestController.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -42,13 +42,6 @@
         
         # remove first segment if it is empty
         shift @segments if @segments && length($segments[0]) == 0;
-        
-        if(@segments) {
-        	my $segment = pop(@segments);
-            my ($obj,$view) = ($segment =~ m/(.*?)(?:\.(\w+))?$/);
-            push @segments, { id => $obj, name => $segment, ext => $view };
-        }
-    
     }
     
     return @segments;    
@@ -64,14 +57,13 @@
 	
 	my $res = $this->resourceFactory->new(
 	   id => 'root',
-	   name => '',
 	   location => Locator->new(base => $action->application->baseUrl)
 	);
 	
 	while(@segments) {
-		my $info = shift @segments;
+		my $id = shift @segments;
 		
-		$res = $res->FetchChildResource($info->{id});
+		$res = $res->FetchChildResource($id);
 	}
 	
 	$res = $res->InvokeHttpVerb($method,$action);
@@ -119,12 +111,18 @@
 Для чего используется метод
 C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>.
 
+=begin text
+
+/music/audio.mp3 -> ['music','audio.mp3']
+
+=end text
+
 =head1 MEMEBERS
 
-=head2 C<[get]rootResource>
+=head2 C<[get]resourceFactory>
 
-Корневой ресурс приложения, должен быть всегда и реализовывать интерфес ресурса
-C<IMPL::Web::Application::ResourceInterface>.
+Фабрика для создания корневого ресурса приложения, полученный ресурс должен
+реализовывать интерфейс C<IMPL::Web::Application::ResourceInterface>.
 
 =head2 C<[get]trailingSlash>
 
--- a/Lib/IMPL/Web/Handler/TTView.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/Handler/TTView.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -65,14 +65,24 @@
     };
 
     my $doc =
-      $this->loader->document( $this->SelectView( $action, ref $model ),
+      $this->loader->document( eval { $view->template } || $this->SelectView( $action, ref $model ),
         $vars );
-
-    return HttpResponse->new(
+        
+    $doc->location($view->location);
+        
+    my %responseParams = (
         type => $this->contentType,
         charset => $this->contentCharset,
         body => $doc->Render()
     );
+    
+    $responseParams{status} = $view->status if $view->status;
+    $responseParams{cookies} = $view->cookies if ref $view->cookies eq 'HASH';
+    $responseParams{headers} = $view->headers if ref $view->headers eq 'HASH';
+
+    return HttpResponse->new(
+        %responseParams        
+    );
 }
 
 sub SelectView {
--- a/Lib/IMPL/Web/HttpResponse.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/HttpResponse.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -46,6 +46,9 @@
 	if(my $charset = $this->charset) {
 	   $q->charset($charset);
 	   binmode $out, ":encoding($charset)";
+	} else {
+	   $q->charset('');
+	   binmode $out;
 	}
 	
 	print $out $q->header(\%headers);
--- a/Lib/IMPL/Web/ViewResult.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/Web/ViewResult.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -10,7 +10,10 @@
     ],
     props => [
         model => PROP_RW,
-        location => PROP_RW
+        location => PROP_RW,
+        cookies => PROP_RW,
+        headers => PROP_RW,
+        status  => PROP_RW
     ]
 };
 
@@ -51,6 +54,18 @@
 
 =head2 C<[get,set]location>
 
-Текущий абсолютный адрес ресурса.   
+Текущий абсолютный адрес ресурса.
+
+=head2 C<[get,set]cookies>
+
+Хеш с печеньками, которые будут добавлены в C<HTTP> ответ.
+
+=head2 C<[get,set]headers>
+
+Заголовки которые нужно добавить в заголовки C<HTTP> ответа.
+
+=head2 C<[get,set]status>
+
+Код C<HTTP> ответа. 
 
 =cut
--- a/Lib/IMPL/declare.pm	Fri Dec 07 16:58:19 2012 +0400
+++ b/Lib/IMPL/declare.pm	Wed Dec 12 04:29:50 2012 +0400
@@ -89,27 +89,37 @@
 	  unless scalar(@$props) % 2 == 0;
 
 	if (@$props) {
-		for ( my $i = 0 ; $i < @$props - 1 ; $i = $i + 2 ) {
-			my ( $prop, $spec ) = @{$props}[ $i, $i + 1 ];
-
-			my $propInfo = IMPL::Class::PropertyInfo->new(
-				{
-					Name     => $prop,
-					Mutators => $spec,
-					Class    => $caller,
-					Access   => $prop =~ /^_/
-					? ACCESS_PRIVATE
-					: ACCESS_PUBLIC
-				}
-			);
-			$propInfo->Implement();
-		}
+	   	$self->_implementProps($props,$caller);
 	}
 	
+    if ($args->{_implement}) {
+        $self->_implementProps($caller->abstractProps,$caller);     
+    }	
+	
 	$IMPL::require::level--;
 	delete $IMPL::require::PENDING{$caller};
 }
 
+sub _implementProps {
+    my ($self, $props, $caller) = @_;
+    
+    for ( my $i = 0 ; $i < @$props - 1 ; $i = $i + 2 ) {
+        my ( $prop, $spec ) = @{$props}[ $i, $i + 1 ];
+
+        my $propInfo = IMPL::Class::PropertyInfo->new(
+            {
+                Name     => $prop,
+                Mutators => $spec,
+                Class    => $caller,
+                Access   => $prop =~ /^_/
+                ? ACCESS_PRIVATE
+                : ACCESS_PUBLIC
+            }
+        );
+        $propInfo->Implement();
+    }
+}
+
 1;
 
 __END__