Mercurial > pub > Impl
view Lib/IMPL/Web/TT/Document.pm @ 103:c289ed9662ca
Schema beta 2
More strict validation, support for inflating a simple nodes and properties
author | wizard |
---|---|
date | Fri, 07 May 2010 18:17:40 +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