By: Eden Cardim- 2/6/2011
Em: Server side, Frameworks & IDEs - Comentários: 1 - Leituras: 2049
Um dos motivos pelo qual o Catalyst e o DBIx::Class são mais recomendáveis do que as alternativas disponíveis no CPAN é que eles possuem uma arquitetura orgânica, e por isso, são muito mais maduros como plataforma. Volta e meia, vejo pedidos de acréscimo de features nas listas de discussão, e percebo, depois de um pouco de reflexão, que a feature já foi implementada “sem querer”, e plugins são um bom caso para se ilustrar esse tipo de coisa.
Recentemente, o Geovanny Junior, da http://eutsiv.com.br, perguntou na lista de discussão do São Paulo Perl Mongers, como que faz para acrescentar plugins na aplicação Catalyst/DBIx::Class dele, inclusive plugins para o schema de banco de dados. No caso dele, ele queria uma estrutura de classes da seguinte forma:
A resposta é que, tanto o Catalyst quanto o DBIx::Class, apesar de não terem sido projetados tendo plugins em mente, podem implementar esse tipo de coisa muito facilmente, combinando as features do Catalyst/DBIx::Class com o Moose.
Com o DBIx::Class, para carregar as tabelas adicionais vindas dos Plugins, basta invocar o método load_namespaces novamente, passando o namespace que se deseja carregar:
MyApp::Schema->load_namespaces() # carregar as tabelas padrão MyApp::Schema->load_namespaces( result_namespace => ' MyApp::Plugin::Result', resultset_namespace => ' MyApp::Plugin::ResultSet' ); # carregar tabelas "plugadas"
Carregando os plugins, você obtem o schema core com as tabelas adicionais. Pro DBIx::Class não faz diferença alguma, então é só trabalhar com o banco de dados normalmente. Para implantar o banco “aditivado”, é só invocar o método deploy num banco de dados conectado:
MyApp::Schema->connect(etc...)->deploy; # implantar o schema no banco
Acho má idéia criar plugins que modifiquem tabelas da plataforma padrão no banco, mais na frente vai virar um inferno pra manter. Tem muita chance de colidirem nomes de tabelas, campos, índices, etc. O ideal prum sistema plugável é que o núcleo do sistema fique isolado dos plugins, e que as modificações nos plugins tenham o mínimo de intrusão possível, para não propagar erros e incompatibilidade para outros plugins. Na minha opinião, o menos intrusivo nesse caso, para se alterar o schema do banco de dados, seria a criação de tabelas separadas e a utilização de relacionamentos.
Acontece que é bastante simples implementar esse tipo de coisa, só é necessário o acréscimo mais classes result e tratá-las como se fossem classes-tabela normais, mas sempre se preocupando em interferir o mínimo possível com a lógica do core da aplicação.
O Catalyst usa o Module::Pluggable para carregar seus componentes. No caso de plugins que não envolvam o banco, pode-se passar configurações adicionais pro Module::Pluggable através da opção setup_components.
MyApp->config(
setup_components => {
search_path => [qw(MyApp MyApp::Plugin)],
except => [qw(MyApp::Plugin::Schema)]
}
);
Observa o uso do “except” para não carregar os plugins do schema, que já estão sendo carregados pelo MyApp::Schema.
Em seguida, para ilustrar, criamos as classes:
package MyApp::Schema::Result::User;
use warnings;
use strict;
use base 'DBIx::Class'; __PACKAGE__->load_components(qw(Core));
__PACKAGE__->table("user");
__PACKAGE__->add_columns(qw(id name age added));
Essa é uma tabela “core” do sistema, bem simples, como prova de conceito.
Agora, um controller que também faz parte do “core” do aplicação.
# controller core da aplicação
package MyApp::Controller::Root;
use Moose;
sub base :Chained('/') PathPart('') Args(0) {
my($self, $c) = @_;
$c->stash->{user} = $c->model->first;
}
Bem simples também, ele apenas pega o primeiro registro do model default, que pode ser configurado para ser uma das tabelas do banco.
Em seguida, criamos uma tabela como “plugin” (que é uma tabela normal, mas em outro namespace):
# plugin para usuários estado-unidenses
package MyApp::Plugin::Schema::Result::User::EUA;
use warnings;
use strict;
use base 'DBIx::Class';
__PACKAGE__->load_components(qw(Core));
__PACKAGE__->table("user_eua");
__PACKAGE__->add_columns(qw(user_id zip_code));
__PACKAGE__->belongs_to(
user => User => {'foreign.id' => 'self.user_id'},
{ proxy => [qw/name age added/] }
);
sub country {q{EUA}}
E mais uma tabela plugin, para usuários brasileiros.
# plugin para usuários brasileiros
package MyApp::Plugin::Schema::Result::User::Brasil;
use warnings;
use strict;
use base 'DBIx::Class';
__PACKAGE__->load_components(qw(Core));
__PACKAGE__->table("user_brasil");
__PACKAGE__->add_columns(qw(user_id CEP));
__PACKAGE__->belongs_to(
user => User => {'foreign.id' => 'self.user_id'}, { proxy => [qw/name age added/] }
);
sub country {q{Brasil}}
Em seguida, um plugin para acrescentar a internacionalização no controller.
# plugin convencional de aplicação # em lib/MyApp/Plugin/Controller/International.pm
package MyApp::Plugin::Controller::International;
use Moose;
package MyApp::Controller::Root;
use Moose;
__PACKAGE__->meta->make_mutable;
before base => sub {
my($self, $c) = @_;
my $country = $c->req->header('X-Geolocation') || 'Brasil'; # ou seja lá qual for o mecanismo de detecção de localidade
$c->stash->{current_model_instance} = $c->model('DB::User::' . $country);
$c->stash->{template} = $country . '.tt' };
__PACKAGE__->meta->make_immutable;
O código acima vai todo no mesmo arquivo, primeiro declaramos o pacote do plugin, só para agradar o framework, já que todos oscomponentes precisam definir seus próprios pacotes. Em seguida alteramos o escopo para o componente que desejamos extender através do plugin.
Por padrão, os componentes do Catalyst são classes Moose imutáveis. A imutabilidade significa que essa classe não vai mais ser alterada através do protocolo de meta-objetos. Isso permite algumas otimizações no backend. Para acrescentar um modificador de método, precisamos desativar a imutabilidade temporariamente, isso se faz através do método make_mutable na meta-classe. Depois acrescentamos o modificador de método, que é o que vai injetar o comportamento extensivo do plugin. Nesse caso, ele vai fazer com que o método $c->model retorne um resultset do tipo EUA ou Brasil e renderize o template correto, a depender da localização.
Agora precisamos dos templates que saibam usar os dados específicos das classes do plugin.
# Brasil.tt Olá, o primeiro usuário brasileiro registrado é [% user.name %], portador do CEP [% user.CEP %]
# EUA.tt Hello, the first registered american user is [% user.name %], his zip code is [% user.zip_code %]
Os plugins podem ser configurados feitos através dos arquivos de configuração do catalyst normalmente, como se fossem componentes do core da aplicação. Tanto o Catalyst e o DBIx::Class já são implementados de forma orgânica e compartimentalizada, e apesar de serem projetos separados, a organicidade da arquitetura permite esse tipo de flexibilidade, com mínimo de esforço e sem impactar no desempenho.
By: Eduardo Almeida- 1/6/2011
Em: Client side, Frameworks & IDEs - Comentários: 0 - Leituras: 908
< scri pt type="text/javascript" src="codebase/dhtmlxcommon.js" >< /script >
< sc ript type="text/javascript" >// < ![ CDATA[
var postStr="parametro1=valor1¶metro2=valor2";
dhtmlxAjax.post("receberequisicao.asp", encodeURI(postStr), outputResponse);
function outputResponse(loader)
{
if(loader.xmlDoc.responseText=="sucesso")
{
alert("sucesso");
}
else
{
alert(loader.xmlDoc.responseText);
}
};
// ]] >< /sc ript >
###### receberequisicao.asp
Form("parametro1")->item();
my $parametro1=$Request->Form("parametro2")->item();
## rotina que efetua os procedimentos e retorna sucesso ou erro
print "sucesso";
%>
Desde de 1998 ...
a WEB2 vêm desenvolvendo sites, softwares, implementando ambientes servidores,
prestando consultoria na área de segurança para diversas empresas
como bancos, imobiliárias, agências, cartórios, escritórios de advocacia e até
empresas multi-nacionais. Trabalhamos para criar
experiências intuitivas para os usuários, desenhar interfaces ricas e
elegantes, desenvolver aplicativos úteis, consolidar sites e produtos
que ajudamos a criar, seja desenvolvendo, analisando ou melhorando sua performance. Resumindo, construímos "business" para internet.
Copyright © 2012 WEB2 Soluções LTDA. CNPJ: 14.832.733/0001-05.