<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>
Construindo um Website Dinâmico
com Class::DBI, CGI::Application e Template Toolkit
</title>
<style type="text/css">
body { padding-left: 10%; padding-right: 8%; }
p { text-align:justify; font-family: sans-serif; }
div.title p:first-child{ font-weight: bold; font-size: 200%; text-align: center; }
div.title p{ font-weight: bold;
                 text-align: center;
                 font-size: 85%;
                 margin-left: 15%;
                 margin-right: 15%;
                 }
div.preface p:first-child { margin-top: 0px;
font-style: normal;
                                 font-weight: bold;
                                 font-size: 120%;
                                 text-align: left;
                                 text-decoration: underline;
                                }
div.preface p { text-align: justify;
                 font-style: italic;
                 margin-left: 10%;
                 margin-right: 10%;
                 font-size: 80%;
                 }
div.paragraph p { text-align: justify; }
div.paragraph p:first-child { margin-top: 0px;
                                 font-weight: bold;
                                 font-size: 120%;
                                 text-decoration: underline;
                                 }
pre.code { font-family: monospace;
font-size: 80%;
                 border: thin solid lightgray;
                 padding-top: 10px;
                 padding-left: 15px;
                 padding-bottom: 10px;
                 background-color: LightGray;
                 margin-left: 10%;
                 margin-right: 15%;
         }
pre.code span.reserved-word { font-weight:bold; }
div.display { text-align: center; }
</style>
</head>
<body>
<div class="title">
<p>Construindo um Website Dinâmico com Class::DBI, CGI::Application e Template Toolkit </p>
<p>Por Luis Campos de Carvalho, Líder do São Paulo Perl Mongers<br>
mailto: monsieur_champs [at] yahoo [dot] com [dot] br</p>
</div>
<div class="preface">
<p>Prefácio</p>
<p>Quando pensamos em aplicativos World Wide Web em Perl, normalmente nos vêem à cabeça aqueles programas gigantescos, desorganizados, cheios de problemas e praticamente impossíveis de se manter. Neste modesto e mal-escrito artigo, eu pretendo mostrar que é possível construir aplicativos dinâmicos, baseados nas tecnologias da World Wide Web, simples, rápidos, fáceis de manter e extensíveis, usando ferramentas de código fonte aberto, noções sobre o paradigma da Orientação a Objetos, e algumas técnicas de engenharia de software básica.</p>
</div>
<div class="paragraph">
<p>Molhando os Pés: primeiro contato com as tecnologias utilizadas neste artigo</p>
<p>Para começar, vamos falar da aplicação que desejamos fazer: é simples, e chega a ser até meio besta, para facilitar a compreensão. Desta forma, ao invés de se prender aos detalhes e complexidades da aplicação que vamos construir, o leitor terá sua atenção presa aos detalhes e complexidades envolvidas com <em>como</em> construir a aplicação.</p>
<p>Vamos construir um Módulo de Autenticação de Usuários.</p>
<p>A responsabilidade principal de um Módulo de Autenticação de Usuários é se certificar de que um usuário de nosso website é realmente quem ele diz ser, e permitir a ele acesso aos demais recursos dinâmicos disponíveis em nosso website fictício.</p>
<p>Para construir esta aplicação, vamos utilizar um <i>framework</i> de desenvolvimento de aplicações dinâmicas para a World Wide Web chamado <a href="http://search.cpan.org/~markstos/CGI-Application-4.04_02/">CGI::Application</a>, combinado com um gerenciador de banco de dados relacional (eu escolhi usar o <a href="http://www.postgresql.org">PostgreSQL</a>, mas outros, como o <a href="http://www.mysql.com">MySQL</a> e o <a href="http://www.oracle.com">Oracle</a> se encaixam aqui perfeitamente e não precisam de adaptações) através do uso de um conjunto de objetos Perl chamado <a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a>. Completam o nosso conjunto de bibliotecas-base um <i>framework</i> de visualização muito poderoso chamado <a href="http://www.template-toolkit.org">Template Toolkit</a> e um pouco de teoria sobre padrões de projeto e modelagem orientada a objetos.</p>
</div>
<div class="paragraph">
<p>O Projeto da Aplicação</p>
<p>Antes de continuarmos, vamos especificar e modelar rapidamente nossa aplicação. Isso, além de nos dar maior consciência sobre o que estamos construindo, ajuda as pessoas a compreender nosso trabalho (e a valorizá-lo).</p>
<p>Nosso Módulo de Autenticação de Usuários terá apenas um ponto de entrada: ele gerará uma página para coletar o nome e senha do usuário, tomará uma decisão baseado nos dados que o usuário lhe enviar e executará uma das duas únicas ações planejadas para ele: ou criará uma sessão para o usuário e o redirecionará para a parte restrita de nosso website dinâmico, ou enviará uma mensagem de erro, informando ao usuário que o par (nome, senha) apresentado não é válido. Em <em>Portugol</em>, para ficar simples:</p>
<pre class="code"> <span class="comment"># Processo 1: coleta de credenciais</span>
<span class="reserved-word">INÍCIO;</span>
constrói página de coleta de dados;
envia página de coleta de dados;
<span class="reserved-word">FIM.</span>
<span class="comment"># Processo 2: autenticação de usuários.</span>
<span class="reserved-word">INÍCIO;</span>
<usuário preenche informações de autenticação>;
recebe dados de autenticação de usuário;
verifica dados;
<span class="reserved-word">SE</span> dados válidos, <span class="reserved-word">ENTÃO</span>
<span class="reserved-word">INÍCIO</span>
gera informação de sessão;
registra informação de sessão;
envia <i>cookie</i> identificador ao usuário;
redireciona usuário autenticado para a aplicação;
<span class="reserved-word">FIM</span>
<span class="reserved-word">SENÃO</span>
<span class="reserved-word">INÍCIO</span>
gera página de informação de erro;
envia página ao usuário;
<span class="reserved-word">FIM;</span>
<span class="reserved-word">FIMSE;</span>
<span class="reserved-word">FIM;</span></pre>
<p>Agora que sabemos como deve ser nosso processo, vamos modelar rapidamente os dados necessários para autenticar um usuário. Precisamos apenas reter permanentemente algumas informações sobre os usuários, como um nome, e uma senha. Para isso, vamos criar uma tabela em nosso banco de dados relacional, utilizando este código SQL:</p>
<p>Isto vai criar uma tabela em nosso banco de dados, onde poderemos registrar nossos usuários.</p>
<pre class="code">-- Este script assume que você tem um banco de dados PostgreSQL, pode
-- conectar-se a ele e tem permissões mínimas para realizar criação de
-- tabelas e inclusão de registros nas tabelas criadas.
-- Se você tiver qualquer problema com isso, converse com seu DBA ou
-- Administrador de Sistemas local.
-- Copyleft 2005 Luis Campos de Carvalho
-- Copyleft 2005 Engenharia de Software Ltda
-- Doado aos São Paulo Perl Mongers
-- This script is free software; you can redistribute it and/or modify
-- it under the term of the GNU Public License.
CREATE SEQUENCE seq_usuario;
CREATE TABLE usuario (
uid INTEGER PRIMARY KEY DEFAULT NEXTVAL( 'seq_usuario'::text ),
login VARCHAR UNIQUE NOT NULL,
senha VARCHAR NOT NULL
);
-- EOF </pre>
<p>A aplicação do <a href="http://www.w3schools.com/sql/default.asp">SQL</a> no banco de dados varia muito. Por isso, vou deixar a tarefa de descobrir como se conectar ao banco de dados e criar tabelas para um futuro artigo sobre <a href="http://search.cpan.org/~timb/DBI-1.48/">DBI</a> e <a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a>.</p>
<p>Vamos passar agora à parte de modelagem de objetos e módulos necessários para a aplicação. Para isso, antes, precisamos conversar um pouco sobre <a href="http://en.wikipedia.org/wiki/MVC">MVC</a>, <a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a>, <a href="http://www.template-toolkit.org">Template Toolkit</a> e <a href="http://search.cpan.org/~markstos/CGI-Application-4.03/">CGI::Application</a>.</p>
</div>
<div class="paragraph">
<p>MVC, Class::DBI e CGI::Application</p>
<p>Agora vamos entrar na parte complicada deste tutorial. O leitor amigo possivelmente deve ter ouvido alguma coisa a respeito de <a href="">MVC</a>, ou, para os iniciados, <em>Model-View-Controller</em>. Este é um padrão de projeto (<em>Design Pattern</em>) que separa toda e qualquer aplicação em três componentes básicos: o Modelo(<em>Model</em>), a Visão (<em>View</em>) e o Controlador (<em>Controller</em>). Leiam um <a href="http://www.andywardley.com/computers/web/mvc.html">contraponto</a>, por <a href="http://www.wardley.org/">Andy Wardley</a>.</p>
<p>Em poucas palavras, já que eu não pretendo nem de longe esgotar este assunto: o <b>Modelo</b> é responsável por manter nossos dados e manipulá-los de acordo com as regras de negócio (que implementamos neles). São os modelos (geralmente temos muitos) que sabem como e onde armazenar e recuperar os dados que captamos e utilizamos.</p>
<p>Enquanto os modelos são responsáveis pelos dados e pelas regras de negócio (a forma de manipular os dados), as <b>Visões</b> tem como responsabilidade a exibição dos dados encontrados nos modelos. Uma visão normalmente conhece um modelo e sabe como exibir os dados daquele modelo por alguma mídia específica. Por exemplo: suponha que temos uma lista de usuários (um Modelo representando usuários) e desejamos exibir estes usuários pela internet (com <a href="http://www.w3.org/MarkUp/">HTML</a>) e em um telefone celular (com <a href="http://www.umtsworld.com/technology/wap.htm">WAP</a>). Para tornar isso possível, não precisamos mexer em nada relacionado com nossa lista de usuários: precisamos apenas implementar Visões capazes de exibir em HTML ou WAP. Assim, quando desejamos exibir a lista de usuários em HTML, utilizamos a visão capaz de exibir a lista em HTML e quando desejamos exibir nossos usuários em WAP, utilizamos a visão que implementa exibição WAP.</p>
<p>Finalmente, o <b>Controlador</b> tem um papel não muito intuitivo, mas muito importante, depois que se aprende a utilizá-lo corretamente: é dele a responsabilidade de decidir, para cada requisição enviada para nossa aplicação, qual modelo deve ser acionado para tratar dela. É também do Controlador a responsabilidade de verificar as credenciais de um usuário e determinar suas permissões de acesso. Normalmente, uma aplicação web tem apenas um controlador, não importa o quão grande ela seja.</p>
<p>A esta altura, você deve estar se perguntando qual a relação disso tudo com as bibliotecas Perl <a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a>, <a href="http://www.template-toolkit.org">Template Toolkit</a> e <a href="http://search.cpan.org/~markstos/CGI-Application-4.04_02/">CGI::Application</a>. É hora de explicar: cada uma desta bibliotecas implementa um dos elementos do MVC que vamos utilizar em nossa aplicação: <a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a> implementa modelos, <a href="http://www.template-toolkit.org">Template Toolkit</a> implementa visões e CGI::Aplication implementa nosso controlador. Vamos construir agora cada uma das diferentes partes do padrão de projeto que utilizaremos:</p>
</div>
<div class="paragraph">
<p>Implementação da Camada de Acesso a Dados com Class::DBI</p>
<p>Para implementar o modelo, vamos precisar de ajuda de mais um padrão de projetos, o <i>Data Access Object</i>, ou <a href="http://en.wikipedia.org/wiki/Data_Access_Object">DAO</a>, para os íntimos.</p>
<p>Este padrão de projeto consiste em manter objetos separados para cuidar das responsabilidades específicas de manipular e armazenar os dados. Fazemos isso para que, quando precisarmos alterar a forma ou o local de armanzenamento das informações, não precisemos alterar nossos processo de manipulação de dados, apenas o processo de armanzenamento e recuperação. Isto torna menor a possibilidade de introdução de novos erros em um sistema antigo por mudanças menos importantes para o negócio.</p>
<p>Para implementar o DAO, vamos utilizar uma biblioteca pronta. Isto é muito melhor que ser obrigado a "reinventar a roda" e construir nós mesmos.</p>
<p>Optamos pela biblioteca <a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a>. Poderíamos ter optado por outras semelhantes, como a <a href="http://search.cpan.org/~cwinters/SPOPS-0.87/">SPOPS</a>, que tem funcionalidade semelhante, mas oferece muitos recursos extras.</p>
<p><a href="http://search.cpan.org/~tmtm/Class-DBI-0.96/">Class::DBI</a> deve ser implementada através de extensão do objeto Class::DBI, e declaração de alguns métodos estáticos para informar à biblioteca sobre nosso banco de dados, nossas tabelas e nosso método preferido de carga de dados. Adicionalmente, podemos ir além e implementar métodos para desempenhar tarefas mais específicas, como algum tipo de <i>query</i> especial para nossa aplicação, ou outras funcionalidades semelhantes. Mas isso també está fora do nosso escopo de hoje. Vamos ver como deve ser nossa classe-base, devidamente comentada:</p>
<pre class="code">=head1 NAME
DAO::Base - Classe base para objetos de acesso a dados
=cut
package DAO::Base;
use strict;
use warnings;
use base qw( Class::DBI );
our $VERSION = sprintf '%d.%02d', q$Revision:$ =~ m/(\d+)\.(\d+)/;
=head1 SYNOPSIS
use base qw( DAO::Base );
=head1 DESCRIPTION
Esta é a classe base dos Objetos de Acesso a Dados, derivados de
Class::DBI.
=cut
__PACKAGE__->connection( 'dbi:Pg:dbname',
                         'dbuser', 'secret',
                         { AutoCommit => 1,
                         RaiseError => 1,
                         PrinError => 0,
                         }
                 );
=head1 AUTHOR
Luis Campos de Carvalho
Engenharia de Software Ltda.
=head1 REVISION
$Revision: $
=head1 COPYRIGHT
Copyleft 2005 Engenharia de Software Ltda.
Doado aos São Paulo Perl Mongers.
This module is free software; you can redistribute it and/or modify it
under the term of the GNU Public License.
=head1 SEE ALSO
L<Class::DBI>
</pre>
<p>Este módulo é composto de algumas declarações interessantes: primeiramente, o nome do pacote <code>package DAO::Base</code> foi escolhido com finalidade didática. É simples modificar isto quando for utilizado em um projeto sério (sim, estou acreditando que as pessoas vão se aproveitar deste código em projeots sérios!).</p>
<p>A próxima coisa interessante a se notar é relacionada com herança: eu declarei que este pacote tem como base (e herda funcionalidades de) Class::DBI, com a asserção <code>use base qw( Class::DBI );</code> isto é equivalente a dizer <code>BEGIN{ require Class::DBI; push @ISA, 'Class::DBI'; }</code>, mas é bem mais curto e fácil de entender.</p>
<p>Também é neste módulo que devemos declarar os dados de conexão com nosso banco de dados, para que ela possa ser compartilhada transparentemente entre todos os módulos derivados deste. Declaramos nossa conexão utilizando o método estático <code>Class::DBI::connection()</code>, mas o chamamos com <code>__PACKAGE__->connection()</code>. Isto é boa prática de programação orientada a objetos em Perl, já que não podemos assumir qual o tipo que será passado para nós quando da instanciação desta classe. A diretriz <code>__PACKAGE__</code> cuida sozinha destes detalhes, fazendo a coisa certa por nós. Ela sempre vai resolver para o nome do pacote correto, não importa o que aconteça. Para saber mais sobre os parâmetros passados ao banco de dados, por favor consultem a documentação do <a href="http://search.cpan.org/~timb/DBI-1.48/">DBI</a>.</p>
<p>Depois de declarar nossa conexão com o banco de dados, estamos prontos para extender esta classe e especializá-la para cada uma das tabelas que teremos.</p>
<p>A única tabela que teremos neste sistema é a tabela de usuários. Mas lembrem-se: para extender este sistema para um sistema completo e útil, basta seguir a mesma linha de pensamento que estamos desenvolvendo aqui e continuar implementando as funcionalidades restantes.</p>
<p>Nosso objeto de acesso a dados de usuário será declarado desta forma:</p>
<pre class="code">=head1 NAME
DAO::Usuario - Objeto de Acesso a Dados da tabela 'usuario'.
=cut
package DAO::Usuario;
use warnings;
use strict;
use base qw( DAO::Usuario );
our $VERSION = sprintf '%d.%02d', q$Revision:$ =~ m/(\d+)\.(\d+)/;
=head1 SYNOPSIS
use DAO::Usuario; $user = DAO::Usuario->create( ... ); $user =
DAO::Usuario->retrieve( ... ); $user = DAO::Usuario->search( ... );
=head1 DESCRIPTION
Este é o módulo de acesso a dados da tabela de usuarios do sistema de
autenticacao de usuarios desenvolvido para o mini-curso da UNISAL.
=cut
__PACKAGE__->table( 'usuario' );
__PACKAGE__->columns( All => qw[ id login senha ] );
=head1 AUTHOR
Luis Campos de Carvalho Engenharia de Software Ltda.
=head1 REVISION
$Revision: $
=head1 COPYRIGHT
Copyleft 2005 Engenharia de Software Ltda.
Doado aos São Paulo Perl Mongers.
This module is free software; you can redistribute it and/or modify
it under the term of the GNU Public License.
=head1 SEE ALSO
L<Class::DBI>
</pre>
<p>Reparem que este módulo se parece muito com o outro. Declaramos um pacote no mesmo nível, <code>DAO::Usuario</code>, para modelar nossos usuários. Em seguida, declaramos que herdamos as fucnionalidades de <code>DAO::Base</code>, em especial duas muito importantes: 1) é de lá que vem nossas informações de banco de dados, que vamos precisar para fazer com que este módulo possa recuperar e armazenar alguma informação no banco de dados; e 2) como <code>DAO::Base</code> herda de <code>Class::DBI</code> (lembra?), também nosso módulo herda as funcionalidades implementadas lá. É este pequeno detalhe que faz com que tudo isso funcione perfeitamente.</p>
<p>As declarações que precisamos fazer aqui são simples: precisamos declarar qual tabela este módulo acessa, e quais os campos da tabela que estarão visíveis para nossa aplicação. Não, você não precisa declarar todos os campos como visíveis. Mas não há como o <code>Class::DBI</code> conhecer (ou utilizar) os campos que você não declarar. Use isto com sabedoria.</p>
<p>Para declarar tabelas, utilizamos a diretriz auto-explicativa <code>__PACKAGE__->table( 'usuario' )</code>. Como todos já perceberam, o único parâmetro passado (o nome da tabela) é obrigatório.</p>
<p><strong>Depois</strong> (lembrem-se: <strong>Depois</strong>!) de declarar qual tabela desejamos acessar, podemos então declarar quais colunas desta tabela desejamos que nosso módulo veja. Note que isso implica que podemos ter tabelas com quantos atributos desejar, e podemos controlar quais módulos acessam que colunas através desta declaração.</p>
<p>Para declarar as colunas visíveis, utilizamos <code>__PACKAGE__->columns( All => qw[ id login senha ] );</code> isto declara três colunas visíveis, e <strong>implicitamente</strong> declara que a primeira coluna da lista (<code>id</code>) é nossa chave primária.</p>
<p>Com isso, encerramos a parte de construção da camada de acesso a dados. O que temos até este momento são dois objetos simples: <code>DAO::Base</code> e <code>DAO::Usuario</code>. </p>
<p>Por agora, vamos apenas reservar estes módulos. Vamos precisar deles mais adiante.</p>
</div>
<div class="paragraph">
<p>Implementação das Visões com Template Toolkit</p>
<p>Agora que podemos contar com nossos objetos de acesso a dados, vamos implementar nossas visões. São elas que darão um rosto para nossa aplicação, e por isso mesmo devem ser tratadas com um certo cuidado. Como esta é uma aplicação reutilizável, devemos tomar alguns cuidados extras com a documentação dos <em>templates</em>, para que seja sempre possível a um desenvolvedor adaptá-lo às suas necessidades.</p>
<p>Nossa primeira visão precisa pedir ao usuário que entre com seu nome e senha em duas caixas de texto. Também precisa oferecer a ele um botão que vai nos levar de volta para a aplicação. Nossa segunda visão será utilizada apenas em caso de erros: caso o nome ou senha fornecidos pelo usuário não o identifiquem corretamente, precisamos informar isto a ele. Em caso de autenticação positiva, vamos utilizar um redirecionamento HTTP (código de resposta 302) para indicar ao <em>browser</em> do usuário para onde ir em seguida, e ao mesmo tempo transmitir a este programa as credenciais do usuário que ele conduz.</p>
<p>Com algum esforço de desenvolvimento, construimos a primeira visão, que vamos chamar de <code>ask-credentials.tmpl</code>. Ela se parece muito com isso:</p>
<div class="display">
<img align="center" valign="middle" src="images/login.gif" alt="quadro de login" border="0" />
</div>
<p>O código fonte HTML utilizado para gerar isto é assim:</p>
<pre class="code"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
<meta name="AUTHOR" content="Luis 'Champs' de Carvalho">
<style type="text/css">
form { font-family: monospace;
border: thin solid gray;
         position: absolute;
         top: 45%; left: 60%;
         padding-left: 5%;
         padding-right: 5%;
         background-color: lightyellow;
         }
form p:first-child { font-weight: bold; }
form p.submit { text-align: right; }
</style>
</head>
<body>
<form action="[% action %]" method="POST" enctype="application/x-www-form-urlencoded">
<p>Entrada do Sistema</p>
<p>Login:
<input type="text" name="login" size="16" tabindex="1" align="middle">
</p>
<p>Senha:
<input type="password" name="passwd" size="16" tabindex="2" align="middle">
</p>
<p class="submit"><input type="submit" name="mode" value="Login" tabindex="3"></p>
</form>
</body>
</html>
</pre>
<p>Preste atenção a alguns pequenos detalhes: os nomes dos campos que estamos utilizando são importantes. Vamos conferir: o campo onde o usuário escreverá seu <em>login</em> chama-se <code>login</code>; o campo onde escreverá sua senha é especial (do tipo <code>password</code>, e chama-se <code>passwd</code>; e finalmente, o botão de envio chama-se <code>mode</code>. Isto é muito importante, pois é através deste campo que a aplicação determinará qual deve ser o próximo passo.</p>
<p>Note também que preenchemos o atributo <code>action</code> do <em>tag</em> <code>form</code> com uma espécie de <em>tag</em> especial. Isto é um comando para o Template Toolkit. Vamos voltar a estes detalhes em breve. Por enquanto, basta prestar atenção nisso.</p>
<p>Precisamos ainda de mais uma visão, para informar o usuário que ele não possui credenciais válidas. Ele deve ser assim:</p>
<pre class="code"><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<!-- $Id$ -->
<head>
<title>Erro na Autenticação!</title>
<meta name="AUTHOR" content="Luis 'Champs' de Carvalho">
<style type="text/css">
p.error { border: thin solid black;
background-color: red;
         font-weight: bold;
         text-align: center;
         position: absolute;
         left: 35%;
         top: 35%;
         }
</style>
</head>
<body>
<p class="error">[% error_message %]</p>
</body>
</html>
</pre>
<p>Note que voltamos a utilizar um daqueles comandos especiais para o Template Toolkit. Vamos falar sobre isso em alguns instantes. O importante agora é que isso liqüida com o assunto das visões, e nos permite começar a explicar como deve ser construío o núcleo da aplicação.</p>
</div>
<div class="paragraph">
<p>Introdução ao conceito de Stash</p>
<p><b>Stash</b> é simplesmente um conceito. É um repositório de dados semi-público, que utilizamos para acumular informações sobre a requisição que estamos processando. Eu digo semi=público por que não podemos acessar o stash de uma requisição exceto se estivermos processando esta requisição.</p>
<p>Vamos implementar nosso stash com um <i>design pattern</i> chamado <a href="">Singleton</a>, que no nosso caso servirá para garantir que todas as referências para o stash sejam processadas pelo mesmo stash, dentro de uma determinada requisição.</p>
<p>Nosso método stash() é implementado automaticamente pela biblioteca <a href="">Class::Accessor</a>, que cria automaticamente métodos de acesso a estruturas de dados auxiliares, com declarações simples como "<code>__PACKAGE__->mk_accessors( qw[ stash ] );</code>".</p>
</div>
<div class="paragraph">
<p>Introdução ao Class::Accessor</p>
</div>
<div class="paragraph">
<p>Introdução ao AppConfig</p>
</div>
<div class="paragraph">
<p>Introdução ao Template Toolkit</p>
</div>
<div class="paragraph">
<p>Introdução ao CGI::Application</p>
</div>
<div class="paragraph">
<p>Implementação do Controlador com CGI::Application</p>
</div>
</body>
</html>