view Lib/IMPL/Web/TT/Document.pm @ 106:83e356614c1e

DOM Builder now is a navigator like SimpleBuilder PostToDOM transformation
author wizard
date Wed, 12 May 2010 17:52:12 +0400
parents 964587c5183c
children 0e72ad99eef7
line wrap: on
line source

package IMPL::Web::TT::Document;
use strict;
use warnings;

use base qw(IMPL::DOM::Document IMPL::Object::Disposable);
use Template::Context;
use Template::Provider;
use IMPL::Class::Property;
use File::Spec;
use Scalar::Util qw(blessed);

BEGIN {
    private property _provider => prop_all;
    private property _context => prop_all;
    public property template => prop_get | owner_set;
    public property presenter => prop_all, { validate => \&_validatePresenter };
}

our %CTOR = (
    'IMPL::DOM::Document' => sub { nodeName => 'document' }
);

sub provider {
    my ($this,%args) = @_;
    
    if (my $provider = $this->_provider) {
        return $provider;
    } else {
        return $this->_provider(new Template::Provider(
            \%args
        ));
    }
}

sub context {
    my ($this) = @_;
    
    if (my $ctx = $this->_context) {
        return $ctx;
    } else {
        return $this->_context (
            new Template::Context(
                VARIABLES => {
                    document => $this,
                    this => $this,
                    render => sub {
                    	$this->_process(@_);
                    }
                },
                TRIM => 1,
                RECURSION => 1,
                LOAD_TEMPLATES => [$this->provider]
            )
        )
    }
}

sub _validatePresenter {
	my ($this,$value) = @_;
	
	die new IMPL::InvalidArgumentException("A view object is required") unless blessed($value) and $value->isa('Template::View');
}

sub LoadFile {
    my ($this,$filePath,$encoding) = @_;
    
    die new IMPL::InvalidArgumentException("A filePath parameter is required") unless $filePath;
    
    $encoding ||= 'utf8';
    
    $this->_context(undef);
    $this->_provider(undef);
    
    my ($vol,$dir,$fileName) = File::Spec->splitpath($filePath);
    
    my $inc = File::Spec->catpath($vol,$dir,'');
    
    $this->provider(
        ENCODING => $encoding,
        INTERPOLATE => 1,
        PRE_CHOMP => 1,
        POST_CHOMP => 1,
        INCLUDE_PATH => $inc
    );
    
    $this->template($this->context->template($fileName));
}

sub AddVar {
	my ($this,$name,$value) = @_;
	
	$this->context->stash->set($name,$value);
}

sub title {
    $_[0]->template->title;
}

sub Render {
    my ($this) = @_;
    
    return $this->template->process($this->context);
}

# Формирует представление для произвольных объектов 
sub _process {
	my ($this,@items) = @_;
	
	my @result;
	
	foreach my $item (@items) {
		if (blessed($item) and $item->isa('IMPL::Web::TT::Control')) {
			push @result, $item->Render();	
		} elsif(blessed($item)) {
			if ($this->presenter) {
				push @result, $this->presenter->print($item);
			} else {
				push @result, $this->toString;
			}
		} else {
			push @result, $item;
		}
	}
	
	return join '',@items;
}

sub Dispose {
    my ($this) = @_;
    
    $this->template(undef);
    $this->_context(undef);
    $this->_provider(undef);
    
    $this->SUPER::Dispose();
}

1;
__END__
=pod

=head1 NAME

C<IMPL::Web::TT::Document> - Документ, позволяющий строить представление по шаблону

=head1 SYNOPSIS

=begin code 

// create new document
my $doc = new IMPL::Web::TT::Document;

// load template
$doc->loadFile('Templates/index.tt');

// render file
print $doc->Render();

=end code

=head1 DESCRIPTION

C<use base qw(IMPL::DOM::Document)>

Документ, основанный на шаблоне Template::Toolkit. Позволяет загрузить шаблон,
и сформировать окончательный документ. Является наследником C<IMPL::DOM::Node>,
т.о. может быть использован для реализации DOM модели.

Внутри шаблона переменная C<document> ссылается на объект документа. По этой
причине образуется циклическая ссылка между объектами шаблона и документом, что
требует вызова метода C<Dispose> для освобождения документа.

=head1 METHODS

=over

=item C<CTOR()>

Создает новый экземпляр документа, свойство C<nodeName> устанавливается в 'C<document>'

=item C<$doc->LoadFile($fileName,$encoding)>

Загружает шаблон из файла C<$fileName>, используя кодировку C<$encoding>. Если
кодировка не указана, использует utf-8.

=item C<$doc->Render()>

Возвращает данные построенные на основе загруженного шаблона.

=item C<$doc->Dispose()>

Освобождает ресурсы и помечает объект как освобожденный.

=back

=head1 DOM

=begin code html

[% table = document.Create('env','table') %]

[% FOEACH item in document.result %]
	[% table.rows.Add( item.get('name','value') ) %]
[% END %]

[% form = document.Create('login','form') %]


[% form.template = 'LOGIN_FORM'%]

[% FOREACH item IN document.childNodes %]
	[%render(item)%]
[% END %]
	
[% BLOCK LOGIN_FORM %]
<form method="POST" action='/login.pl'>
	user: [% render(this.item('name')) %] password: [% render(this.item('password')) %] <input type="submit"/>
</form>
[% END %]

=end code html


=cut