[SP-pm] Catalyst: Começando...
Daniel de Oliveira Mantovani
daniel.oliveira.mantovani at gmail.com
Tue Feb 3 18:17:40 PST 2009
Estou esperando o resto!
Ficou muito bom, obrigado de novo!
[]s
2009/2/3 Blabos de Blebe <blabos em gmail.com>
> Muito bom. Gostei das explicações nos comentários. Vai ter
> continuação? Espero que sim.
>
> Parabéns
>
> 2009/2/3 Daniel de Oliveira Mantovani <daniel.oliveira.mantovani em gmail.com
> >:
> >
> > Valeu Thiago!
> > 2009/2/3 Nelson Ferraz <nferraz em gmail.com>
> >>
> >> Parece muito bom, Thiago! Obrigado pela contribuição!
> >>
> >> Por que não formata o documento em pod, e copia para o wiki? Aqui vai um
> >> começo:
> >>
> >> =head1 NOME
> >>
> >> Catalyst - O Elegante framework de programação Web em Perl.
> >>
> >> =head1 DESCRICAO
> >>
> >> Catalyst é um framework elegante de programação MVC para Web em Perl
> >> (ambos gratuitos e de código aberto). Este tutorial
> >> simples e talvez muito objetivo tem como missão facilitar o
> >> entedimento para os novos nesta ferramenta de forma pratica, não
> >> se prendendo muito a conceitos, motivos e paradigmas.
> >>
> >> =head1 INICIO
> >>
> >> =head2 Instalação do Catalyst.
> >>
> >> O Perl tem o CPAN, no qual é um repositorio farto de modulos e
> >> documentação, você pode utilizar o site http://search.cpan.org/ para
> >> navegar por ele, e toda distribuição do Perl vem com um aplicativo
> >> chamado "cpan" para você poder instalar os modulos atravez da
> >> linha de comando.
> >>
> >> $ export PERL_MM_USE_DEFAULT=1
> >> $ cpan -i Task::Catalyst
> >>
> >> O Catalyst tem algumas dependencias, e por isto, além do pacote do
> >> Catalyst o "cpan" irá automaticamente instalar as suas dependencias,
> >> perceba que estamos utilizando o pacote Task::Catalyst, no qual contém
> >> uma serie de pacotes recomendadas para a utilização do Catalyst.
> >>
> >> DICA: Sete a variavel de ambiente PERL_MM_USE_DEFAULT=1 para o cpan
> >> não lhe questionar sobre as dependencias e demais perguntas, e
> >> instalar elas sem lhe perguntar.
> >>
> >> Pronto, a instalação esta concluida, agora estamos com o sistema apto
> >> para programar utilizando o framework de programação Catalyst.
> >>
> >> =head2 Iniciando o meu primeiro projeto.
> >>
> >> No pacote do Catalyst, vem acompanhando um aplicativo que facilita a
> >> nossa vida para montar o ambiente básico para iniciarmos o nosso
> >> projeto, chamado de "catalyst.pl", para isto basta executar ele com o
> >> primeiro argumento sendo o nome do projeto.
> >>
> >> $ catalyst.pl webapp
> >> created "webapp"
> >> created "webapp/script"
> >> created "webapp/lib"
> >> created "webapp/root"
> >> created "webapp/root/static"
> >> created "webapp/root/static/images"
> >> created "webapp/t"
> >> created "webapp/lib/webapp"
> >> created "webapp/lib/webapp/Model"
> >> created "webapp/lib/webapp/View"
> >> created "webapp/lib/webapp/Controller"
> >> created "webapp/webapp.conf"
> >> created "webapp/lib/webapp.pm"
> >> created "webapp/lib/webapp/Controller/Root.pm"
> >> created "webapp/README"
> >> created "webapp/Changes"
> >> created "webapp/t/01app.t"
> >> created "webapp/t/02pod.t"
> >> created "webapp/t/03podcoverage.t"
> >> created "webapp/root/static/images/catalyst_logo.png"
> >> created "webapp/root/static/images/btn_120x50_built.png"
> >> created "webapp/root/static/images/btn_120x50_built_shadow.png"
> >> created "webapp/root/static/images/btn_120x50_powered.png"
> >> created "webapp/root/static/images/btn_120x50_powered_shadow.png"
> >> created "webapp/root/static/images/btn_88x31_built.png"
> >> created "webapp/root/static/images/btn_88x31_built_shadow.png"
> >> created "webapp/root/static/images/btn_88x31_powered.png"
> >> created "webapp/root/static/images/btn_88x31_powered_shadow.png"
> >> created "webapp/root/favicon.ico"
> >> created "webapp/Makefile.PL"
> >> created "webapp/script/webapp_cgi.pl"
> >> created "webapp/script/webapp_fastcgi.pl"
> >> created "webapp/script/webapp_server.pl"
> >> created "webapp/script/webapp_test.pl"
> >> created "webapp/script/webapp_create.pl"
> >>
> >> Pronto, agora estamos com nosso ambiente básico para começar a
> >> programar, vou explicar de forma rápida a estrutura
> >> de diretorios criada para você entender melhor:
> >>
> >> $ ls webapp/
> >> Changes lib/ Makefile.PL README root/ script/ t/ webapp.conf
> >>
> >> Veja, que temos quatro diretorios, que são eles:
> >>
> >> =over
> >>
> >> =item lib/
> >>
> >> Contém a parte da programação lógica, onde iremos escrever nossos
> >> modulos e códigos em Perl.
> >>
> >> =item root/
> >>
> >> Neste diretorio iremos colocar arquivos estáticos, como templates,
> >> javascript e css.
> >>
> >> =item script/
> >>
> >> Scripts para inicializar a nossa aplicação.
> >>
> >> =item t/
> >>
> >> Testes para nossa aplicação.
> >>
> >> =back
> >>
> >> Vamos falar um pouco do diretorio "script/", nele você tem um script
> >> que usaremos muito neste tutorial, webapp_server.pl, no
> >> qual irá iniciar um servidor http na porta 3000 por padrão, para
> >> visualizarmos o nosso aplicativo:
> >>
> >> $ script/webapp_server.pl
> >>
> >> Depois de executar ele, você já pode acessar o aplicativo pelo seu
> >> browser favorito, pelo endereço:
> >>
> >> L<http://localhost:3000>
> >>
> >> =head2 Entendendo um MVC (Model-View-Controller)
> >>
> >> MVC é um padrão de arquitetura de software, uma das maiores
> >> dificuldades do entendimento de um framework de programação
> >> web como o Catalyst para os iniciantes é justamente este conceito.
> >>
> >> Basicamente o significado deles é:
> >>
> >> =over
> >>
> >> =item Model:
> >>
> >> São as informações utilizadas pelo aplicativo, no qual este modelo
> >> pode ser um banco de dados, um arquivo texto e etc.
> >>
> >> =item Controller:
> >>
> >> Lógica do nosso aplicativo, onde podemos por exemplo alterar as
> >> informações (Model), filtrar e etc.
> >>
> >> =item View:
> >>
> >> Renderizar o Model e o Controller para o usuário, ou seja como o
> >> aplicativo será apresentado.
> >>
> >> =back
> >>
> >> Esta é uma forma rápida de apresentar os três componentes do MVC,
> >> sabendo disto, vamos começar a produzir nosso aplicativo.
> >>
> >> =head2 Nosso projeto: Agenda telefonica
> >>
> >> Vamos começar a estudar o nosso aplicativo, ele irá gerenciar uma
> >> lista de telefones, no qual iremos efetuar um simples "CRUD"
> >> (Create-Remove-Update-Destroy), no qual iremos permitir efetuar a
> >> criação, remover, atualizar e apagar dados de nossa lista.
> >>
> >> Vamos projetar nossa agenda telefonica, utilizando o MVC da seguinte da
> >> forma:
> >>
> >> =over
> >>
> >> =item Model:
> >>
> >> Iremos utilizar o MySQL, porém para efetuar a conectividade com o
> >> banco de dados, iremos utilizar um driver do DBI, no
> >> qual o MySQL e tantos outros ele suporta, e é interessante além de
> >> utilizar o driver de comunicação com o banco de dados, algum
> >> ORM (http://en.wikipedia.org/wiki/Object-relational_mapping) para
> >> facilitar a interface com o DB, existem alguns disponiveis como
> >> por exemplo o Class::DBI ou DBIx::Class para evitar que você escreva
> >> SQL no teu código, evitar alguns bugs e trazer agilidade no
> >> desenvolvimento, no nosso caso iremos utilizar o DBIx::Class.
> >>
> >> =item View:
> >>
> >> Iremos utilizar o HTML como formato de apresentação para nossos
> >> usuarios, portanto teremos que carregar o modulo que
> >> cuidará de manipular os dados que iremos jogar em nosso arquivo de
> >> template, existem alguns modulos disponiveis como o
> >> HTML::Manson ou Template::Toolkit), iremos utilizar neste caso o
> >> Template::Toolkit.
> >>
> >> =item Controller:
> >>
> >> Aqui é o lugar onde iremos programar, captar os dados no Model e
> >> "espirrar" para a View, entre outras.
> >>
> >> =back
> >>
> >> =head2 Começando pelo Model.
> >>
> >> Bem, já dissemos que iremos utilizar o MySQL como banco de dados, e
> >> também já explicamos por que iremos utilizar o DBIx::Class.
> >>
> >> Precisamos instalar ele:
> >>
> >> $ cpan -i DBIx::Class
> >>
> >> Certo, agora temos tudo o que precisamos para trabalhar com o nosso
> >> Model. Neste tutorial eu vou utilizar o exemplo de criar a
> >> tabela direto pelo client do MySQL, e depois ler elas pelo DBIx::Class.
> >>
> >> mysql> create database webapp
> >> mysql> grant all on webapp.* to webapp em localhost identified by
> >> 'webapp';
> >> mysql> flush privileges;
> >> mysql> create table telefones (
> >> id int not null auto_increment,
> >> nome varchar(255),
> >> telefone varchar(255),
> >> primary key(id));
> >>
> >> Criado a nosso database e nossa tabela, agora vamos para "importar"
> >> nosso banco de dados para o DBIx::Class, eu não irei me
> >> aprofundar no DBIx::Class neste tutorial, pois não é o objetivo dele.
> >>
> >> Para importarmos este database para os schemas que o DBIx::Class
> >> utiliza, iremos executar um dos scripts facilitadores do diretorio
> >> scripts/ que se chama "webapp_create.pl" no qual facilita algumas
> >> tarefas como esta, a sintaxe utilizada é auto-explicativa, é
> >> basicamente:
> >>
> >> # script/webapp_create.pl model DB DBIC::Schema webapp::Schema
> >> create=static dbi:mysql:dbname=webapp webapp webapp
> >> exists "/home/thiago/webapp/script/../lib/webapp/Model"
> >> exists "/home/thiago/webapp/script/../t"
> >> Dumping manual schema for webapp::Schema to directory
> >> /home/thiago/webapp/script/../lib ...
> >> Schema dump completed.
> >> created "/home/thiago/webapp/script/../lib/webapp/Model/DB.pm"
> >> created "/home/thiago/webapp/script/../t/model_DB.t"
> >>
> >> Vejamos os argumentos deste script:
> >>
> >> =over
> >>
> >> =item model
> >>
> >> Estamos criando um model para o script webapp_create.pl
> >>
> >> =item DB
> >>
> >> O nome criado para este modem será DB (vide lib/webapp/Model/DB.pm)
> >>
> >> =item DBIC::Schema
> >>
> >> Nome do helper para criar o Schema para o DBIx::Class
> >>
> >> =item create=static
> >>
> >> Significa que o schema será estatico, ou seja, a toda alteração nas
> >> tabelas, você precisa atualizar nos arquivos criados para o schema.
> >>
> >> =item dbname
> >>
> >> Nome do database no MySQL.
> >>
> >> =item webapp
> >>
> >> Usuario para se conectar no banco.
> >>
> >> =item webapp
> >>
> >> Senha para se conectar no banco.
> >>
> >> =back
> >>
> >> Agora, de uma lida nos arquivos criados em lib/webapp/Schema/* e
> >> lib/webapp/Model/*
> >>
> >> Pronto, já temos o nosso Model pronto para o nosso aplicativo.
> >>
> >> =head2 View - Template Toolkit.
> >>
> >> Iremos utilizar neste exemplo a Template::Toolkit, iremos utilizar um
> >> helper da mesma maneira que
> >> usamos para o banco de dados:
> >>
> >> # script/webapp_create.pl view TT TT
> >> exists "/home/thiago/webapp/script/../lib/webapp/View"
> >> exists "/home/thiago/webapp/script/../t"
> >> created "/home/thiago/webapp/script/../lib/webapp/View/TT.pm"
> >> created "/home/thiago/webapp/script/../t/view_TT.t"
> >>
> >> Pronto, o helper já criou os arquivos necessarios para utilizarmos a
> >> Template Toolkit em nosso projeto.
> >>
> >> =head2 Controller - Agora sim, programando!
> >>
> >> Estamos na melhor parte, é onde tudo acontece, iremos criar 4 actions,
> >> para criar, remover, listar e editar.
> >>
> >> Eu irei colocar o código que utilizei, e com ele comentado explicando
> >> passo-a-passo do que estou
> >> fazendo nele. Não irei utilizar nenhum helper ou facilitador nesta
> >> parte, pois acredito que a melhor maneira
> >> de se desenvolver o Controller é na 'unha'.
> >>
> >> Iremos criar um arquivo lib/webapp/Controller/telefone.pm, no qual ele
> >> irá representar na URI "/telefone".
> >>
> >> Caso queira baixar todos os arquivos, clique aqui.
> >>
> >> package webapp::Controller::telefone;
> >>
> >> use strict;
> >> use warnings;
> >> use parent 'Catalyst::Controller';
> >>
> >> # Nos estamos utilizando um mecanismo muito interessante neste
> >> # exemplo, que recomendo a utilizacao, o Chained.
> >> # Não iremos entrar discutir sobre ele, porem ele ajuda
> >> # manusearmos os argumentos passados pela URI.
> >> # Por tanto, vamos criar uma rotina "base" no qual todas as
> >> # requisições passaram por ela (Chained()).
> >> #
> >>
> search.cpan.org/dist/Catalyst-Runtime/lib/Catalyst/DispatchType/Chained.pm
> >>
> >> sub base :Chained('/') CaptureArgs(0) PathPart('telefone') {
> >> my ($self, $c) = @_;
> >>
> >> # stash é o local onde iremos colocar informações para
> compartilhar
> >> # com outras partes do nosso aplicativo, para cada requisição o
> >> stash
> >> # tem uma vida.
> >> # No caso, abaixo estamos atribuindo ao "collection" no stash o
> >> nosso
> >> # model "DB::telefones", que corresponde a nossa tabela telefones
> >> que
> >> # criamos no MySQL.
> >>
> >> $c->stash->{collection} = $c->model('DB::telefones');
> >> }
> >>
> >>
> >> # Veja, aqui estamos criando uma URI list/, no qual ela esta
> >> vinculada a nossa
> >> # função base, criada anteriormente (Chained('base')),
> >> #
> >> # Ou seja, para chamar a URL, http://localhost:3000/telefone/list,
> >> primeiramente
> >> # ele vai passar na base e depois na list. (* E por último, neste
> >> nosso exemplo
> >> # na action end do Root.pm, no qual nem iremos comentar neste
> >> tutorial).
> >> #
> >> # Veja que estamos dizendo Args(0), isto significa que não preciso de
> >> nenhum
> >> # elemento extra na minha URI, sempre que esta action for
> requisitada,
> >> será
> >> # /telefone/list
> >>
> >> sub list :Chained('base') Args(0) {
> >> my ($self, $c) = @_;
> >>
> >> # "req" ou "request" são as informações que estão no request da
> >> # requisição, e no qual temos o metodo param que retorna o valor
> >> # do atributo que gostariamos.
> >> my $key = $c->req->param('key') || "";
> >>
> >> # Aham, aqui estamos utilizando o DBIx:Class, repare que não
> iremos
> >> # escrever nenhum um código de SQL aqui, veja abaixo que iremos
> >> # utilizar uma função search_like(), no qual iremos procurar pelo
> >> # elemento $key nos dois campos (nome, telefone), estou usando o
> >> # $key, caso o usuario queira procurar por alguma palavra chave.
> >> my $items = $c->stash->{collection}->search_like({
> >> nome => "\%$key\%",
> >> telefone => "\%$key\%"
> >> });
> >>
> >> # Aqui estou colocando no stash o key, para mostrar na View por
> >> qual
> >> # palavra o usuario esta procurando, e o items encontrados.
> >> $c->stash->{key} = $key;
> >> $c->stash->{items} = $items;
> >> }
> >>
> >> # Esta função é para remover uma determinada coluna do nosso banco de
> >> dados,
> >> # repare que aqui estamos utilizando Args(1), ou seja estou esperando
> >> um
> >> # elemento na minha URI, além de /telefones/destroy, eu só irei
> acessar
> >> esta
> >> # URI, se acessar por /telefones/destroy/N, onde N é o ID do nosso
> >> item.
> >> # Veja que no código da função, estaremos novamente usando uma
> >> função do DBIx:Class,
> >> # primeiramente irei procurar por este elemento com find() e então
> >> irei remover
> >> # ele.
> >>
> >> sub destroy :Chained('base') :Args(1) {
> >> my ($self, $c, $id) = @_;
> >> my $row = $c->stash->{collection}->find({ id => $id });
> >> $row->delete if $row;
> >> }
> >>
> >> # Aqui, iremos editar o nosso item, onde também esperamos um
> >> argumento, que é o id
> >> # do item, e iremos procurar ele.
> >> # Repare que aqui, eu faço uma verificação, onde quero saber se o
> >> metodo utilizado
> >> # para chamar esta requisição é POST, caso não seja eu vou
> >> "encarrar" (detach())
> >> # esta função e vou passar para a próxima função da cadeia. (end()
> >> no Root.pm, neste
> >> # caso).
> >> # Resumindo, se o usuário não apertou "ALTERAR" no html (no qual o
> >> form esta enviando
> >> # os dados via POST), eu irei mostrar a página com os dados do
> >> objeto N ($id).
> >>
> >> sub edit :Chained('base') :Args(1) {
> >> my ($self, $c, $id) = @_;
> >>
> >> my $row = $c->stash->{row} = $c->stash->{collection}->find({id =>
> >> $id});
> >> $c->stash->{template} = "telefone/create.tt";
> >>
> >> $c->detach() unless $c->req->method eq 'POST';
> >>
> >> # Caso o usuario, tenha apertado o submit do nosso form, para
> >> alterar os dados,
> >> # eu vou colocar eles em $parameters = {}, e vou mandar o $row
> >> (que é o objeto
> >> # do find()) para o metodo update().
> >>
> >> my $parameters;
> >> $parameters->{nome} = $c->req->param('nome');
> >> $parameters->{telefone} = $c->req->param('telefone');
> >>
> >> $row->update($parameters);
> >>
> >> # Agora, nao vou mandar ele para a mesma tela, vou enviar para
> >> uma template diferente.
> >> $c->stash->{template} = "telefone/edit_ok.tt";
> >> }
> >>
> >> # Esta rotina é bem parecida com a do edit, com a unica diferença,
> >> que ao invez de atualizar
> >> # eu vou inserir.
> >>
> >> sub create :Chained('base') :Args(0) {
> >> my ($self, $c) = @_;
> >> $c->detach() unless $c->req->method eq 'POST';
> >>
> >> my $parameters;
> >> $parameters->{nome} = $c->req->param('nome');
> >> $parameters->{telefone} = $c->req->param('telefone');
> >>
> >> my $row = $c->stash->{collection}->new($parameters);
> >> $row->insert;
> >>
> >> $c->stash->{template} = "telefone/create_ok.tt";
> >> }
> >>
> >> # Caso, eu não especifique nada na URI de telefones, ou seja, acessar
> >> # http://localhost:3000/telefone eu irei redirecionar para a action
> >> list,
> >> # que já comentamos sobre ela.
> >> sub index :Path :Args(0) {
> >> my ($self, $c) = @_;
> >>
> >> $c->res->redirect(
> >> $c->uri_for(
> >> $c->controller->action_for('list')
> >> )
> >> );
> >> }
> >>
> >> 1;
> >>
> >>
> >> Código pronto, porem precisamos das templates.
> >>
> >> Agora, crie estes arquivos no diretorio root/telefone:
> >>
> >> Este arquivo, é para a action "create", no qual é o nosso formulario
> >> para criar um item na nossa agenda.
> >>
> >> =head3 create.tt
> >>
> >> <h1>Criar</h1>
> >>
> >> <form method="POST">
> >>
> >> <table><tr><td>
> >> Nome:
> >> </td><td> <input type="text" name="nome" value="[% row.nome %]"
> >> size=20>
> >> </td></tr><tr><td>
> >> Telefone:
> >> </td><td> <input type="text" name="telefone" value="[%
> >> row.telefone %]" size=20>
> >> </td></tr><tr><td colspan="2">
> >> <center><input type="submit"></center>
> >> </td></tr></table>
> >>
> >> </form>
> >>
> >> Este arquivo é a mensagem depois da criação do item.
> >>
> >> =head3 create_ok.tt
> >>
> >> <h1>Telefone inserido com sucesso!</h1>
> >>
> >> Mensagem para o item apagado.
> >> =head3 destroy.tt
> >>
> >> <h1>Telefone apagado</h1>
> >>
> >> Mensagem para item editado.
> >>
> >> =head3 edit_ok.tt
> >>
> >> <h1>Editado com sucesso.</h1>
> >>
> >> Listar itens da nossa agenda, e também dar ao usuário a opção de
> procurar
> >> neles.
> >>
> >> =head3 list.tt
> >>
> >> <h1>Listar</h1>
> >>
> >> <form>
> >> Procurar por:
> >> <input type="text" name="key" size="15">
> >> <input type="submit" value=" Procurar " >
> >> </form>
> >>
> >> [% IF key %]
> >> <br/>
> >> <b>Procurando por [% key %]</b>
> >> <br/>
> >> [% END %]
> >>
> >> <table><tr><td>
> >> <b>Nome</b>
> >> </td><td>
> >> <b>Telefone</td>
> >> </td><td>
> >> <b>Ação
> >> </td></tr>
> >>
> >> [% WHILE (item = items.next) %]
> >> <tr><td>
> >> [% item.nome %]
> >> </td><td>
> >> [% item.telefone %]
> >> </td><td>
> >> <a href="[% c.uri_for('edit', item.id) %]">Editar</a>
> >> -
> >> <a href="[% c.uri_for('destroy', item.id) %]">Remover</a>
> >> </td></tr>
> >> [% END %]
> >>
> >> </table>
> >>
> >> =head1 AUTOR
> >>
> >> Thiago Rondon <thiago em aware.com.br>
> >>
> >> =head1 COLABORADORES
> >> _______________________________________________
> >> SaoPaulo-pm mailing list
> >> SaoPaulo-pm em pm.org
> >> http://mail.pm.org/mailman/listinfo/saopaulo-pm
> >
> >
> >
> > --
> > http://mantovanihouse.blogspot.com/
> >
> > -------(\_------------_/)-----------
> > -------)--(----------)--(-----------
> > ------(----(---------)----)----------
> > -------)----(-------)----(-----------
> > -------(----(-------)----)-----------
> > --------\_-(\\.---.//)-_/------------
> > ----------\)' -8--8- '(/--------------
> > -----------/------------\---------------
> > ----------(--)--------(--)--------------
> > ------------(_c__c_)----------------
> > ----------------------------------------
> >
> > _______________________________________________
> > SaoPaulo-pm mailing list
> > SaoPaulo-pm em pm.org
> > http://mail.pm.org/mailman/listinfo/saopaulo-pm
> >
> _______________________________________________
> SaoPaulo-pm mailing list
> SaoPaulo-pm em pm.org
> http://mail.pm.org/mailman/listinfo/saopaulo-pm
>
--
http://mantovanihouse.blogspot.com/
-------(\_------------_/)-----------
-------)--(----------)--(-----------
------(----(---------)----)----------
-------)----(-------)----(-----------
-------(----(-------)----)-----------
--------\_-(\\.---.//)-_/------------
----------\)' -8--8- '(/--------------
-----------/------------\---------------
----------(--)--------(--)--------------
------------(_c__c_)----------------
----------------------------------------
-------------- Pr?xima Parte ----------
Um anexo em HTML foi limpo...
URL: <http://mail.pm.org/pipermail/saopaulo-pm/attachments/20090204/cf05dc9e/attachment-0001.html>
More information about the SaoPaulo-pm
mailing list