diff lib/IMPL/Web/Handler/RestController.pm @ 407:c6e90e02dd17 ref20150831

renamed Lib->lib
author cin
date Fri, 04 Sep 2015 19:40:23 +0300
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lib/IMPL/Web/Handler/RestController.pm	Fri Sep 04 19:40:23 2015 +0300
@@ -0,0 +1,148 @@
+package IMPL::Web::Handler::RestController;
+use strict;
+
+use IMPL::Const qw(:prop);
+use IMPL::declare {
+	require => {
+	    Locator => 'IMPL::Web::AutoLocator',
+	    ResourceInterface => 'IMPL::Web::Application::ResourceInterface', 
+		Exception => 'IMPL::Exception',
+		ArgumentExecption => '-IMPL::InvalidArgumentException',
+		NotFoundException => 'IMPL::Web::NotFoundException',
+		Loader => 'IMPL::Code::Loader'
+	},
+	base => {
+		'IMPL::Object' => undef,
+		'IMPL::Object::Autofill' => '@_',
+		'IMPL::Object::Serializable' => undef
+	},
+	props => [
+	   resourceFactory => PROP_RO,
+	   trailingSlash => PROP_RO
+	]	
+};
+
+sub CTOR {
+	my ($this) = @_;
+	
+	die ArgumentException->new(resourceFactory => "A web-resource is required")
+	   unless $this->resourceFactory;
+	   #unless eval { $this->resourceFacotry->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 if it is empty
+        shift @segments if @segments && length($segments[0]) == 0;
+    }
+    
+    return @segments;    
+}
+
+
+sub Invoke {
+	my ($this,$request) = @_;
+	
+	my $method = $request->requestMethod;
+	
+	my @segments = $this->GetResourcePath($request);
+	
+	my $factory = $this->resourceFactory;
+	
+	$factory = Loader->default->Require($factory)
+		unless ref($factory) || eval { $factory->can('new') };
+	
+	my $res = $factory->new(
+	   id => 'root',
+	   request => $request,
+	   location => Locator->new(base => $request->application->baseUrl),
+	);
+	
+	while(@segments) {
+		my $id = shift @segments;
+		$res = $res->FetchChildResource($id);
+	}
+	
+	$res = $res->InvokeHttpVerb($method);
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Web::Handler::RestController> - Обрабатывает C<HTTP> запрос передавая
+его соответствующему ресурсу.
+
+=head1 SYNOPSIS
+
+Используется в конфигурации приложения как элемент цепочки обработчиков.
+Как правило располагается на самом верхнем уровне.
+
+=begin code xml
+
+    <handlers type="ARRAY">
+        <item type="IMPL::Web::Handler::RestController">
+            <resourceFactory>My::App::Web::RootResource</resourceFactory>
+        </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
+
+Использует C<PATH_INFO> для определения нужного ресурса, затем предает
+найденному ресурсу управление для обработки запроса.
+
+Если ресурс не найден, то возникает исключение C<IMPL::Web::NotFoundException>.
+
+Для определения нужного ресурса контроллер разбивает C<PATH_INFO> на фрагменты
+и использует каждый фрагмент для получения дочернего ресурса начиная с корневого.
+Для чего используется метод
+C<< IMPL::Web::Application::ResourceInterface->FetchChildResource($childId) >>.
+
+Дерево ресурсов сущестувет независимо от обрабатываемого запроса, однако оно
+может полностью или частично загружаться в начале обработки запроса и
+освобождаться по окончании обработки запроса. Поэтому при получении дочерних
+ресурсов не участвует C<HTTP> запрос, он адресуется только последнему ресурсу.
+
+=begin text
+
+/music/audio.mp3 -> ['music','audio.mp3']
+
+=end text
+
+=head1 MEMEBERS
+
+=head2 C<[get]resourceFactory>
+
+Фабрика для создания корневого ресурса приложения, полученный ресурс должен
+реализовывать интерфейс C<IMPL::Web::Application::ResourceInterface>.
+
+Фабрика может сохранять ссылку на корневой ресурс и каждый раз не создавать
+его, а возвращать уже существующий. Это вполне оправдано, если хранение
+дерева ресурсов требует меньше ресурсов, чем его создание и при этом приложение
+остается в памяти между C<HTTP> запросами.
+
+=head2 C<[get]trailingSlash>
+
+Если данная переменная имеет значение C<true>, то слеш в конце пути к ресурсу
+будет интерпретироваться, как дочерний ресурс с пустым идентификатором.
+
+=cut
\ No newline at end of file