diff Lib/IMPL/Web/Handler/RestController.pm @ 229:47f77e6409f7

heavily reworked the resource model of the web application: *some ResourcesContraact functionality moved to Resource +Added CustomResource *Corrected action handlers
author sergey
date Sat, 29 Sep 2012 02:34:47 +0400
parents d6e2ea24af08
children 6d8092d8ce1b
line wrap: on
line diff
--- a/Lib/IMPL/Web/Handler/RestController.pm	Thu Sep 13 17:55:01 2012 +0400
+++ b/Lib/IMPL/Web/Handler/RestController.pm	Sat Sep 29 02:34:47 2012 +0400
@@ -2,69 +2,72 @@
 use strict;
 
 use IMPL::lang qw(:declare :constants);
-
-
 use IMPL::declare {
 	require => {
+	    ResourceInterface => 'IMPL::Web::Application::ResourceInterface', 
 		Exception => 'IMPL::Exception',
 		ArgumentExecption => '-IMPL::InvalidArgumentException',
-		HttpException => 'IMPL::Web::Exception',
-        NotFoundException => 'IMPL::Web::NotFoundException'
+		NotFoundException => 'IMPL::Web::NotFoundException'
 	},
 	base => {
 		'IMPL::Object' => undef,
 		'IMPL::Object::Autofill' => '@_',
 		'IMPL::Object::Serializable' => undef
-	}	
+	},
+	props => [
+	   rootResource => PROP_GET | PROP_OWNERSET,
+	   trailingSlash => PROP_GET | PROP_OWNERSET
+	]	
 };
 
-BEGIN {
-	public property root => PROP_GET | PROP_OWNERSET;
-	public property contract => PROP_GET | PROP_OWNERSET;
-}
-
 sub CTOR {
 	my ($this) = @_;
 	
-	die ArgumentException->new("root") unless $this->root;
-	die ArgumentException->new("contract") unless $this->contract;
+	die ArgumentException->new(rootResource => "A web-resource is required")
+	   unless eval { $this->rootResource->isa(ResourceInterface) };
+	 
 }
 
+sub GetResourcePath {
+    my ($this,$action) = @_;
+    
+    my $pathInfo = $action->pathInfo;
+    my @segments;
+    
+    if (length $pathInfo) {
+    
+        @segments = split(/\//, $pathInfo, $this->trailingSlash ? -1 : 0);
+        
+        # remove first segment since it's always empty
+        shift @segments;
+        
+        my ($obj,$view) = (pop(@segments) =~ m/(.*?)(?:\.(\w+))?$/);
+        push @segments, $obj;
+    
+    }
+    
+    return @segments;    
+}
+
+
 sub Invoke {
 	my ($this,$action) = @_;
 	
-	my $query = $action->query;
-	
-	my $method = $query->request_method;
-	
-	#TODO: path_info is broken for IIS
-	my $pathInfo = $query->path_info;
-	my @segments;
-	
-	if (length $pathInfo) {
+	my $method = $action->requestMethod;
 	
-		@segments = split /\//, $pathInfo, -1; # keep trailing empty string if present
-		
-		# remove first segment since it's always empty
-		shift @segments;
-		
-		my ($obj,$view) = (pop(@segments) =~ m/(.*?)(?:\.(\w+))?$/);
-		push @segments, $obj;
+	my @segments = $this->GetResourcePath($action);
 	
-	}
-	
-	
-	my $res = $this->contract->Transform($this->root, { id => '' } );
+	my $res = $this->rootResource;
 	
 	while(@segments) {
 		my $id = shift @segments;
 		
-		$res = $res->FetchChildResource($id,$action);
+		$res = $res->FetchChildResource($id);
 		
 		die NotFoundException->new($pathInfo,$id) unless $res;
 	}
 	
-	$res = $res->InvokeHttpMethod($method,$action);
+	$res = $res->InvokeHttpVerb($method,$action);
 }
 
 1;
@@ -75,32 +78,50 @@
 
 =head1 NAME
 
-C<IMPL::Web::Handler::RestController> - Транслирует запросы к ресурсам в вызовы методов.
+C<IMPL::Web::Handler::RestController> - Обрабатывает C<HTTP> запрос передавая
+его соответствующему ресурсу.
 
 =head1 SYNOPSIS
 
-Использует контракты для преобразования стандартных C<REST> запросов в вызовы методов объектов.
-C<$ENV{PATH_INFO}> используется как путь к нужному ресурсу у которого будет вызван метод указанный в запросе.
+Используется в конфигурации приложения как элемент цепочки обработчиков.
+Как правило располагается на самом верхнем уровне.
+
+=begin code xml
+
+    <handlers type="ARRAY">
+        <item type="IMPL::Web::Handler::RestController">
+            <rootResource type="My::App::Web::RootResource"/>
+        </item>
+        <item type="IMPL::Web::Handler::JSONView" />
+        <item type="IMPL::Web::Handler::SecureCookie" />
+        <item type="IMPL::Web::Handler::ErrorHandler" />
+    </handlers>
+
+=end code xml
+
 
 =head1 DESCRIPTION
 
-=head2 Resource model
+Использует C<PATH_INFO> для определения нужного ресурса, затем предает
+найденному ресурсу управление для обработки запроса.
+
+Если ресурс не найден, то возникает исключение C<IMPL::Web::NotFoundException>.
 
-Ресурсы имеют иерархическую структуру, аналогичную файлам и каталогам, которая описывается контрактом, также
-контрак описывает то, как должны обрабатываться методы C<HTTP> запроса, такие как C<GET> и C<POST>.
-
-За корректность реализации данных методов отвечает разработчик.
+Для определения нужного ресурса контроллер разбивает C<PATH_INFO> на фрагменты
+и использует каждый фрагмент для получения дочернего ресурса начиная с корневого.
+Для чего используется метод
+C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>.
 
-Каждый ресурс представляет собой коллкецию вложенных ресурсов, путь указанный в C<HTTP> запросе разбивается на
-части, затем каждый сегмент последовательно используется для поиска дочернего ресурса. При обработки
-первого сегмента используется корневой ресурс. Корневой ресурс должен существовать всегда.
+=head1 MEMEBERS
 
-=head2 Contract
+=head2 C<[get]rootResource>
 
-Контрактом может быть любое преобразование которое определяет соответсвие между объектами приложения и
-ресурсами, доступными через протокол C<HTTP>.
+Корневой ресурс приложения, должен быть всегда и реализовывать интерфес ресурса
+C<IMPL::Web::Application::ResourceInterface>.
 
+=head2 C<[get]trailingSlash>
 
-
+Если данная переменная имеет значение C<true>, то слеш в конце пути к ресурсу
+будет интерпретироваться, как дочерний ресурс с пустым идентификатором.
 
 =cut
\ No newline at end of file