view Lib/IMPL/Web/Application/ResourceContract.pm @ 228:431db7034a88

Для синхронизации
author andrei <andrei@nap21.upri>
date Thu, 13 Sep 2012 17:55:01 +0400
parents 70ad6bc20908
children 47f77e6409f7
line wrap: on
line source

package IMPL::Web::Application::ResourceContract;
use strict;
use IMPL::lang qw(:declare);
use IMPL::declare {
	require => {
		'Exception' => 'IMPL::Exception',
		'ArgumentException' => '-IMPL::ArgumentException',
		'KeyNotFoundException' => '-IMPL::KeyNotFoundException',
		'ResourceClass' => 'IMPL::Web::Application::Resource'
	},
	base => [
	   'IMPL::Object' => undef
	]
};

BEGIN {
	public property resourceFactory => PROP_ALL;
	public property operations => PROP_ALL;
	private property _namedResources => PROP_ALL;
	private property _regexpResources => PROP_ALL | PROP_LIST; 
}

sub CTOR {
	my $this = shift;
	my %args = @_;
	
	$this->resourceFactory( $args{resourceFactory} || ResourceClass );
	
	my $resources = $args{resources} || [];
	my $operations = $args{operations} || {};
	
	die ArgumentException->new(resources => 'resources parameter must be a reference to an array')
	   unless ref $resources eq 'ARRAY';
	   
	die ArgumentException->new(opearations => 'operations parameter must be a reference to a hash')
	   unless ref $operations eq 'HASH';
	   
	my %nameMap;
		   
	foreach my $res (@$resources) {
		next unless $res->{contract};
		if(my $name = $res->{name}) {
			$nameMap{$name} = $res;
		}
		if($res->{match}) {
			$this->_regexpResources->Append($res);
		}
	}
	
	$this->_namedResources(\%nameMap);
}

sub CreateResource {
	my $this = shift;
	my %args = @_;
	
	return $this->resourceFactory->new (
	   %args,
	   contract => $this
	);
}

sub FindChildResourceContractInfo {
	my ($this,$name) = @_;
	
	if(my $contract = $this->_namedResources->{$name}) {
		return $contract;
	} else {
		foreach my $info ( $this->_regexpResources ) {
			my $rx = $info->{match};
			return $info if $name =~ m/$rx/;
		}
	}
	
	return undef;
}

sub CreateChildResource {
	my $this = @_;
	my %args = @_;
	
	my $id = $args{id} or die ArgumentException( id => 'id parameter must be specified');
	my $parent = $args{parent};
	my $model = $parent->model if $parent;
	my $binding, $childContract, @bindingVars;
	
	if(my $info = $this->_namedResources->{$id}) {
		@bindingVars = ($id);
		$childContract = $info->{contract};
		$binding = $info->{bind};
    } else {
        foreach my $info ( $this->_regexpResources ) {
            my $rx = $info->{match};
            next unless $rx;
            if( @bindingVars = ($id =~ m/$rx/) ) {
            	$childContract = $info->{contract};
            	$binding = $info->{bind};
            }
        }
    }
    
    if ($childContract) {
    	my $childModel = $binding ? $binding->($parent,$model,@bindingVars) : undef;
    	
    	return $childContract->CreateResource(
    	   %args,
    	   model => $childModel
    	);
    } else {
    	die KeyNotFoundException->new($id);
    }
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::Application::ResourceContract> - описание ресурса

=head1 SYNIOSIS

=begin code

use IMPL::require {
	ResourceContract => 'IMPL::Web::Application::ResourceContract',
	OperationContract => 'IMPL::Web::Application::OperationContract'
};

my $contract = ResourceContract->new(
    operations => {
    	get => OperationContract->new(
            bind => sub {
                return "Hello!";
            }
        )
    },
    resources => [
        {
        	name => 'info',
        	bind => sub {
        		return $_[0]->model->info;
        	},
        	contract => ResourceContract->new(
        	   get => OperationContract->new(
        	       bind => sub {
        	       	   my ($resource,$model) = @_;
        	       	   return $model; # or the same: $resource->model;
        	       }
        	   )
        	)
        }
    ]
)

my $obj = My::App::Data->fetch('something');

my $resource = $contract->CreateResource(
    model => $obj,
    parent => $prentResource,
    id => 'item-something'
);

my $child = $contract->CreateChildResource(
    parent => $resource,
    id => 'info'
);

=end code 

=head1 DESCRIPTION

=cut