Mercurial > pub > Impl
view Lib/IMPL/Web/View/TTLoader.pm @ 323:b56b1ec33b59
minor changes to support JSON in transformation from a query to an object
author | sergey |
---|---|
date | Thu, 23 May 2013 18:40:26 +0400 |
parents | d3b5a67ad2e8 |
children | 86336d451b82 |
line wrap: on
line source
package IMPL::Web::View::TTLoader; use strict; use Template::Constants qw(:status); use IMPL::Const qw(:prop); use IMPL::declare { require => { Provider => 'Template::Provider', Context => 'Template::Context', TTRegistry => 'IMPL::Web::View::TTRegistry', TTFactory => 'IMPL::Web::View::TTFactory', TTDocument => '-IMPL::Web::View::TTDocument', Exception => 'IMPL::Exception', ArgumentException => '-IMPL::InvalidArgumentException', KeyNotFoundException => '-IMPL::KeyNotFoundException' }, base => [ 'IMPL::Object' => undef, 'IMPL::Object::Serializable' => undef ], props => [ options => PROP_RO, provider => PROP_RO, context => PROP_RO, ext => PROP_RO, layoutBase => PROP_RO, isInitialized => PROP_RO, initializer => PROP_RO, _globals => PROP_RW ] }; sub save { my ($this,$context) = @_; $context->AddVar($_, $this->$_()) for qw(options provider context ext layoutBase); } sub restore { my ($class,$data,$surrogate) = @_; my %params = @$data; my $refOpts = delete $params{options}; if ($surrogate){ $surrogate->callCTOR($refOpts,%params); } else { $surrogate = $class->new($refOpts,%params); } return $surrogate; } sub CTOR { my ($this,$refOpts,%args) = @_; $refOpts ||= {}; $this->ext($args{ext}) if $args{ext}; $this->initializer($args{initializer}) if $args{initializer}; $this->_globals(ref $args{globals} eq 'HASH' ? $args{globals} : {}); $this->options($refOpts); $this->layoutBase($args{layoutBase}) if $args{layoutBase}; # to aviod cyclic references we need to do a copy of $refOpts $refOpts->{LOAD_TEMPLATES} = $this->provider(Provider->new( { %$refOpts } )); $this->context(Context->new($refOpts)); } sub document { my ($this,$name,$vars) = @_; $vars ||= {}; my $tt = $this->template($name); $this->_init(); my $opts = { %{ $this->options } }; $this->context->localise(); my $ctx = _clone_context($this->context); $this->context->delocalise(); $ctx->stash->update($vars); my $registry = TTRegistry->new($this, $ctx); my $factory = TTFactory->new($tt->class || TTDocument, $tt, $ctx, $name, $registry); $vars->{registry} = $registry; $vars->{layoutBase} = $this->layoutBase; return $factory->new( $vars ); } sub template { my ($this,$name) = @_; $name =~ s/^\s+|\s+$//g; die ArgumentException->new("A valid template name is required") unless length $name; $name = $this->_appendExt($name); my ($tt,$error) = $this->provider->fetch($name); if (defined $error and $error == STATUS_DECLINED) { die KeyNotFoundException->new($name); } elsif (defined $error and $error == STATUS_ERROR) { die Exception->new("Failed to load a template", $name, $tt); } return $tt; } sub _appendExt { my ($this,$name) = @_; return $name unless $this->ext; if (length $this->ext and substr( $name, -length($this->ext) ) eq $this->ext) { return $name; } else { return $name . $this->ext; } } sub _init { my ($this) = @_; if (!$this->isInitialized) { my $initializer = $this->initializer || sub {}; eval { $this->context->process($initializer,$this->_globals); }; if (my $e = $@) { die Exception->new("Failed to process an initializer", $this->initializer, $e); } $this->isInitialized(1); } } sub _clone_context { my $args = { %{shift || {}} }; delete $args->{CONFIG}; return Template::Context->new($args); } 1; __END__ =pod =head1 NAME C<IMPL::Web::View::TTLoader> - предоставляет глобальный контекст для загрузки шаблонов =head1 SYNOPSIS =begin code use IMPL::Web::View::TTLoader(); my $loader = new IMPL::Web::View::TTLoader( { INCLUDE_PATH => [ '/my/app/tt', '/my/app/tt/lib' ] }, ext => '.tt', initializer => 'shared/global' ); my $doc = $loader->document('index'); my $html = $doc->Render(); =end code =head1 DESCRIPTION Провайдер для загрузки шаблонов и документов. Имеет собственное пространство имен, контекст выполнения шаблонов. Контект загрузчика инициализируется шаблоном, в котором определяются глобальные переменные, которые будут доступны в документах, однако их изменения будут локализованы. Инициализация контекста провайдера происходит при первой загрузке любого документа. =head1 MEMBERS =head2 C<CTOR($options,%args)> =over =item * C<$options> Параметры контекста загрузчика, контексты документов и элементов управления также унаследуют эти свойства. Напрямую передаются в конструктор C<Template::Context>. =item * C<%args> Именованные параметы загрузчика. =over =item * C<ext> Расширение, которое будет добавляться к именам шаблонов и документов (если оно не будет указано явно). =item * C<initializer> Имя шаблона, который будет использован для инициализации контекста. =item * C<globals> Глобальные переменнын, которые будут переданы в контекст. =item * C<layoutBase> Путь к шаблонам для оформления документов. Каждый документ может задавать свой C<layout> указанный в его C<META> блоке или конструкторе. См. C<IMPL::View::TTDocument>. =back =back =head2 C<document($docName)> Загружает документ с именем C<$docName>. При необходимости к нему будет добавлено расширение, указанное в свойстве C<ext>. Это единственно полезный метод провайдера. =cut