diff Lib/IMPL/Web/Application/RestResource.pm @ 200:a9dbe534d236

sync
author sergey
date Tue, 24 Apr 2012 02:34:49 +0400
parents e743a8481327
children 0c018a247c8a
line wrap: on
line diff
--- a/Lib/IMPL/Web/Application/RestResource.pm	Mon Apr 23 01:36:52 2012 +0400
+++ b/Lib/IMPL/Web/Application/RestResource.pm	Tue Apr 24 02:34:49 2012 +0400
@@ -7,29 +7,32 @@
 use IMPL::declare {
 	require => {
 		ForbiddenException => 'IMPL::Web::ForbiddenException',
+		NotFoundException => 'IMPL::Web::NotFoundException',
 		InvalidOpException => '-IMPL::InvalidOperationException',
 		ArgumentException => '-IMPL::InvalidArgumentException',
 		TTransform => '-IMPL::Transform',
-		TResolve => '-IMPL::Config::Resolve'
+		TResolve => '-IMPL::Config::Resolve',
+		CustomResource => 'IMPL::Web::Application::CustomResource'
 	},
 	base => {
-		'IMPL::Object' => undef,
-		'IMPL::Object::Autofill' => '@_'
+		'IMPL::Web::Application::RestBaseResource' => '@_'
 	}
 };
 
 BEGIN {
-	public property id => PROP_GET | PROP_OWNERSET;
 	public property target => PROP_GET | PROP_OWNERSET;
-	public property parent => PROP_GET | PROP_OWNERSET;
+	
 	public property methods => PROP_GET | PROP_OWNERSET;
+	
 	public property childRegex => PROP_GET | PROP_OWNERSET;
 	public property enableForms => 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;
+	public property orphan => PROP_GET | PROP_OWNERSET;
+	
+	public property listChildren => PROP_GET | PROP_OWNERSET;
+	public property fetchChild => PROP_GET | PROP_OWNERSET;
+	public property createChild => PROP_GET | PROP_OWNERSET;
+	public property updateChild => PROP_GET | PROP_OWNERSET;
+	public property deleteChild => PROP_GET | PROP_OWNERSET;
 }
 
 sub CTOR {
@@ -37,108 +40,25 @@
 	
 	die ArgumentException->new("id","Identifier is required for non-root resources") if $this->id and not length $this->id;
 	die ArgumentException->new("target") unless $this->target;
+	die ArgumentException->new("A contract is required") unless $this->contract;
 	
-	if ($this->enableForms && $this->parent) {
-		$this->methods({}) unless $this->methods;
-		
-		if ($this->insert) {
-			$this->methods->{create} = {
-				get => sub {
-					my ($that,$id,$action) = @_;
-					return $that->target;
-		        }
-			};
-		}
+	if ($this->enableForms) {
 		
-		if ($this->parent->update) {
-			$this->methods->{edit} = {
-                get => sub {
-                    my ($that,$id,$action) = @_;
-                    return $that->target;
-                },
-                post => sub {
-                	my ($that,$id,$action) = @_;
-                	return $that->parent->PutImpl($that->id,$action);
-                } 
-            };
-		}
-		
-		if ($this->parent->delete) {
-            $this->methods->{delete} = {
-                get => sub {
-                    my ($that,$id,$action) = @_;
-                    return $that->target;
-                },
-                post => sub {
-                    my ($that,$id,$action) = @_;
-                    return $that->parent->DeleteImpl($that->id,$action);
-                } 
-            };
-        }
 	}
 }
 
-sub GetHttpImpl {
-	my($this,$method) = @_;
-	
-	my %map = (
-		GET => 'GetImpl',
-        PUT => 'PutImpl',
-        POST => 'PostImpl',
-        DELETE => 'DeleteImpl'
-	);
-	
-	return $map{$method};
-}
-
-sub InvokeHttpMethod {
-	my ($this,$method,$childId,$action) = @_;
-	
-	my $impl = $this->GetHttpImpl($method) || 'HttpFallbackImpl';
-	
-	return $this->$impl($childId,$action);
-}
-
 sub GetImpl {
-    my ($this,$id,$action) = @_;
+    my ($this,$action) = @_;
     
-    my $rx;
-    my $method;
-    if (length $id == 0) {
-    	$method = $this->list or die ForbiddenException->new();
-    } elsif ($this->methods and $method = $this->methods->{$id}->{get}) {
-    	# we got method info
-    } 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);
+    return $this->target;
 }
 
 sub PutImpl {
-	my ($this,$id,$action) = @_;
+	my ($this,$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();	   
-	}
+	die ForbiddenException->new() if $this->orhpan;
+	
+	$this->parent->UpdateImpl($this->id,$action);
 }
 
 sub PostImpl {
@@ -183,6 +103,50 @@
 	die ForbiddenException->new();
 }
 
+sub UpdateImpl {
+	my ($this,$id,$action) = @_;
+	
+	my $method = $this->updateChild or die ForbiddenException->new();
+	$this->InvokeMember($method,$action);
+}
+
+sub FetchChildResource {
+	my ($this,$id,$action) = @_;
+	
+	my $rx = $this->childRegex;
+	my $method;
+	my %params = (
+	   parent => $this,
+	   id => $id
+	);
+	
+	if (length $id == 0) {
+		
+		$method = $this->list;
+		die ForbiddenException->new() unless $method;
+		
+		return $this->contract->Transform( $this->InvokeMember($method,$id,$action), \%params );
+		
+	} elsif ($method = $this->methods->{$id}) {
+		# поскольку данный объект был получен не как дочерний объект,
+		# а как выполнение метода, то для него не определены операции
+		# put и delete по умолчанию.
+		$params{orphan} = 1;
+		
+		return $this->contract->Transform( $this->InvokeMember($method,$id,$action), \%params );
+		 
+	} elsif ($rx and $id =~ m/^$rx$/ and $method = $this->fetch) {
+		# ok
+	} else {
+		die ForbiddenException->new();
+	}
+	
+	my $res = $this->InvokeMember($method,$id,$action);        
+    die NotFoundException->new() unless defined $res;
+        
+    return $this->contract->Transform($res, {parent => $this, id => $id} );
+}
+
 sub InvokeMember {
 	my ($this,$method,$id,$action) = @_;
 	
@@ -332,6 +296,10 @@
 
 Каждый ресурс представляет собой коллекцию и реализует методы C<HTTP> C<GET,POST,PUT,DELETE>.
 
+Ресурсы выстраиваются в иерархию, на основе пути. Поиск конечного реурса происходит последовательным
+вызовом метода GET с именем очередного ресурса. 
+  
+
 =head2 HTTP METHODS
 
 =head3 C<GET>
@@ -373,8 +341,8 @@
 =head1 BROWSER COMPATIBILITY
 
 Однако существует проблема с браузерами, поскольку тег C<< <form> >> реализет только методы
-C<GET,POST>. Для решения данной проблемы используется режим совместимости C<compatible>. В
-случае когда данный режим активен, автоматически публикуются дочерние C<create,edit,delete>.
+C<GET,POST>. Для решения данной проблемы используется режим совместимости C<enableForms>. В
+случае когда данный режим активен, автоматически публикуются дочерние ресурсы C<create,edit,delete>.
 
 =head2 C<GET create>