Mercurial > pub > Impl
view Lib/IMPL/Web/View/TTDocument.pm @ 299:bd79145657e5
sync
author | sergey |
---|---|
date | Thu, 21 Mar 2013 16:00:09 +0400 |
parents | 78f767765706 |
children | bf3af33b9003 |
line wrap: on
line source
package IMPL::Web::View::TTDocument; use strict; use Scalar::Util qw(weaken); use IMPL::Const qw(:prop); use IMPL::lang qw(:hash is); use Carp qw(carp); use mro; use IMPL::declare { require => { TTFactory => 'IMPL::Web::View::TTFactory', TTControl => 'IMPL::Web::View::TTControl', Loader => 'IMPL::Code::Loader' }, base => [ 'IMPL::Web::View::TTControl' => sub { my ($template,$ctx) = @_; $ctx ||= Template::Context->new(); return 'document', $template, $ctx; # context } ], props => [ layout => PROP_RW, loader => PROP_RW, ] }; sub CTOR { my ($this,$template,$ctx,$loader,$vars) = @_; $this->controls({}); $this->loader($loader) if $loader; $this->layout( $template->layout ) unless $this->layout; $this->context->stash->update($vars) if ref $vars eq 'HASH'; $this->InitInstance(); } sub Render { my ($this,$args) = @_; $args ||= {}; my %controls; my $require; my $documentContext; my $self = $this; $require = sub { my $control = shift; unless($self) { carp("Cant load control $control outside the rendering procedure"); return; } if (my $factory = $controls{$control}) { return $factory; } else { my $path = $control; if ( my $template = $self->loader->template($path) ) { $factory = new IMPL::Web::View::TTFactory( $template, $documentContext, join( '/', splice( @{[split(/\//,$path)]}, 0, -1 ) ), $require ); $controls{$control} = $factory; return $factory; } else { die new IMPL::KeyNotFoundException($control); } } }; $this->context->localise(); $documentContext = _clone_context( $this->context ); $this->context->stash->set(require => $require); $this->context->stash->set(document => sub { $self }); my $text = eval { if ($this->layout) { my $tlayout = $this->loader->layout($this->layout); if(my $init = $tlayout->blocks->{INIT}) { $this->context->process( $init, hashMerge( $args, { template => $this->template } ) ); } my $content = $this->next::method($args); return $this->context->include( $tlayout, { %{$args}, content => $content, this => $this, template => $this->template } ); } else { return $this->next::method($args); } }; undef $require; undef $documentContext; undef %controls; undef $self; $this->context->delocalise(); my $e = $@; if ($e) { die $e; } else { return $text; } } sub _clone_context { my $args = { %{shift || {}} }; delete $args->{CONFIG}; return Template::Context->new($args); } 1; __END__ =pod =head1 NAME C<IMPL::Web::View::TTDocument> - документ для построения HTML страницы на основе шаблонов TT. =head1 SYNOPSIS =begin code use IMPL::Web::View::TTDocument(); my $doc = new IMPL::Wbe::View::TTDocument($template,$ttOptions); return $doc->Render(); =end code Однако, более предпочтительный способ использовать C<IMPL::Web::View::TTLoader>. =head1 DESCRIPTION Документ для представления данных. Документы представляют собой иерархически организованные данные, элементами данного документа являются данные для отображения, такие как =over =item * Объекты из БД =item * Навигационные цепочки =item * Меню и т.п. =back Скприт шаблона формирует структуру документа, затем сформированная структура форматируется в готовый документ. Процесс форматирования объектной модели в готовый документ может быть выполнена как вручную, так и при помощи вспомогательного шаблона - обертки. Если у шаблона документа указан C<layout> в метаданных, то он будет использован как шаблон для форматирования объектной модели, вывод самого шаблона будет проигнорирован. Если обертка не задана, то результатом будет вывод самого скрипта шаблона. Использование объектной модели документа позволяет решить задачи по созданию контейнеров, у которых может быть сложное содежимое. Примером таких элементов могут быть формы, внутри форм элементы управления также могут группироваться. =head2 Элементы управления (компоненты) Документ состоит из узлов, часть которых наследуется от C<IMPL::Web::View::TTControl>, такие узлы называются элементами управления. Каждый элемент управления имеет собственный контекст, который наследуется от контекста документа. =head2 Фабрика элементов управления Для создания элементов управления используются фабрики. Каждый элемен управления имеет свой шаблон для форматиорвания содержимого, фабрика связывает шаблон и класс элемента управления, для чего при загрузке шаблона используется свойство C<type> из метаданных. Фабрика загружается в документ при том только один раз, повторные загрузки фабрики возвращают уже загруженную. Для загрузки фабрики используется метод C<require()> с указанием элемента управления. =head2 Порядок обработки документа Построение представления данных состоит из двух этапов =over =item 1 Создание объектной модели документа. На данном этапе создаются все элементы управления. =item 1 Преобразование объектной модели в конечнное представление. На данном этапе происходит форматирование документа. =back =head2 Загрузка элемента управления =over =item 1 C<TInput = require('my/org/input')> =item 1 Загружается шаблон C<my/org/input.tt> =item 1 Создается фабрика элементов управления с собственным контекстом, унаследованным от контекст документа. =item 1 При первом создании элемента управления фабрика инициализируется выполнением блока C<INIT>. =back =head2 Создание элемента управления =over =item 1 C<< TInput.new('login') >> =item 1 Создается новый дочерний контекст к контексту фабрики =item 1 Создается экземпляр элемента управления =item 1 Выполняется блок конструктора C<CTOR> в контексте элемента управления, параметр C<this> имеет значение нового экземпляра элемента управления =back =head1 MEMBERS =over =item C<CTOR($template, $contextOpts, $loader[, $vars])> Создает экземпляр документа с указанным шаблоном и параметрами. =over =item C<$template> C<Template::Document> шаблон документа. =item C<$contextOpts> C<HASH> Параметры контекста C<Template::Context> для документа. Эти параметры будут сохранены в свойстве C<opts>, а также на их основе будет создан контекст текщего документа. Как правило эти параметы задаются загрузчиком документа C<IMPL::Web::View::TTLoader>, таким образом, что C<Template::Stash> создаваемого контекста наследует переменные из контекста загрузчика. =item C<$loader> C<IMPL::Web::View::TTLoader> загрузчик, который будет использоваться для загрузки элементов управления, а также для получения обертки, заданной в свойстве документа C<layout>. =item C<$vars> C<HASH> Необязательный параметр. переменные которые будут переданы в блок конструктора C<INIT>. Как правило они используются для передачи данных для построения документа =back =back =over =item C<templateVars($name[,$newValue])> Получает или задает переменную для шаблона документа. Имя переменнной может быть составным, например C<'my.var.name'>, см. C<Template::Stash::set()>. =item C<RequireControl($controlName)> Загружает фабрику элемента управления, если она уже была загружена, возвращает на нее ссылку. При загрузки фабрики для нее создается собственный контекст на основе параметров из свойства C<opts> и ее пространство имен наследуется от пространства имен документа из свойства C<stash>. =item C<Render($vars)> Выполняет блок C<renderBlock> документа для получения конечного представления, C<$vars> содержит переменные для блока. =item C<RenderContent($vars)> Выполняет шаблон документа для получения представления содержимого, в отличии от метода C<Render> не использует обертку указанную в свойстве C<layout>, если обертка не указана, то эти методы идентичны. =item C<[get,set]layout> Обертка, которая будет использована для построения представления документа. В обертке будет доступна специальная переменная C<content>, при обращении к которой будет B<выполнен> метод C<RenderContent()> и возвращен результат его работы. Для получения шаблона обертки используется загрузчик из свойства C<loader>. =item C<[get]opts> Параметры контекста, используются для создания контекстов фабрик элементов управления. =item C<[get]loader> Загрузчик, используется для загрузки шаблонов фабрик элементов управления и обертки. =item C<[get]controls> C<HASH> Коллекция загруженных фабрик элементов управления, ключем является квалифицированное имя элемента управления. =item C<[get]stash> C<Template::Stash> Пространство имен документа, оно используется как родительское для пространств имен загружаемых фабрик элементов управления. =back =head1 TEMPLATES =begin text [%META layout='default'%] [% BLOCK CTOR; section('top','TOP'); section('bottom','BOTTOM'); section('client','CLIENT'); END %] [% BLOCK TOP; TMenu = require('my/org/Menu'); append(TMenu.new()); END %] =end =cut