view Lib/IMPL/Web/View/TTFactory.pm @ 298:78f767765706

TT view refactoring
author cin
date Tue, 19 Mar 2013 02:02:37 +0400
parents 86ff93b34f2a
children bf3af33b9003
line wrap: on
line source

package IMPL::Web::View::TTFactory;
use strict;

use Template::Context();

use IMPL::lang qw(:hash);
use IMPL::Exception();
use Scalar::Util qw(weaken);


use IMPL::Const qw(:prop);
use IMPL::declare {
    require => {
        Loader => 'IMPL::Code::Loader'
    },
    base => [
        'IMPL::Object::Factory' => sub {
            shift->class || 'IMPL::Web::View::TTControl'
        }
    ],
    props => [
        template => PROP_RW,
        context => PROP_RW,
        instances => PROP_RW,
        base => PROP_RW,
        require => PROP_RO
    ]
};

sub CTOR {
    my ($this,$template,$context,$base,$require) = @_;
    
    die IMPL::ArgumentException("A template is required") unless $template;
    
    Loader->safe->Require($this->factory)
        if $this->factory and not ref $this->factory;
    
    $context ||= new Template::Context();
    
    $this->template($template);
    $this->context($context);
    $this->base($base);
    $this->instances(0);
    $this->require($require);
}

sub MergeParameters {
    my ($this,$name,$refProps) = @_;
    
    if (ref $name) {
        $refProps = $name;
        $name = (ref $refProps eq 'HASH' and ($refProps->{name} || $refProps->{id})) || '*anonymous*';
    }
    
    $refProps->{factory} = $this;
    
    my $base = $this->base;
    
    $this->context->localise();
    
    my $ctx = _clone_context($this->context);
    
    $this->context->delocalise();
    
    my $stash = $ctx->stash;
    my $require = $this->require;
    
    
    $stash->update({
        require => sub {
            my ($module) = @_;
            
            $module =~ s/^\.\//$base\//;
            return $require->($module);
        }        
    });
    
    return ($name, $this->template, $ctx, $refProps);
}

sub CreateObject {
    my $this = shift;
    
    my $count = $this->instances;
    
    unless($count) {
        # нужно выполнить именно блок INIT шаблона при создании первого экземпляра
        if (my $init = $this->template->blocks->{INIT}) {
            $this->context->process($init);
        }
        
        $this->context->visit($this->template->blocks);
    }
    
    my $instance = $this->SUPER::CreateObject(@_);
    
    $instance->InitInstance();
    
    $count++;
    $this->instances($count);
    
    return $instance;
}

sub _clone_context {
    my $args = { %{shift || {}} };
    delete $args->{CONFIG};
    
    return Template::Context->new($args);
}

sub save {
    die new IMPL::NotImplementedException("This class doesn't support serialization");
}

sub restore {
    die new IMPL::NotImplementedException("This class doesn't support serialization");
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::View::TTFactory> - фабрика элементов управления

=head1 SYNOPSIS

=begin code

my $factory = new IMPL::Web::View::TTFactory(
    'IMPL::Web::View::TTControl',
    $doc,
    $context,
    {
        TRIM => 1
    },
    {
        myprop => 'my value'
    },
);

my $input1 = $factory->new('login', { class => "required" } );

my $propval = $input->nodeProperty('myprop'); # 'my value'

=end code

=begin text

[%
    this.appendChild(
        my.org.input.new('login', class = this.errors('login') ? "invalid" : "" )
    );
%]

=end text

=head1 DESCRIPTION

C< Inherits L<IMPL::Object::Factory> >

=head1 MEMBERS

=over

=item C<[get,set]template>

Документ C<Template::Document> который описывает элемент управления. См. C<IMPL::Web::View::TTControl>.

=item C<[get,set]context>

Контекст фабрики элементов управления, в этом контексте выполняет шаблон элемента управления при загрузке.
Далее в этом контексте будет выполнен блок инициализации при создании первого элемента управления.

=item C<[get,set]opts>

Параметры контекста элемента управления (ссылка на хеш). Каждый элемент управления при создании получает свой контекст,
который создает с данными параметрами и хранилищем переменных, дочерним к контексту фабрики.

=item C<[get,set]nodeProperties>

Ссылка на хеш со значениями свойств по умолчанию для создаваемого элемента управления.

=item C<[get]instances>

Количество созданных элементов управления данной фабрикой

=item C<[override]MergeParameters($name,$nodeProps)>

Превращает значения переданные методу C<new> фабрики в параметры для создания элемента управления.

=over

=item C<$name>

Имя создаваемого узла (C<nodeName>).

=item C<$nodeProps>

Ссылка на шех со значениями свойств узла. Данные значения будут совмещены со значениями из свойства C<nodeProperties>

=back

=item C<[override]CreateObject(@params)>

Создает экземпляр элемента управления стандартным образом. Учитывает количество экземпляров и если это первый,
то производит дополнительную инициализацию контекста выполнив блок шаблона C<INIT>.

=item C<[inherited]new($name,$nodeProps)>

Создает элемент управления с указанным именем и набором свойств. 

=back

=cut