Mercurial > pub > Impl
view Lib/IMPL/Web/View/TTContext.pm @ 348:f116cd9fe7d9
working on TTView: pre-alpha version
author | cin |
---|---|
date | Thu, 03 Oct 2013 19:48:57 +0400 |
parents | 3eafa6fefa9f |
children | 86b470004d47 |
line wrap: on
line source
package IMPL::Web::View::TTContext; use strict; use Template::Base; use Carp qw(carp); use IMPL::Exception(); use IMPL::lang qw(is typeof hashApply); use IMPL::declare { require => { Document => '-Template::Document', TypeKeyedCollection => 'IMPL::TypeKeyedCollection', ArgException => "-IMPL::InvalidArgumentException" }, base => [ 'Template::Context' => '@_' ] }; BEGIN { no strict 'refs'; foreach my $prop (qw( root base tt_ext tt_cache parent prefix cache includes )) { my $t = $prop; *{__PACKAGE__ . '::' . $prop} = sub { my $this = shift; return @_ ? $this->stash->set($t, @_) : $this->stash->get($t); } } } sub clone { my $this = shift; my $params = shift; $this->localise(); my $args = { %{$this} }; $this->delocalise(); my $class = ref($this); delete $args->{CONFIG}; my $clone = $class->new($args); $clone->stash->update($params) if $params; return $clone; } sub find_template { my ($this,$name) = @_; my $cache = $this->tt_cache; $this->tt_cache($cache = {}) unless $cache; if(my $tpl = $cache->{$name}) { return $tpl; } my @inc = ($this->base, @{$this->includes || []}); my $ext = $this->tt_ext || ""; my $file; foreach my $dir (@inc) { $file = $dir ? "$dir/$name" : $name; my $base = join('/',splice([split(/\/+/,$file)],0,-1)); $file = $ext ? "$file.$ext" : $file; warn "lookup: $file"; my $tt = eval { $this->template($file) }; return $cache->{$name} = { base => $base, template => $tt, } if $tt; } $this->throw(Template::Constants::ERROR_FILE, "$name: not found"); } sub display { my $this = shift; my $model = shift; my ($template, $args); if (ref $_[0] eq 'HASH') { $args = shift; } else { $template = shift; $args = shift; } my $prefix = $this->prefix; if (not(($args and delete $args->{'-no-resolve'}) or ref $model)) { $prefix = $prefix ? "${prefix}.${model}" : $model; $model = $this->resolve_model($model); } else { $prefix = ""; } $template = $template ? $this->find_template($template) : $this->find_template_for($model); return $this->render( $template, hashApply( { prefix => $prefix, model => $model, }, $args ) ); } sub invoke_environment { my ($this,$code,$env) = @_; $env ||= {}; my $out = eval { $this->localise( hashApply( { root => $this->root || $this, cache => TypeKeyedCollection->new(), display => sub { $this->display(@_); }, render => sub { $this->render(@_); } }, $env ) ); &$code($this); }; my $e = $@; $this->delocalise(); die $e if $e; return $out; } sub render { my ($this,$template,$args) = @_; $args ||= {}; #TODO handle classes my $base; $template = $this->find_template($template) unless ref $template; if (ref $template eq 'HASH') { $base = $template->{base}; $template = $template->{template}; } else { carp "got an invalid template object: $template"; $base = $this->base; } return $this->invoke_environment( sub { return shift->include($template,$args); }, { base => $base, parent => $this } ) } sub resolve_model { my ($this,$prefix) = @_; die ArgException->new(prefix => "the prefix must be specified") unless defined $prefix; #TODO handle DOM models my @comp = map { $_, 0 } grep length($_), split(/\.|\[(\d+)\]/, $prefix); return $this->stash->get(['model',0,@comp]); } sub find_template_for { my ($this,$model) = @_; my $type = typeof($model); return $this->find_template('templates/plain') unless $type; if (my $template = $this->cache->Get($type)) { return $template; } else { no strict 'refs'; my @isa = $type; while (@isa) { my $sclass = shift @isa; (my $name = $sclass) =~ s/:+/_/g; $template = $this->find_template("templates/$name"); if ($template) { $this->cache->Set($sclass,$template); return $template; } push @isa, @{"${sclass}::ISA"}; } } return; } 1; __END__ =pod =head1 NAME C<IMPL::Web::View::TTContext> - доработанная версия контекста =head1 DESCRIPTION Расширяет функции C<Template::Context> =begin plantuml @startuml object RootContext { document globals } object DocumentContext { base extends } object ControlContext { base extends } RootContext o-- DocumentContext RootContext o-- ControlContext Document -- DocumentContext Control - ControlContext Loader . RootContext: <<creates>> Loader . Document: <<creates>> Loader -up- Registry @enduml =end plantuml =head1 MEMBERS =head2 C<[get,set]base> Префикс пути для поиска шаблонов =head2 C<template($name)> Сначала пытается загрузить шаблон используя префикс C<base>, затем без префикса. =head2 C<clone()> Создает копию контекста, при этом C<stash> локализуется, таким образом клонированный контекст имеет собственное пространство имен, вложенное в пространство родительского контекста. =cut