diff lib/IMPL/Web/Handler/ViewSelector.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/ViewSelector.pm	Fri Sep 04 19:40:23 2015 +0300
@@ -0,0 +1,100 @@
+package IMPL::Web::Handler::ViewSelector;
+use strict;
+
+use IMPL::Const qw(:prop);
+
+use IMPL::declare {
+    require => {
+        NotAcceptable => 'IMPL::Web::NotAcceptableException',
+        HttpResponse  => 'IMPL::Web::HttpResponse'
+      },
+      base => [
+        'IMPL::Object'               => undef,
+        'IMPL::Object::Autofill'     => '@_',
+        'IMPL::Object::Serializable' => undef
+      ],
+      props => [
+        views    => PROP_RW | PROP_LIST,
+        fallback => PROP_RW,
+        types    => PROP_RW
+      ]
+};
+
+sub Invoke {
+    my ( $this, $action, $next ) = @_;
+
+    my $result = $next ? $next->($action) : undef;
+
+    my $model;
+
+    return $result if eval { $result->isa(HttpResponse) };
+
+    my $handler;
+    my $path = $action->pathInfo;
+
+    if ( $this->types and $path =~ m/\.(\w+)$/ ) {
+        my $forced;
+        if ( $forced = $this->types->{$1} and $action->query->Accept($forced) )
+        {
+            ($handler) =
+              grep eval { $_->can('contentType') }
+              && $_->contentType eq $forced, $this->views;
+        }
+    }
+
+    if ( not $handler ) {
+
+        my @handlers =
+          sort { $b->{preference} <=> $a->{preference} } map {
+            {
+                handler    => $_,
+                preference => eval { $_->can('contentType') }
+                ? $action->query->Accept( $_->contentType )
+                : 0
+            }
+          } $this->views;
+
+        my $info = shift @handlers;
+        $handler = $info ? $info->{handler} : undef;
+
+    }
+
+    die NotAcceptable->new(
+        map {
+            eval { $_->can('contentType') } ? $_->contentType : ()
+        } $this->views
+    ) unless $handler;
+
+    return $handler->Invoke( $action, sub { $result } );
+}
+
+1;
+
+__END__
+
+=pod
+
+=head1 NAME
+
+C<IMPL::Web::Handler::ViewSelector> - Выбор нужного представления на основе заголовка C<Accept>
+
+=head1 DESCRIPTION
+
+Использует заголовок запроса C<Accept> для выбора подходящего представления, если задано свойство C<types>,
+пытается в первую очередь по расширению определить, какое представление подходит.
+
+В случаях, когда не требуется строить представление для данных (например, при перенаправлении к другому
+ресурсу или если нет данных), нужно, чтобы данному обработчику был возвращен
+L<IMPL::Web::Application::ActionResult>, который будет просто передан далее.
+
+=head1 MEMBERS
+
+=head2 C<[get,set,list]views>
+
+Список представлений, которые могут быть возвращены.
+
+=head2 C<[get,set]types>
+
+Хеш с соотвествием между расширением и типом содержимого, для подсказки при выборе представления.
+
+=cut