Mercurial > pub > Impl
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