diff Lib/IMPL/Web/Application/RestResource.pm @ 197:6b1dda998839

Added IMPL::declare, IMPL::require, to simplify module definitions IMPL::Transform now admires object inheritance while searching for the transformation Added HTTP some exceptions IMPL::Web::Application::RestResource almost implemented
author sergey
date Thu, 19 Apr 2012 02:10:02 +0400
parents a705e848dcc7
children 2ffe6f661605
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/RestResource.pm	Mon Apr 16 17:42:54 2012 +0400
+++ b/Lib/IMPL/Web/Application/RestResource.pm	Thu Apr 19 02:10:02 2012 +0400
@@ -1,6 +1,139 @@
 package IMPL::Web::Application::RestResource;
 use strict;
 
+use IMPL::lang qw(:declare :constants);
+use IMPL::declare {
+	require => {
+		ForbiddenException => 'IMPL::Web::ForbiddenException'
+	},
+	base => {
+		'IMPL::Object' => undef
+	}
+};
+
+BEGIN {
+	public property target => PROP_GET | PROP_OWNERSET;
+	public property methods => PROP_GET | PROP_OWNERSET;
+	public property childRegex => PROP_GET | PROP_OWNERSET;
+	public property list => PROP_GET | PROP_OWNERSET;
+	public property fetch => PROP_GET | PROP_OWNERSET;
+	public property insert => PROP_GET | PROP_OWNERSET;
+	public property update => PROP_GET | PROP_OWNERSET;
+	public property delete => PROP_GET | PROP_OWNERSET;
+}
+
+sub GetHttpImpl {
+	my($this,$method) = @_;
+	
+	my %map = (
+		GET => 'GetImpl',
+        PUT => 'PutImpl',
+        POST => 'PostImpl',
+        DELETE => 'DeleteImpl'
+	);
+	
+	return $map{$method};
+}
+
+sub InvokeHttpMethod {
+	my ($this,$method,$child,$action) = @_;
+	
+	my $impl = $this->GetHttpImpl($method) || 'FallbackImpl';
+	
+	return $this->$impl($child,$action);
+}
+
+sub GetImpl {
+    my ($this,$id,$action) = @_;
+    
+    my $rx;
+    my $method;
+    if (length $id == 0) {
+    	$method = $this->list;
+    } elsif ($method = $this->methods->{$id}) {
+    	if (ref $method eq 'HASH' and not $method->{allowGet}) {
+    		die ForbiddenException->new();
+    	}
+    } elsif($rx = $this->childRegex and $id =~ m/$rx/ ) {
+    	$method = $this->fetch or die ForbiddenException->new();
+        
+        $method = {
+        	method => $method,
+        	parameters => [qw(id)]
+        } unless ref $method;
+        
+    } else {    
+        die ForbiddenException->new();
+    }
+    
+    return $this->InvokeMember($method,$id,$action);
+}
+
+sub PutImpl {
+	my ($this,$id,$action) = @_;
+	
+	my $rx = $this->childRegex;
+	if ( $rx and $id =~ m/$rx/ and $this->update ) {
+		my $method = $this->update or die ForbiddenException->new();
+		
+		$method = {
+			method => $method,
+			parameters => [qw(id query)]
+		} unless ref $method;
+		
+		return $this->InvokeMember($method,$id,$action);
+	} else {	
+	   die ForbiddenException->new();	   
+	}
+}
+
+sub PostImpl {
+	my ($this,$id,$action) = @_;
+	
+	my $method;
+	
+	if (length $id == 0) {
+		$method = $this->insert or die ForbiddenException->new();
+		
+		$method = {
+			method => $method,
+			parameters => [qw(query)]
+		} unless ref $method;
+	} elsif ($method = $this->methods->{$id}) {
+		die ForbiddenException->new() unless ref $method and $method->{allowPost}; 
+	} else {
+		die ForbiddenException->new();
+	}
+	
+	return $this->InvokeMemeber($method,$id,$action);
+}
+
+sub DeleteImpl {
+	my ($this,$id,$action) = @_;
+	
+	my $rx = $this->childRegex;
+	if ($rx and $id =~ m/$rx/ and my $method = $this->delete) {
+		
+		$method = {
+			method => $method,
+			parameters => [qw(id)]
+		} unless ref $method;
+		
+		return $this->InvokeMember($method,$id,$action);
+	} else {
+		die ForbiddenException->new();
+	}
+}
+
+sub HttpFallbackImpl {
+	die ForbiddenException->new();
+}
+
+sub InvokeMember {
+	my ($this,$method,$id,$action) = @_;
+}
+
+
 1;
 
 __END__
@@ -11,6 +144,138 @@
 
 C<IMPL::Web::Application::RestResource> - ресурс Rest вебсервиса.
 
+=head1 SYNOPSIS
+
+=begin text
+
+[REQUEST]
+GET /artists
+
+[RESPONSE]
+<artists>
+    <artist id="1">
+        <name>The Beatles <name/>
+    </atrist>
+    <artist id="2">
+        <name>Bonobo</name>
+    </artist>
+</artists>
+
+[REQUEST]
+GET /artists/1/cds?title='Live at BBC'
+
+[RESPONSE]
+<cds>
+    <cd id="14">
+        <title>Live at BBC 1</title>
+    </cd>
+    <cd id="15">
+        <title>Live at BBC 2</title>
+    </cd>
+</cds>
+
+[REQUEST]
+GET /cds/15
+
+[RESPONSE]
+<cd id="15">
+    <title>Live at BBC 2</title>
+</cd>
+
+=end text
+
+=begin code
+
+use IMPL::require {
+	TRes => 'IMPL::Web:Application::RestResource',
+	DataContext => 'My::App::DataContext'
+};
+
+my $cds = TRes->new(
+    DataContext->Default,
+    {
+    	methods => {
+    		get => {
+    			
+    		},
+    		post => {
+    			
+    		}
+    	}
+    	get => 'search',
+    	
+    	
+    }   
+);
+
+=end code
+
 =head1 DESCRIPTION
 
+Каждый ресурс представляет собой коллекцию и реализует методы C<HTTP> C<GET,POST,PUT,DELETE>.
+
+=head2 HTTP METHODS
+
+=head3 C<GET>
+
+Возвращает коллекцию дочерних ресурсов.
+
+=head3 C<GET {id}>
+
+Возвращает дочерний объект с идентификатором C<id>
+
+=head3 C<GET {method}>
+
+Вызывает метод C<method> и возвращает его результаты. При публикации методов доступных
+через C<GET> данные методы не должны вносить изменений в предметную область.
+
+=head3 C<PUT {id}>
+
+Обновляет дочерний ресурс с указанным идентификатором.
+
+=head3 C<DELETE {id}>
+
+Удаляет дочерний ресурс с указанным идентификатором.
+
+=head3 C<POST>
+
+Добавляет новый дочерний ресурс в коллекцию.
+
+=head2 HTTP METHOD MAPPING 
+
+=head3 C<POST {method}>
+
+Вызывает метод C<method>, в отличии от C<GET> методы опубликованные через C<POST> могут вносить
+изменения в объекты. 
+
+=head1 MEMBERS
+
+=head2 C<[get]target>
+
+Объект (также может быть и класс), обеспечивающий функционал ресурса.
+
+=head2 C<[get]methods>
+
+=head2 C<[get]childRegex>
+
+=head2 C<[get]fetch>
+
+=head2 C<[get]list>
+
+=head2 C<[get]insert>
+
+=head2 C<[get]update>
+
+=head2 C<[get]delete>
+
+=head2 C<GetImpl($child,$action)>
+
+=head2 C<PutImpl($child,$action)>
+
+=head2 C<PostImpl($child,$action)>
+
+=head2 C<DeleteImpl($child,$action)>
+
+=head2 C<InvokeMember($memberInfo,$child,$action)>
+
 =cut
\ No newline at end of file