Mercurial > pub > Impl
changeset 67:9f5795a10939
Documentation, minor fixes
author | wizard |
---|---|
date | Fri, 19 Mar 2010 20:06:12 +0300 |
parents | f47f93534005 |
children | 739f1288ca84 |
files | Lib/IMPL/Object/Factory.pm Lib/IMPL/Web/Application.pm Lib/IMPL/Web/Application/Action.pm Lib/IMPL/Web/Application/Response.pm _test/Resources/app.xml |
diffstat | 5 files changed, 334 insertions(+), 60 deletions(-) [+] |
line wrap: on
line diff
--- a/Lib/IMPL/Object/Factory.pm Thu Mar 18 17:58:33 2010 +0300 +++ b/Lib/IMPL/Object/Factory.pm Fri Mar 19 20:06:12 2010 +0300 @@ -70,14 +70,6 @@ =begin code -sub ProcessItems { - my ($factory,$items); - - return map $factory->new($_), @$items; -} - -my @users = ProcessItems('MyApp::User',$db->selectUsers); - my $factory = new IMPL::Object::Factory( 'MyApp::User', { @@ -85,13 +77,35 @@ } ); +my $class = 'MyApp::User'; + +my $user; + +$user = $class->new(name => 'nobody'); # will create object MyApp::User + # and pass parameters (name=>'nobody') + +$user = $factory->new(name => 'root'); # will create object MyApp::User + # and pass paremeters (isAdmin => 1, name => 'root') + =end code -my @admins = ProcessItems($factory,$db->selectAdmins); +Или сериализованная форма в XML. + +=begin code xml +<factory type="IMPL::Object::Factory"> + <factory>MyApp::User</factory>, + <parameters type="HASH"> + <isAdmin>1</isAdmin> + </parameters> +</factory> + +=end code xml =head1 DESCRIPTION +C<[Serializable]> + Класс, реализующий фабрику классов. Фабрика классов это любой объект, который имеет метод C< new > вызов которого приводит к созданию нового @@ -108,16 +122,56 @@ =over -=item C< factory > +=item C< CTOR($factory,$parameters) > + +Создает новый экземпляр + +=over + +=item C<$factory> + +Либо имя класса, либо другая фабрика. + +=item C<$parameters> + +Ссылка на параметры для создания объектов, может быть ссылкой на хеш, массив и т.д. + +Если является ссылкой на хеш, то при создании объектов данной фабрикой этот хеш +будет развернут в список и передан параметрами методу C<new>. + +Если является ссылкой на массив, то при создании объектов данной фабрикой этот массив +будет передан в списк и передан параметрами методу C<new>. + +Если является любым другим объектом или скаляром, то будет передан параметром методу +C<new> как есть. + +=back + +=item C< [get] factory > Свойство, содержащее фабрику для создание новых объектов текущей фабрикой. Чаще всего оно содержит имя класса. -=item C< parameters > +=item C< [get] parameters > Свойство, содержит ссылку на параметры для создания объектов, при создании объекта эти параметры будут развернуты в список и переданы оператору C< new > фабрике из свойства C< factory >, за ними будут -следовать параметры непосредственно текущей фабрики. +следовать параметры непосредственно текущей фабрики. + +=item C<new(@params)> + +Создает новый объект, используя свйство C<factory> как фабрику и передавая туда параметры +из свойства C<parameters> и списка C<@params>. Ниже приведен упрощенный пример, как это происходит. + +=begin code + +sub new { + my ($this,@params) = @_; + + return $this->factory->new(_as_list($this->parameters), @params); +} + +=end code =back
--- a/Lib/IMPL/Web/Application.pm Thu Mar 18 17:58:33 2010 +0300 +++ b/Lib/IMPL/Web/Application.pm Fri Mar 19 20:06:12 2010 +0300 @@ -14,7 +14,7 @@ BEGIN { public property handlerError => prop_all; - public property factoryAction => prop_all; + public property actionFactory => prop_all; public property handlersQuery => prop_all | prop_list; public property responseCharset => prop_all; public property options => prop_all; @@ -30,7 +30,7 @@ sub CTOR { my ($this) = @_; - $this->factoryAction('IMPL::Web::Application::Action') unless $this->factoryAction; + $this->actionFactory('IMPL::Web::Application::Action') unless $this->actionFactory; $this->responseCharset('utf-8') unless $this->responseCharset; } @@ -39,7 +39,7 @@ while (my $query = $this->FetchRequest()) { - my $action = $this->factoryAction->new( + my $action = $this->actionFactory->new( query => $query, application => $this, ); @@ -72,8 +72,15 @@ =head1 SYNOPSIS +=begin code + require MyApp; -MyApp->spawn('app.config')->Run(); + +my $instance = spawn MyApp('app.config'); + +$instance->Run(); + +=end code =head1 DESCRIPTION @@ -82,13 +89,94 @@ Процесс обработки запроса состоит из следующих частей -1. Получение cgi запроса -2. Вызов модуля для инициализации объекта действия -3. Инициализация контекста выполнения -4. Выполнение запроса -5. Преобразование полученных данных в тело ответа +=over + +=item 1 + +Получение cgi запроса + +=item 2 +Создание объекта C<IMPL::Web::Application::Action> +=item 3 +Формирование цепочки вызовов при помощи C<< IMPL::Web::Application::Action->ChainHandler >> + +=item 4 + +Выполнение запроса C<< IMPL::Web::Application::Action->Invoke >> =cut + +Также приложение поддерживает отложенное создание объектов, которые по первому обращению +к свойствам. Это реализовано в базовом классе C< IMPL::Configuration >. Для настройки +активаторов можно использовать свойство C<options>, в которое должен быть помещен хеш +со ссылками на активаторы, см. пример ниже C<CONFIGURATION>. + +=head2 CONFIGURATION + +Ниже приведен пример конфигурации приложения + +=begin code xml + +<?xml version="1.0" encoding="UTF-8"?> +<Application id='app' type="Test::Web::Application::Instance"> + + <!-- Begin custom properties --> + <name>Sample application</name> + <dataSource type='IMPL::Config::Activator' id='ds'> + <factory>IMPL::Object</factory> + <parameters type='HASH'> + <db>data</db> + <user>nobody</user> + </parameters> + </dataSource> + <securityMod type='IMPL::Config::Activator'> + <factory>IMPL::Object</factory> + <parameters type='HASH'> + <ds refid='ds'/> + </parameters> + </securityMod> + <!-- End custom properties --> + + <!-- direct access to the activators --> + <options type="HASH"> + <dataSource refid='ds'/> + </options> + + <!-- Set default output encoding, can be changed due query handling --> + <responseCharset>utf-8</responseCharset> + + <!-- Actions creation configuration --> + <actionFactory type="IMPL::Object::Factory"> + + <!-- Construct actions --> + <factory>IMPL::Web::Application::Action</factory> + <parameters type='HASH'> + + <!-- with special responseFactory --> + <responseFactory type='IMPL::Object::Factory'> + + <!-- Where resopnses have a special streamOut --> + <factory>IMPL::Web::Application::Response</factory> + <parameters type='HASH'> + + <!-- in memory dummy output instead of STDOUT --> + <streamOut>memory</streamOut> + + </parameters> + </responseFactory> + </parameters> + </actionFactory> + + <!-- Query processing chain --> + <handlersQuery type="IMPL::Object::List"> + <item type="IMPL::Web::QueryHandler::PageFormat"> + <templatesCharset>cp1251</templatesCharset> + </item> + </handlersQuery> +</Application> + +=end code xml +
--- a/Lib/IMPL/Web/Application/Action.pm Thu Mar 18 17:58:33 2010 +0300 +++ b/Lib/IMPL/Web/Application/Action.pm Fri Mar 19 20:06:12 2010 +0300 @@ -87,49 +87,159 @@ =pod +=head1 NAME + +C<IMPL::Web::Application::Action> - Обертка вокруг C<CGI> запроса. + =head1 DESCRIPTION -Определяет порядок выполнения запроса. +C<[Infrastructure]> -Запрос выполняется последовательным вызовом цепочки обработчиков, при этом обработчики -сами вызывают следующие. +Определяет порядок выполнения запроса. Запрос выполняется последовательным вызовом +цепочки обработчиков, при этом обработчики сами вызывают следующие. +Обработчики выполняются в порядке, обратном их добавлению. Типичная цепочка может быть такой, в порядке добавления -SecCallToMethod($target,$method) -AuthenticateMethod -TDocumentOut($file) +=begin code + +IMPL::Web::QueryHandler::SecCallToMethod +IMPL::Web::QueryHandler::AuthenticateCookie +IMPL::Web::QueryHandler::PageFormat + +=end code что приведет к следующей последовательности -Action->Invoke() { - TDocumentOut->Invoke($Action,$nextHandler) { - my $result = $nextHandler() { - $AuthenticateMethod($Action,$nextHandler) { - my $context = $Action->application->security->Authenticate($Action->query,$Action->response); - return $context->Impersonate($nextHandler) { - $objSecCallToMethod->Invoke($Action,undef) { +=begin code + +# the application creates a new Action object + +my $action = $application->actionFactory->new( + action => $application, # the application passes self + query => $query # current CGI query +); + +# forms query handlers stack + +$action->ChainHandler($_) foreach qw ( + IMPL::Web::QueryHandler::SecCallToMethod + IMPL::Web::QueryHandler::AuthenticateCookie + IMPL::Web::QueryHandler::PageFormat +); + +# and finally invokes the action + +$action->Invoke() { + + # some internals + + IMPL::Web::QueryHandler::PageFormat->Invoke($action,$nextHandlerIsAuthHandler) { + + #some internals + + my $result = $nextHandlerIsAuthHandler() { + + # some internals + + IMPL::Web::QueryHandler::AuthenticateCookie->Invoke($action,$nextHandlerIsSecCall) { + + # some internals + # do auth and generate security $context + + # impersonate $context and call the next handler + return $context->Impersonate($nextHandlerIsSecCall) { + + # some internals + + IMPL::Web::QueryHandler::SecCallToMethod->Invoke($action,undef) { + + # next handler isn't present as it is the last hanler + + # some internals + # calculate the $method and the $target from CGI request + IMPL::Security->AccessCheck($target,$method); return $target->$method(); + } + } + } } - $this->format($result,$Action->response->streamBody); + + # some intenals + # formatted output to $action->response->streamBody } } +=end code + или как альтернатива может быть еще -$objSecCallToMethod($target,$method) -$AuthenticateMethod -$TransfromToSimpleData -$JSONOut +=begin code + +IMPL::Web::QueryHandler::SecCallToMethod +IMPL::Web::QueryHandler::AuthenticateCookie +IMPL::Web::QueryHandler::Filter->new( target => IMPL::Transform::ObjectToJSON->new() , method => 'Transform') +IMLP::Web::QueryHandler::JSONFormat + + +=end code В данной цепочке также происходит вызов метода, но его результат потом преобразуется в простые структуры и передается JSON преобразователю. Таким образом модулю логики не требуется знать о выходном формате, всю работу проделают дополнительные фильтры. +=head1 MEMBERS + +=head2 PROPERTIES + +=over + +=item C< [get] application> + +Экземпляр приложения создавшего текущий объект + +=item C< [get] query > + +Экземпляр C<CGI> запроса + +=item C< [get] response > + +Ответ на C<CGI> заспрос C<IMPL::Web::Application::Response> + +=item C< [get] responseFactory > + +Фабрика ответов на запрос, используется для создания нового ответа +либо при конструировании текущего объекта C<IMPL::Web::Application::Action>, +либо при вызове метода C<ReinitResponse> у текущего объекта. + +По умолчанию имеет значение C<IMPL::Web::Application::Response> + +=back + +=head2 METHODS + +=over + +=item C< ReinitResponse() > + +Отмена старого ответа C<response> и создание вместо него нового. + +Данная операция обычно проводится при обработке ошибок, когда +уже сформированный ответ требуется отменить. Следует заметить, +что эта операция не возможна, если ответ частично или полностью +отправлен клиенту. Тогда возникает исключение C<IMPL::InvalidOperationException>. + +=item C< ChainHandler($handler) > + +Добавляет новый обработчик в цепочку. Выполнение цепочки начинается с конца, +тоесть последний добавленный будет выполнен первым. + +=back + =head1 HANDLERS =head2 subroutines @@ -151,9 +261,9 @@ =back -=head2 C< IMPL::Web::Application::QueryHandler > +=head2 C< IMPL::Web::QueryHandler > -Любой объект наследованный от C< IMPL::Web::Application::QueryHandler > может быть +Любой объект наследованный от C< IMPL::Web::QueryHandler > может быть использован в качестве обработчика запроса =cut \ No newline at end of file
--- a/Lib/IMPL/Web/Application/Response.pm Thu Mar 18 17:58:33 2010 +0300 +++ b/Lib/IMPL/Web/Application/Response.pm Fri Mar 19 20:06:12 2010 +0300 @@ -14,6 +14,7 @@ #todo: add binary method to set a binary encoding, set it automatic when type isn't a text BEGIN { + # автозаполнение буде происходить в порядке объявления public property query => prop_get | owner_set; # cgi query public property status => prop_all, { validator => \&_checkHeaderPrinted }; public property contentType => prop_all, { validator => \&_checkHeaderPrinted }; # String @@ -32,11 +33,19 @@ __PACKAGE__->PassThroughArgs; +our %CTOR = ( + 'IMPL::Object::Autofill' => sub { + my %args = @_; + + $args{query} = CGI->new($args{query} || {}); + + %args; + } +); + sub CTOR { my ($this,%args) = @_; - $this->query(CGI->new($this->query() | {})) unless $this->query; - if (lc $this->streamOut eq 'memory') { my $dummy = ''; open my $hout, '>:encoding(utf8)', \$dummy or die new IMPL::Exception("Failed to create memory stream",$!); @@ -165,15 +174,23 @@ =pod +=head1 NAME + +C<IMPL::Web::Application::Response> - Ответ веб сервера непосредственно клиенту. + =head1 DESCRIPTION -Ответ сервера на CGI запрос, позволяет сформировать основные свойства заголовка и тело запроса. +C<[Infrastructure]> + +Позволяет сформировать основные свойства заголовка и тело ответа. + +Создается объектом C<IMPL::Web::Application::Action> в процессе обработки запроса. + +Может использоваться обработчиками C<IMPL::Web::QueryHandler> в процессе выполнения запроса. Объект позволяет буфферизировать вывод в тело ответа, что позволяет отменить или изменить -ответ в последний момент. - -Свойство C< isHeaderPrinted > можно использовать для определения были ли отправлены какие-нибудь -данные клиенту. +ответ в последний момент. Свойство C< isHeaderPrinted > используется для определения факта +отправлки данных клиенту. =head1 PROPERTIES @@ -184,27 +201,27 @@ =over -=item C< query > +=item C< [get] query > CGI запрос, который используется для вывода данных, заголовка и пр. Существует всегда. -=item C< status > +=item C< [get,set] status > Код ошибки HTTP. Например, '200 OK'. По умолчанию не установлен, при отправке клиенту бедт отправлен '200 ОК'. -=item C< contentType > +=item C< [get,set] contentType > Тип MIME. По умолчанию не установлен, подразумивается 'text/html'. -=item C< charset > +=item C< [get,set] charset > Кодировка, синоним свойства query->charset. -=item C< expires > +=item C< [get,set] expires > Определяет время жизни контента, например '+10m'. По умолчанию не задано и не передается. -=item C< cookies > +=item C< [get,set] cookies > Хеш массив с cookies, например C< { cart => ['foo','bar'], display => 'list' } >. @@ -216,7 +233,7 @@ =over -=item C< buffered > +=item C< [get,set] buffered > C< True > - то тело ответа пишется в буффер и будет отправлено при вызове метода C< Complete >, заголовок также будет отправлен после вызова метода C< Complete >. @@ -226,15 +243,15 @@ Это свойство можно менять до первого обращения к потоку для записи в тело ответа. -=item C< streamOut > +=item C< [get] streamOut > Стандартный вывод CGI приложения. -=item C< streamBody > +=item C< [get] streamBody > Поток для записи в тело ответа. -=item C< isHeadPrinted > +=item C< [get] isHeadPrinted > Признак того, что заголовок уже был отправлен клиенту. @@ -255,4 +272,9 @@ =back +=head1 REMARKS + +Данный объект является автозаполняемым, т.е. все его свойства можно задать через +именованные параметры конструктора. + =cut \ No newline at end of file
--- a/_test/Resources/app.xml Thu Mar 18 17:58:33 2010 +0300 +++ b/_test/Resources/app.xml Fri Mar 19 20:06:12 2010 +0300 @@ -27,7 +27,7 @@ <responseCharset>utf-8</responseCharset> <!-- Actions creation configuration --> - <factoryAction type="IMPL::Object::Factory"> + <actionFactory type="IMPL::Object::Factory"> <factory>IMPL::Web::Application::Action</factory> <parameters type='HASH'> <responseFactory type='IMPL::Object::Factory'> @@ -37,7 +37,7 @@ </parameters> </responseFactory> </parameters> - </factoryAction> + </actionFactory> <!-- Query processing --> <handlersQuery type="IMPL::Object::List">