Mercurial > pub > Impl
view Lib/IMPL/Web/Application/CustomResource.pm @ 339:97628101b765
refactoring: application now holds a security object factory rather than a security object
author | cin |
---|---|
date | Wed, 19 Jun 2013 03:25:44 +0400 |
parents | e8be9062ecf2 |
children | e12c14177848 |
line wrap: on
line source
package IMPL::Web::Application::CustomResource; use strict; use IMPL::Const qw(:prop); use IMPL::declare { require => { NotAllowedException => 'IMPL::Web::NotAllowedException', HttpResponse => 'IMPL::Web::HttpResponse' }, base => [ 'IMPL::Web::Application::Resource' => '@_' ], props => [ accessCheck => PROP_RW, resources => PROP_RO, verbs => PROP_RO, namedResources => PROP_RO, regexResources => PROP_RO ] }; our %RESOURCE_BINDINGS = ( GET => 'HttpGet', POST => 'HttpPost', PUT => 'HttpPut', DELETE => 'HttpDelete', HEAD => 'HttpHead', OPTIONS => 'HttpOptions', TRACE => 'HttpTrace' ); sub CTOR { my ($this,%args) = @_; $this->verbs($args{verbs} || {}); $this->resources($args{resources} || []); $this->accessCheck($args{accessCheck}) if $args{accessCheck}; while(my ($verb,$methodName) = each %RESOURCE_BINDINGS) { if(my $method = $this->can($methodName)) { $this->verbs->{lc($verb)} ||= $method; } } } sub FindChildResourceInfo { my ( $this, $name ) = @_; $this->PrepareResourcesCache() unless $this->namedResources; if ( my $info = $this->namedResources->{$name} ) { return $info, [$name]; } else { foreach my $info ( @{$this->regexResources} ) { my $rx = $info->{match}; if(my @childId = $name =~ m/$rx/) { return $info, \@childId; } } } return; } sub GetAllowedMethods { map( uc, keys %{ shift->verbs } ); } sub PrepareResourcesCache { my ($this) = @_; my @resources = ($this->GetChildResources(), @{$this->resources}); my %nameMap; my @rxMap; foreach my $res (@resources) { #skip resources without contract next unless $res->{contract}; if ( my $name = $res->{name} ) { $nameMap{$name} = $res; } if ( $res->{match} ) { push @rxMap,$res; } } $this->regexResources(\@rxMap); $this->namedResources(\%nameMap); } sub AccessCheck { my ($this,$verb) = @_; my $handler = $this->accessCheck; if(ref($handler) eq 'CODE') { return &$handler($this,$verb); } } sub GetChildResources { } sub HttpOptions { my ($this) = @_; my @allow = $this->GetAllowedMethods(); return HttpResponse->new( status => '200 OK', headers => { allow => join ( ',', @allow ) } ); } 1; __END__ =pod =head1 NAME C<IMPL::Web::Application::CustomResource> - базовый класс для ресурсов, реальзуемых в коде. =head1 SYNOPSIS =begin code package MyApp::Web::Resources::ProfileResource; use IMPL::declare { base => [ 'IMPL::Web::Application::CustomResource' => '@_' ] } sub HttpGet { my ($this) = @_; return $this->model; } sub HttpPut { my ($this,$action) = @_; my $form = MyApp::Web::Schema::UpdateUser->new(); $this->model->update( $form->Bind($action) ); } sub GetChildResources { return { name => 'create', contract => { class => 'My::Web::FormResource', formName => 'create', schema => 'profile.schema' } }, { match => qr/^(.*)$/, contract => { class => 'My::Web::ItemResource' } } } =end code =head1 MEMBERS =head2 C<[static]contractFactory> Фабрика, используемая для получения контракта ресурса. По умолчанию C<IMPL::Web::Application::CustomResourceContract>. =head2 C<[static]contractInstance> Экземпляр контракта для ресурса. Создается при первом обращении при помощи метода C<InitContract()>. =head2 C<[static]InitContract()> Создает новый экземпляр контракта, используя фабрику из свойства C<contractFactory>. =head2 C<[static]CreateContract(%args)> Создает новый контракт, который при создании ресурсов будет передавать им в конструкторе параметры C<%args>. Реализуется при помощи C<IMPL::Object::Factory> которой задается параметр ссылка на C<%args>, т.о. при создании ресурса, ему в конструкторе будет передан список из ключей и значений хеша C<%args>, а затем остальные аргументы. =head2 C<[static]CreateResource(%args)> Создает контракт по-умолчанию и вызывает у него метод C<CreateResource(%args)>. =head2 C<[static]GetChildResources()> Статический метод, который должны переопределять новые классы ресурсов, у которых есть дочерние ресурсы. =begin code package MyApp::Web::MyResource sub GetChildResources { my $self = shift; return $self->SUPER::GetChildResources(), { name => 'info', contract => $contractInfo }; } =end code Метод возвращает список из хешей, которые будут переданы в качестве параметра C<resources> контракту данного ресурса. =cut