view Lib/IMPL/Web/View/TTControl.pm @ 260:2879cdb6b8cd

sync
author sergey
date Tue, 25 Dec 2012 02:18:59 +0400
parents f48a1a9f4fa2
children 6b6d4b2275a1
line wrap: on
line source

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

use IMPL::Const qw(:prop);
use IMPL::lang qw(:hash);
use Scalar::Util qw(blessed);
use IMPL::declare {
	require => {
        TTContext => 'Template::Context',
        Exception => 'IMPL::Exception',
        ArgumentException => '-IMPL::InvalidArgumentException',
        OperationException => '-IMPL::InvalidOperationException'
	},
	base => [
	   'IMPL::Object' => undef
	],
	props => [
	   id => PROP_RO,
	   attributes => PROP_RW,
	   name => PROP_RO,
	   context => PROP_RO,
	   template => PROP_RO
	]
};


{
    my $nextId = 1;
    sub _GetNextId {
        return $nextId++;
    }
}

our $AutoloadRegex = qr/^[a-z]/;
our @REFLECT_META = qw(title layout);

sub CTOR {
    my ($this,$name,$template,$context,$refProps) = @_;
    
    $name ||= "control";
    
    $this->template( $template ) or die new IMPL::ArgumentException("A template is required");
    $this->context( $context ) or die new IMPL::ArgumentException("A context is required");
    
    $this->id($name . "-" . _GetNextId()) unless $this->id;
    
    $this->name($name);
    $this->attributes({});
    
    my %attrs;
    
    foreach my $meta ( @REFLECT_META ) {
        next if $meta =~ /^_/;
        if( my $value = $template->$meta() ) {
            $attrs{$meta} = $value;
        }
    }
    
    hashApply(\%attrs,$refProps) if ref $refProps eq 'HASH';
    
    while (my($key,$value) = each %attrs) {
        $this->SetAttribute($key,$value);
    }
}

sub InitInstance {
    my ($this,$args) = @_;
    
    $args ||= {};
    
    if ( my $ctor = $this->template->blocks->{CTOR} ) {
        $this->context->include($ctor, { %$args, this => $this, template => $this->template } );
    }
}

sub GetAttribute {
    my ($this,$name) = (shift,shift);
    
    if (my $method = $this->can($name)) {
        unshift @_,$this;
        goto &$method;
    } else {
        return $this->attributes->{$name};
    }
}

sub SetAttribute {
    my $this = shift;
    my $name = shift;
    
    if (my $method = $this->can($name)) {
        unshift @_, $this;
        goto &$method;
    } else {
        return $this->attributes->{$name} = shift;
    }
}

sub GetRenderBlock {
    $_[0]->template->blocks->{RENDER} || $_[0]->template;
}

sub Render {
    my ($this,$args) = @_;
    
    $args = {} unless ref $args eq 'HASH';
    
    if(my $body = $this->GetRenderBlock ) {
        return $this->context->include( $body, { %$args, this => $this, template => $this->template } );
    } else {
        return "";
    }    
}

sub AUTOLOAD {
    our $AUTOLOAD;
    
    my $method = ($AUTOLOAD =~ m/(\w+)$/)[0];
    
    return if $method eq 'DESTROY';
    
    if ($method =~ /$AutoloadRegex/) {
        my $this = shift;
        
        die OperationException->new("can't invoke method '$method' on an unblessed reference") unless blessed $this;
    
        return @_ ? $this->SetAttribute($method,@_) : $this->GetAttribute($method);
    } else {
        die OperationException->new("The specified method '$method' doesn't exists");
    }
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::View::TTControl>

=head1 SYNPOSIS

=head1 DESCRIPTION

=head2 BLOCKS

=head3 INIT

Данный блок шаблона управления выполняется один раз при создании первого экземпляра элемента управления,
может использоваться для формирования заголовочной части документа, скрипта подключающего ajax модули
при необходимости и т.п.

=head3 CTOR

данный блок выполняется каждый раз при создании нового экземпляра элемента управления, при этом переменная C<this>
указывает на эземпляр элемента упарвления. Данный блок можно использовать для инициализации свойств элемента
управления.

=head3 RENDER

Данный блок выполняется при вызове метода C<Render()>, вывод данного блока и есть результат отображения элемента управления.
Если в шаблоне нет блока C<RENDER>, то сам шаблон считается таковым. 

=head2 TEMPLATE VARS

Каждый шаблон имеет собственное пространство имен, унаследованное от пространства имен фабрики элементов (которая в свою очередь наследует контекст документа).
В шаблоне могут определяться новые переменные, которые разделяются между блоками. Также доступны стандартные переменные

=over

=item * C<this> ссылка на объект элемента управления

=item * C<component> ссылка на текущий шаблон, устанавливается автоматически в методе C<Template::Context::process>.

=item * C<template> ссылка на шаблон элемента управления, для совместимости с C<TT>

=back

=head1 MEMBERS

=over

=item * C<[get]context>

Контекст элемента управления, хранит пременные шаблона. Наследуется от контекста фабрики элементов управления, который
наследуется от контекста документа.

=item * C<[get,set]template>

C<Template::Document> Шаблон элемента управления.

=item * C<AUTOLOAD>

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

=back


C<lang ru>

=cut