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