comparison Lib/IMPL/Web/View/TTLoader.pm @ 345:72799d1211c5

sync
author cin
date Fri, 27 Sep 2013 16:28:27 +0400
parents 9bdccdf1f50b
children
comparison
equal deleted inserted replaced
344:f1d67615a5b1 345:72799d1211c5
3 3
4 use Template::Constants qw(:status); 4 use Template::Constants qw(:status);
5 5
6 use File::Spec(); 6 use File::Spec();
7 use IMPL::Const qw(:prop); 7 use IMPL::Const qw(:prop);
8 use Scalar::Util qw(weaken);
9
8 use IMPL::declare { 10 use IMPL::declare {
9 require => { 11 require => {
10 Provider => 'Template::Provider', 12 Provider => 'Template::Provider',
11 Context => 'IMPL::Web::View::TTContext', 13 Context => 'IMPL::Web::View::TTContext',
12 TTRegistry => 'IMPL::Web::View::TTRegistry', 14 TTRegistry => 'IMPL::Web::View::TTRegistry',
19 base => [ 21 base => [
20 'IMPL::Object' => undef, 22 'IMPL::Object' => undef,
21 'IMPL::Object::Serializable' => undef 23 'IMPL::Object::Serializable' => undef
22 ], 24 ],
23 props => [ 25 props => [
24 options => PROP_RO,
25 provider => PROP_RO, 26 provider => PROP_RO,
26 context => PROP_RO, 27 context => PROP_RO,
27 ext => PROP_RO, 28 registry => PROP_RO,
28 layoutBase => PROP_RO,
29 isInitialized => PROP_RO,
30 initializer => PROP_RO,
31 _globals => PROP_RW 29 _globals => PROP_RW
32 ] 30 ]
33 }; 31 };
34 32
35 sub save { 33 sub save {
56 sub CTOR { 54 sub CTOR {
57 my ($this,$refOpts,%args) = @_; 55 my ($this,$refOpts,%args) = @_;
58 56
59 $refOpts ||= {}; 57 $refOpts ||= {};
60 58
61 $this->ext($args{ext}) if $args{ext}; 59 # to aviod cyclic references we need to do a copy of $refOpts
62 $this->initializer($args{initializer}) if $args{initializer}; 60 $refOpts->{LOAD_TEMPLATES} = Provider->new( { %$refOpts } );
61
62 my $ctx = Context->new( { %$refOpts } );
63 $this->context($ctx);
64
63 $this->_globals(ref $args{globals} eq 'HASH' ? $args{globals} : {}); 65 $this->_globals(ref $args{globals} eq 'HASH' ? $args{globals} : {});
64 66
65 $this->options($refOpts); 67 $ctx->tt_ext($args{ext} || '.tt');
66 $this->layoutBase($args{layoutBase}) if $args{layoutBase}; 68
67 69 $this->registry(TTRegitry->new($ctx));
68 # to aviod cyclic references we need to do a copy of $refOpts 70
69 $refOpts->{LOAD_TEMPLATES} = $this->provider(Provider->new( { %$refOpts } )); 71 weaken($ctx);
70 72 weaken($this);
71 $this->context(Context->new($refOpts)); 73 $ctx->stash->update({
74 require => sub {
75 my ($modname) = @_;
76
77 my @inc;
78 push @inc, $ctx->base if $ctx->base;
79
80 my $ti = $ctx->find_template($name,@inc);
81
82 require $this->registry->Require($ti);
83 },
84 inclue => sub {
85 my ($name) = @_;
86
87 my @inc;
88 push @inc, $ctx->base if $ctx->base;
89
90 my $ti = $ctx->find_template($name,@inc);
91
92 return $ctx->include($ti->{template}, {base => $ti->{base}} );
93 }
94 });
95
96
72 } 97 }
73 98
74 sub document { 99 sub document {
75 my ($this,$name,$vars) = @_; 100 my ($this,$name,$vars) = @_;
76 101
77 $vars ||= {}; 102 $vars ||= {};
78 103
79 my $tt = $this->template($name); 104 my $factory = $this->registry->Require($name);
80 105
81 $this->_init(); 106 return $factory->new(hashMerge($vars, $this->_globals));
82
83 my $opts = { %{ $this->options } };
84
85 my $ctx = $this->context->clone();
86
87 $ctx->stash->update($vars);
88
89 my $registry = TTRegistry->new($this, $ctx);
90
91 my $factory = TTFactory->new($tt->class || TTDocument, $tt, $ctx, $name, $registry);
92
93 $vars->{registry} = $registry;
94 $vars->{layoutBase} = $this->layoutBase;
95
96 return $factory->new( $vars );
97 }
98
99
100 sub template {
101 my ($this,$name) = @_;
102
103 $name =~ s/^\s+|\s+$//g;
104
105 die ArgumentException->new("A valid template name is required") unless length $name;
106
107 $name = $this->_appendExt($name);
108
109 my ($tt,$error) = $this->provider->fetch($name);
110
111 if (defined $error and $error == STATUS_DECLINED) {
112 die KeyNotFoundException->new($name);
113 } elsif (defined $error and $error == STATUS_ERROR) {
114 die Exception->new("Failed to load a template", $name, $tt);
115 }
116
117 return $tt;
118 }
119
120 sub ResolveFileName {
121 my ($this,$fname) = @_;
122
123 $fname = $this->_appendExt($fname);
124
125 my @files = grep -f , map File::Spec->catfile($_,$fname), @{$this->provider->paths()};
126 return shift @files;
127 }
128
129 sub _appendExt {
130 my ($this,$name) = @_;
131
132 return $name unless $this->ext;
133
134 if (length $this->ext and substr( $name, -length($this->ext) ) eq $this->ext) {
135 return $name;
136 } else {
137 return $name . $this->ext;
138 }
139 }
140
141 sub _init {
142 my ($this) = @_;
143
144 if (!$this->isInitialized) {
145 my $initializer = $this->initializer || sub {};
146
147 eval {
148 $this->context->process($initializer,$this->_globals);
149 };
150 if (my $e = $@) {
151 die Exception->new("Failed to process an initializer", $this->initializer, $e);
152 }
153
154 $this->isInitialized(1);
155 }
156 } 107 }
157 108
158 1; 109 1;
159 110
160 __END__ 111 __END__
177 '/my/app/tt', 128 '/my/app/tt',
178 '/my/app/tt/lib' 129 '/my/app/tt/lib'
179 ] 130 ]
180 }, 131 },
181 ext => '.tt', 132 ext => '.tt',
182 initializer => 'shared/global' 133 globals => {
134 images => '//cdn.mysite.net/static/images'
135 }
183 136
184 ); 137 );
185 138
186 my $doc = $loader->document('index'); 139 my $doc = $loader->document('index');
187 140