view 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 source

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__

=pod

=head1 NAME

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