view Lib/IMPL/Web/AutoLocator.pm @ 400:ef37ec102dab

redirection support while fetching child resources
author cin
date Wed, 14 May 2014 17:27:32 +0400
parents 793cc7f0a7e7
children 7171a8e2e2ba
line wrap: on
line source

package IMPL::Web::AutoLocator;
use strict;

use overload '""' => 'toString';

use IMPL::Const qw(:prop);
use IMPL::lang qw(:hash);
use IMPL::clone qw(clone);
use URI;
use URI::Escape;
use IMPL::declare {
	require => {
		Exception => 'IMPL::Exception',
		ArgumentException => '-IMPL::InvalidArgumentException'
	},
	base => [
        'IMPL::Object' => undef,
        'IMPL::Object::Autofill' => '@_',
        'IMPL::Object::Serializable' => '@_'
	],
	props => [
	   base => PROP_RO,
	   view => PROP_RW,
	   query => PROP_RW,
	   hash => PROP_RW
	]
};

sub Clone {
    my $this = shift;
    
    return clone($this);
}

sub Child {
	my $this = shift;
	my $child = shift or die ArgumentException->new("a child resource identifier is required");
	die ArgumentException->new("a child resource can't be a reference") if ref $child;
	
	# safe
	$child = uri_escape($child);
	
	my %args;
	
	$args{base} = $this->base =~ /\/$/ ? $this->base . $child : $this->base . '/' . $child;
	$args{view} = $this->view if $this->view;
	$args{hash} = $this->hash if $this->hash;
	
	if (@_) {
		my $query = shift;
		
		$args{query} = ref $query eq 'HASH' ? hashMerge($this->query,$query) : $query;
	}
	
	return $this->new(%args);
}

sub Sibling {
    my $this = shift;
    my $child = shift or die ArgumentException->new("a child resource identifier is required");
    die ArgumentException->new("a child resource can't be a reference") if ref $child;
    
    # safe
    $child = uri_escape($child);
    
    my %args;
    
    if($this->base =~ /(.*?)(\/[^\/]*)?$/) {
    	$args{base} = join('/',$1,$child);
    } else {
    	$args{base} = $child;
    }
    
    $args{view} = $this->view if $this->view;
    $args{hash} = $this->hash if $this->hash;
    
    if (@_) {
        my $query = shift;
        
        $args{query} = ref $query eq 'HASH' ? hashMerge($this->query,$query) : $query;
    }
    
    return $this->new(%args);

}

sub Query {
    my ($this,$query) = @_;
    
    my %args;
    
    $args{base} = $this->base;
    $args{view} = $this->view if $this->view;
    $args{hash} = $this->hash if $this->hash;
    $args{query} = ref $query eq 'HASH' ? hashMerge($this->query,$query) : $query;
    
    return $this->new(%args);
}

sub SetView {
	my ($this,$newView) = @_;
	
	$this->view($newView);
	
	return $this;
}

sub url {
	my ($this) = @_;
	
	my $url = URI->new($this->view ? $this->base . "." . $this->view : $this->base);
	$url->query_form($this->query);
	$url->fragment($this->hash);
	
	return $url;
}

sub ToAbsolute {
    my ($this,$baseUrl) = @_;
    
    return URI->new_abs( $this->url, $baseUrl );
}

sub toString {
    shift->url->as_string();
}

sub AUTOLOAD {
	our $AUTOLOAD;
	
	(my $method) = ($AUTOLOAD =~ m/(\w+)$/);
	
	return if $method eq 'DESTROY';
	
	my $this = shift;
	return $this->Child($method,@_);
}



1;

__END__

=head1 NAME

C<IMPL::Web::AutoLocator> - Обертка вокруг адреса ресурса.

=head1 SYNOPSIS

=begin code

use IMPL::require {
	Locator => 'IMPL::Web::AutoLocator'
};

my $bugTracker = Locator->new(base => "http://myhost.org/bugzilla")->SetView("cgi");

my $bug = $bugTracker->show_bug({id = 1});

my $wikiPages = Locator->new(base => "http://myhost.org/wiki/bin/view");

my $page = $wiki->Main->HowTo;

my $images = Locator->new(base => "http://static.myhost.org/images", view => "png");

my $editIco = $images->icons->small->edit;

=end code

=head1 DESCRIPTION

Для удобстав навигации по ресурсам, полностью отражает классическую структуру
иерархически организованных ресурсов. позволяет гибко работать с параметрами
запроса и хешем. Для постоты чтения реализует метод C<AUTOLOAD> для доступа
к дочерним ресурсам.

=head1 MEMBERS

=head2 C<CTOR(%args)>

Создает новый объект расположение. Позволяет задать путь, расширение, параметры
запроса и фрагмент ресурса.

=over

=item * C<base>

Строка с базовым адресом для дочерних ресурсов.

=item * C<view>

Задает суфикс, обозначающий представление ресурса, аналогично расширению у
файлов. Данный суффикс может использоваться контроллером для выбора
представления ресурса.

=item * C<query>

Ссылка на хеш с параметрами запроса

=item * C<hash>

Часть C<uri> обозначающая фрагмент документа (все, что идет после символа C<#>).

=back

=head2 C<Child($child[,$query])>

Получает расположение дочернего ресурса. При этом cоздается новый объект адреса ресурса.

=head2 C<SetView($view)>

Позволяет указать представление (расширение) у текущего адреса ресурса. Изменяет
представление и возвращает измененный адрес ресурса.

=head2 C<[get]base>

Базовый адрес, относительно которого будут получены дочерние ресурсы.

=head2 C<[get,set]view>

Представление для ресурсов, аналогично расширению у файлов.

=head2 C<[get,set]query>

Ссылка на хеш с параметрами для C<GET> запроса.

=head2 C<[get,set]hash>

Часть адреса ресурса, отвечающая за фрагмент. 

=head2 C<[get]url>

Объект C<URI> для текущего адреса.

=head2 C<AUTLOAD>

Перенаправляет вызовы методов в метод C<Child> передавая первым параметром имя метода.

=cut