view Lib/IMPL/Web/Application/ControllerUnit.pm @ 112:0ed8e2541b1c

Form processing mechanism
author wizard
date Tue, 18 May 2010 17:59:31 +0400
parents 6c25ea91c985
children 7b14e0122b79
line wrap: on
line source

package IMPL::Web::Application::ControllerUnit;
use strict;
use base qw(IMPL::Object);

use IMPL::Class::Property;
use IMPL::DOM::Transform::PostToDOM;
use IMPL::DOM::Schema;

use constant {
	CONTROLLER_METHODS => 'controller_methods',
	STATE_CORRECT => 'correct',
	STATE_NEW => 'new',
	STATE_INVALID => 'invalid'
};

BEGIN {
	public property action => prop_get | owner_set;
	public property application => prop_get | owner_set;
	public property query => prop_get | owner_set;
	public property formData => prop_get | owner_set;
	public property formSchema => prop_get | owner_set;
	public property formErrors => prop_get | owner_set;
}

sub CTOR {
	my ($this,$action,$args) = @_;
	
	$this->action($action);
	$this->application($action->application);
	$this->query($action->query);
	
	$this->$_($args->{$_}) foreach qw(formData formSchema formErrors);
}

sub forms {
	my ($self,%forms) = @_;
	
	while ( my ($method,$info) = each %forms ) {
		die new IMPL::Exception("A method doesn't exists in the controller",$self,$method) unless $self->can($method);
		if ( not ref $info ) {
			$self->class_data(CONTROLLER_METHODS)->{$method} = {
				wrapper => 'FormWrapper',
				schema => $info
			};
		} elsif (ref $info eq 'HASH') {
			die new IMPL::Exception("A schema must be specified",$self,$method) unless $info->{schema};
			
			$self->class_data(CONTROLLER_METHODS)->{$method} = {
				wrapper => 'FormWrapper',
				schema => $info->{schema} 
			};
		} else {
			die new IMPL::Exception("Unsupported method information",$self,$method);
		}
	}
}

sub transactions {
	
}

sub InvokeAction {
	my ($self,$method,$action) = @_;
	
	if (my $methodInfo = $self->class_data(CONTROLLER_METHODS)->{$method}) {
		if (my $wrapper = $methodInfo->{wrapper}) {
			return $self->$wrapper($method,$action,$methodInfo);
		} else {
			return $self->TransactionWrapper($method,$action,$methodInfo);			
		}
	} else {
		die new IMPL::InvalidOperationException("Invalid method call",$self,$method);
	}
}

sub TransactionWrapper {
	my ($self,$method,$action,$methodInfo) = @_;
	
	my $unit = $self->new($action);
	return $unit->$method();
}

sub FormWrapper {
	my ($this,$method,$action,$methodInfo) = @_;
	
	my $schema = $this->loadSchema($methodInfo->{schema});
	
	my $process = $this->query->param('process') || 0;
	
	
	
	my %result = (
		
	);
}

1;

__END__

=pod

=head1 NAME

C<IMPL::Web::Application::ControllerUnit> - базовый класс для обработчика транзакций в модели контроллера.

=head1 DESCRIPTION

Классы, наследуемые от данного класса используются для выполнения транзакций, которые приходят
через контроллер запросов. Как правило один класс представляет собой пакет транзакций, каждая
из которых является независимой от другой.

Перед выполнением транзакции создается экземпляр объекта, в рамках которого будет выполнена транзакция.
Для этого вызывается метод C<InvokeAction($method,$action)>, который создает/восстанавливает контекст
транзакции.

Транзакции на данный момент делятся на простые и формы.

=head2 Простые транзакции

Простые транзакции получаю только запрос, без предварительной обработки, и возвращенный результат напрямую
передается пользователю.

=head2 Формы

При использовании форм запрос предварительно обрабатывается, для получения DOM документа с данными формы.
Для постороенния DOM документа используется схема. При этом становятся доступны дополнительные свойства
C<formData>, C<formSchema>, C<formErrors>.

Результат выполнения транзакции не возвращается напрямую пользователю, а включается в общий ответ, который
выглядит следующим образом

=begin code

{
	state => '{ new | correct | invalid }',
	result => $transactionResult,
	formData => $formDOM,
	formSchema => $formSchema,
	formErrors => @errors
}

=end code

=over

=item C<state>

Состояние верификации формы.

=over

=item C<new>

Первоначальное содержимое формы, оно может быть некорректным, но это нормально.
В данном состоянии транзакция обычно не выполняется.

=item C<correct>

Данные формы корректны, транзакция выполнена, и ее результат доступен через поле C<result>

=item C<invalid>

Содержимое формы не прошло верификацию, ошибки доступны через поле C<formErrors>. Транзакция
не выполнялась.

=back

=item C<result>

Результат выполнения транзакции, если конечно таковая выполнялась.

=item C<formData>

ДОМ документ с данными формами. Документ существует всегда, не зависимо от его корректности,
может быть использован для построения формы, уже заполненную параметрами.

=item C<formSchema>

Схема данных формы, может использоваться для построения динамических форм.

=item C<formErrors>

Ошибки верификации данных, если таковые были

=back

=head1 MEMBERS

=over

=item C<[get] application>

=item C<[get] query>

=item C<[get] response>

=item C<[get] formData>

=item C<[get] formSchema>

=item C<[get] formErrors>

=item C<InvokeAction($method,$action)>

Конструирует контекст выполнения транзакции, может быть переопределен для конструирования контекста по
своим правилам.

=item C<TransactionWrapper($method,$action,$methodInfo)>

Обертка для конструирования простых транзакций, может быть переопределен для конструирования контекста по
своим правилам.

=item C<FormWrapper($method,$action,$methodInfo)>

Обертка для конструирования форм, может быть переопределен для конструирования контекста по
своим правилам.

=back

=head1 EXAMPLE

=begin code

package MyBooksUnit;
use strict;
use base qw(IMPL::Web::Application::ControllerUnit);

__PACKAGE__->PassThroughArgs;

__PACKAGE__->transactions(qw(
	find 
	info
));
__PACKAGE__->forms(
	create => 'books.create.xml'
);

sub find {
	my ($this) = @_;
	
	return $this->application->dataSource->resultset('Books')->find({author => $this->query->param('author')});
}

sub info {
	my ($this) = @_;
	
	return $this->application->dataSource->resultset('Books')->find({id => $this->query->param('id')});
}

sub create {
	my ($this) = @_;
	
	my %book = map {
		$_ => $this->formData->selectSingleNode($_)->nodeValue
	} qw(author_id title year ISBN);
	
	return $this->application->datasource->resultset('Books')->create(\%book);
}

=end code

=cut