Mercurial > pub > Impl
diff Lib/IMPL/Web/Handler/RestController.pm @ 229:47f77e6409f7
heavily reworked the resource model of the web application:
*some ResourcesContraact functionality moved to Resource
+Added CustomResource
*Corrected action handlers
author | sergey |
---|---|
date | Sat, 29 Sep 2012 02:34:47 +0400 |
parents | d6e2ea24af08 |
children | 6d8092d8ce1b |
line wrap: on
line diff
--- a/Lib/IMPL/Web/Handler/RestController.pm Thu Sep 13 17:55:01 2012 +0400 +++ b/Lib/IMPL/Web/Handler/RestController.pm Sat Sep 29 02:34:47 2012 +0400 @@ -2,69 +2,72 @@ use strict; use IMPL::lang qw(:declare :constants); - - use IMPL::declare { require => { + ResourceInterface => 'IMPL::Web::Application::ResourceInterface', Exception => 'IMPL::Exception', ArgumentExecption => '-IMPL::InvalidArgumentException', - HttpException => 'IMPL::Web::Exception', - NotFoundException => 'IMPL::Web::NotFoundException' + NotFoundException => 'IMPL::Web::NotFoundException' }, base => { 'IMPL::Object' => undef, 'IMPL::Object::Autofill' => '@_', 'IMPL::Object::Serializable' => undef - } + }, + props => [ + rootResource => PROP_GET | PROP_OWNERSET, + trailingSlash => PROP_GET | PROP_OWNERSET + ] }; -BEGIN { - public property root => PROP_GET | PROP_OWNERSET; - public property contract => PROP_GET | PROP_OWNERSET; -} - sub CTOR { my ($this) = @_; - die ArgumentException->new("root") unless $this->root; - die ArgumentException->new("contract") unless $this->contract; + die ArgumentException->new(rootResource => "A web-resource is required") + unless eval { $this->rootResource->isa(ResourceInterface) }; + } +sub GetResourcePath { + my ($this,$action) = @_; + + my $pathInfo = $action->pathInfo; + my @segments; + + if (length $pathInfo) { + + @segments = split(/\//, $pathInfo, $this->trailingSlash ? -1 : 0); + + # remove first segment since it's always empty + shift @segments; + + my ($obj,$view) = (pop(@segments) =~ m/(.*?)(?:\.(\w+))?$/); + push @segments, $obj; + + } + + return @segments; +} + + sub Invoke { my ($this,$action) = @_; - my $query = $action->query; - - my $method = $query->request_method; - - #TODO: path_info is broken for IIS - my $pathInfo = $query->path_info; - my @segments; - - if (length $pathInfo) { + my $method = $action->requestMethod; - @segments = split /\//, $pathInfo, -1; # keep trailing empty string if present - - # remove first segment since it's always empty - shift @segments; - - my ($obj,$view) = (pop(@segments) =~ m/(.*?)(?:\.(\w+))?$/); - push @segments, $obj; + my @segments = $this->GetResourcePath($action); - } - - - my $res = $this->contract->Transform($this->root, { id => '' } ); + my $res = $this->rootResource; while(@segments) { my $id = shift @segments; - $res = $res->FetchChildResource($id,$action); + $res = $res->FetchChildResource($id); die NotFoundException->new($pathInfo,$id) unless $res; } - $res = $res->InvokeHttpMethod($method,$action); + $res = $res->InvokeHttpVerb($method,$action); } 1; @@ -75,32 +78,50 @@ =head1 NAME -C<IMPL::Web::Handler::RestController> - Транслирует запросы к ресурсам в вызовы методов. +C<IMPL::Web::Handler::RestController> - Обрабатывает C<HTTP> запрос передавая +его соответствующему ресурсу. =head1 SYNOPSIS -Использует контракты для преобразования стандартных C<REST> запросов в вызовы методов объектов. -C<$ENV{PATH_INFO}> используется как путь к нужному ресурсу у которого будет вызван метод указанный в запросе. +Используется в конфигурации приложения как элемент цепочки обработчиков. +Как правило располагается на самом верхнем уровне. + +=begin code xml + + <handlers type="ARRAY"> + <item type="IMPL::Web::Handler::RestController"> + <rootResource type="My::App::Web::RootResource"/> + </item> + <item type="IMPL::Web::Handler::JSONView" /> + <item type="IMPL::Web::Handler::SecureCookie" /> + <item type="IMPL::Web::Handler::ErrorHandler" /> + </handlers> + +=end code xml + =head1 DESCRIPTION -=head2 Resource model +Использует C<PATH_INFO> для определения нужного ресурса, затем предает +найденному ресурсу управление для обработки запроса. + +Если ресурс не найден, то возникает исключение C<IMPL::Web::NotFoundException>. -Ресурсы имеют иерархическую структуру, аналогичную файлам и каталогам, которая описывается контрактом, также -контрак описывает то, как должны обрабатываться методы C<HTTP> запроса, такие как C<GET> и C<POST>. - -За корректность реализации данных методов отвечает разработчик. +Для определения нужного ресурса контроллер разбивает C<PATH_INFO> на фрагменты +и использует каждый фрагмент для получения дочернего ресурса начиная с корневого. +Для чего используется метод +C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>. -Каждый ресурс представляет собой коллкецию вложенных ресурсов, путь указанный в C<HTTP> запросе разбивается на -части, затем каждый сегмент последовательно используется для поиска дочернего ресурса. При обработки -первого сегмента используется корневой ресурс. Корневой ресурс должен существовать всегда. +=head1 MEMEBERS -=head2 Contract +=head2 C<[get]rootResource> -Контрактом может быть любое преобразование которое определяет соответсвие между объектами приложения и -ресурсами, доступными через протокол C<HTTP>. +Корневой ресурс приложения, должен быть всегда и реализовывать интерфес ресурса +C<IMPL::Web::Application::ResourceInterface>. +=head2 C<[get]trailingSlash> - +Если данная переменная имеет значение C<true>, то слеш в конце пути к ресурсу +будет интерпретироваться, как дочерний ресурс с пустым идентификатором. =cut \ No newline at end of file