diff Lib/IMPL/Web/Application/RestResource.pm @ 198:2ffe6f661605

Implemented IMPL::Web::Handler::RestController fixes in IMPL::Serialization completed IMPL::Web::Application::RestResource added IMPL::Web::Handler::JSONView added IMPL::Web::RestContract
author cin
date Fri, 20 Apr 2012 16:06:36 +0400
parents 6b1dda998839
children e743a8481327
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/RestResource.pm	Thu Apr 19 02:10:02 2012 +0400
+++ b/Lib/IMPL/Web/Application/RestResource.pm	Fri Apr 20 16:06:36 2012 +0400
@@ -1,13 +1,19 @@
 package IMPL::Web::Application::RestResource;
 use strict;
 
-use IMPL::lang qw(:declare :constants);
+use IMPL::lang qw(:declare :constants is);
+use IMPL::Exception();
+
 use IMPL::declare {
 	require => {
-		ForbiddenException => 'IMPL::Web::ForbiddenException'
+		ForbiddenException => 'IMPL::Web::ForbiddenException',
+		InvalidOpException => '-IMPL::InvalidOperationException',
+		ArgumentException => '-IMPL::InvalidArgumentException',
+		TTransform => '-IMPL::Transform'
 	},
 	base => {
-		'IMPL::Object' => undef
+		'IMPL::Object' => undef,
+		'IMPL::Object::Autofill' => '@_'
 	}
 };
 
@@ -22,6 +28,12 @@
 	public property delete => PROP_GET | PROP_OWNERSET;
 }
 
+sub CTOR {
+	my ($this) = @_;
+	
+	die ArgumentException->new("target") unless $this->target;
+}
+
 sub GetHttpImpl {
 	my($this,$method) = @_;
 	
@@ -36,11 +48,11 @@
 }
 
 sub InvokeHttpMethod {
-	my ($this,$method,$child,$action) = @_;
+	my ($this,$method,$childId,$action) = @_;
 	
-	my $impl = $this->GetHttpImpl($method) || 'FallbackImpl';
+	my $impl = $this->GetHttpImpl($method) || 'HttpFallbackImpl';
 	
-	return $this->$impl($child,$action);
+	return $this->$impl($childId,$action);
 }
 
 sub GetImpl {
@@ -49,8 +61,8 @@
     my $rx;
     my $method;
     if (length $id == 0) {
-    	$method = $this->list;
-    } elsif ($method = $this->methods->{$id}) {
+    	$method = $this->list or die ForbiddenException->new();
+    } elsif ($this->methods and $method = $this->methods->{$id}) {
     	if (ref $method eq 'HASH' and not $method->{allowGet}) {
     		die ForbiddenException->new();
     	}
@@ -62,8 +74,6 @@
         	parameters => [qw(id)]
         } unless ref $method;
         
-    } else {    
-        die ForbiddenException->new();
     }
     
     return $this->InvokeMember($method,$id,$action);
@@ -131,8 +141,57 @@
 
 sub InvokeMember {
 	my ($this,$method,$id,$action) = @_;
+	
+	#normalize method info
+	if (not ref $method) {
+		$method = {
+			method => $method
+		};
+	}
+	
+	if (ref $method eq 'HASH') {
+		my @args;
+		my $member = $method->{method} or die InvalidOpException->new("A member name isn't specified");
+		if (my $params = $method->{parameters}) {
+			if (ref $params eq 'HASH') {
+				@args = map {
+					$_,
+					$this->MakeParameter($params->{$_},$id,$action)
+				} keys %$params;				
+			} elsif (ref $params eq 'ARRAY') {
+				@args = map $this->MakeParameter($_,$id,$action), @$params;
+			} else {
+				@args = ($this->MakeParameter($params,$id,$action)); 
+			}
+		}
+		$this->target->$member(@args);
+	} else {
+		die InvalidOpException->new("Unsupported type of the method information", ref $method);
+	}
 }
 
+sub MakeParameter {
+	my ($this,$param,$id,$action) = @_;
+	
+	if ($param) {
+		if (is $param, TTransform ) {
+			return $param->Transform($this,$action->query);
+		} elsif ($param and not ref $param) {
+			my %std = (
+                id => $id,
+                action => $action,
+                query => $action->query
+			);
+			
+			return $std{$param} || $action->query->param($param);
+		}
+	} else {
+		return undef;
+	}
+}
+
+
+
 
 1;
 
@@ -195,16 +254,14 @@
     DataContext->Default,
     {
     	methods => {
-    		get => {
-    			
+    		history => {
+    			allowGet => 1,
+    			method => 'GetHistory',
+    			parameters => [qw(from to)] 
     		},
-    		post => {
-    			
-    		}
     	}
-    	get => 'search',
-    	
-    	
+    	list => 'search',
+    	fetch => 'GetItemById'
     }   
 );
 
@@ -241,6 +298,10 @@
 
 Добавляет новый дочерний ресурс в коллекцию.
 
+=head3 C<POST {method}>
+
+Вызывает метод C<method>.
+
 =head2 HTTP METHOD MAPPING 
 
 =head3 C<POST {method}>
@@ -256,26 +317,161 @@
 
 =head2 C<[get]methods>
 
+Содержит описания методов, которые будут публиковаться как дочерние ресурсы.
+
 =head2 C<[get]childRegex>
 
+Содержит регулярное выражение для идентификаторов дочерних объектов. Если оно
+не задано, то данный ресурс не является коллекцией.
+
 =head2 C<[get]fetch>
 
+Содержит описание метода для получения дочернего объекта. Если данный метод
+отсутствует, то дочерние ресурсы не получится адресовать относительно данного.
+По умолчанию получает идентификатор дочернего ресурса первым параметром.  
+
 =head2 C<[get]list>
 
+Описание метода для получения списка дочерних объектов. По умолчанию не
+получает параметров.
+
 =head2 C<[get]insert>
 
+Описание метода для добавление дочернего ресурса. По умолчанию получает
+объект C<CGI> описывабщий текущий запрос первым параметром.
+
 =head2 C<[get]update>
 
+Описание метода для обновления дочернего ресурса. По умолчанию получает
+идентификатор дочернего ресурса и объект C<CGI> текущего запроса.
+
 =head2 C<[get]delete>
 
+Описание метода для удаления дочернего ресурса. По умолчанию получает
+идентификатор дочернего ресурса.
+
 =head2 C<GetImpl($child,$action)>
 
+=over
+
+=item C<$child>
+
+Идентификатор дочернего ресутсра
+
+=item C<$action>
+
+Текущий запрос C<IMPL::Web::Application::Action>.
+
+=back
+
+Переадресует запрос нужному методу внутреннего объекта C<target> при
+помощи C<InvokeMember>.
+
 =head2 C<PutImpl($child,$action)>
 
+=over
+
+=item C<$child>
+
+Идентификатор дочернего ресутсра
+
+=item C<$action>
+
+Текущий запрос C<IMPL::Web::Application::Action>.
+
+=back
+
+Переадресует запрос нужному методу внутреннего объекта C<target> при
+помощи C<InvokeMember>.
+
 =head2 C<PostImpl($child,$action)>
 
+=over
+
+=item C<$child>
+
+Идентификатор дочернего ресутсра
+
+=item C<$action>
+
+Текущий запрос C<IMPL::Web::Application::Action>.
+
+=back
+
+Переадресует запрос нужному методу внутреннего объекта C<target> при
+помощи C<InvokeMember>.
+
 =head2 C<DeleteImpl($child,$action)>
 
+=over
+
+=item C<$child>
+
+Идентификатор дочернего ресутсра
+
+=item C<$action>
+
+Текущий запрос C<IMPL::Web::Application::Action>.
+
+=back
+
+Переадресует запрос нужному методу внутреннего объекта C<target> при
+помощи C<InvokeMember>.
+
 =head2 C<InvokeMember($memberInfo,$child,$action)>
 
+=over
+
+=item C<$memberInfo>
+
+Описание члена внутреннего объекта C<target>, который нужно вызвать.
+
+=item C<$child>
+
+Идентификатор дочернего ресутсра
+
+=item C<$action>
+
+Текущий запрос C<IMPL::Web::Application::Action>.
+
+=back
+
+Вызывает метод внутреннего объекта C<target>, предварительно подготовив
+параметры на основе описания C<$memberInfo> и при помощи С<MakeParameter()>.
+
+=head2 C<MakeParameter($paramDef,$child,$action)>
+
+=over
+
+=item C<$paramDef>
+
+Описание параметра, может быть C<IMPL::Transform> или простая строка.
+
+Если описание параметра - простая строка, то ее имя либо
+
+=over
+
+=item C<id>
+
+Идентификатор дочернего ресурса
+
+=item C<query>
+
+Объект C<CGI> текущего запроса
+
+=item C<action>
+
+Текущий запрос C<IMPL::Web::Application::Action>
+
+=item C<любое другое значение>
+
+Интерпретируется как параметр текущего запроса.
+
+=back
+
+Если описание параметра - объект C<IMPL::Transform>, то будет выполнено это преобразование над C<CGI>
+объектом текущего запроса C<< $paramDef->Transform($action->query) >>.
+
+=back
+
 =cut
\ No newline at end of file