view Lib/IMPL/Web/Handler/ViewSelector.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 3cebcf6fdb9b
line wrap: on
line source

package IMPL::Web::Handler::ViewSelector;
use strict;

use IMPL::lang qw(:declare :constants);

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_ALL | PROP_LIST,
        fallback => PROP_ALL,
        types    => PROP_ALL
      ]
};

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