Frame Mostra PDF
Frame Mostra PDF
Frame Mostra PDF
4ª edição
AMOSTRA
PABLO DALL'OGLIO
1 Introdução
CAPÍTULO 1
Introdução
Este capítulo apresenta os conceitos fundamentais presentes no Adianti
Framework. Aqui você conhecerá as premissas de desenvolvimento do
framework, suas principais características, sua arquitetura, estrutura de
diretórios e como se dá o fluxo de execução de seu funcionamento.
1.1 Características
Aqui veremos as características do Adianti Framework.
Foco em aplicações de negócio
O Adianti Framework em nenhum momento teve a intenção de possibilitar o
desenvolvimento de sites e blogs. Digo isso porque quase todo o framework é
introduzido com o desenvolvimento de um blog. O Adianti Framework nasceu
dentro de um contexto de desenvolvimento de sistemas de gestão, sistemas de
informação. Então ele não prima pela flexibilidade de configuração de seus
componentes. Por outro lado, ele apresenta componentes bem acabados, pron
tos e fáceis de utilizar para a criação de aplicações de negócio. O que diferencia
sites de aplicações de negócio? O importante para a aplicação de negócio é a
funcionalidade, não o aspecto visual. O usuário de uma aplicação de negócio
não vai solicitar que cada uma das telas do sistema tenha uma cor diferente, ele
deseja que o sistema funcione bem e não se importa que todas as telas do siste
ma sejam parecidas. Nada impede você de utilizar o framework para desenvol
ver o backend de um site, inclusive eu o uso para isto, mas sua vocação real
mente não é frontends, para isso existem diversas outras boas soluções no mer
cado.
Capítulo 1 - Introdução - amostra do livro 13
Orientado a componentes
Diferentemente de outros frameworks que instruem o desenvolvedor a mesclar
HTML e PHP em templates com o auxílio de helpers, no Adianti Framework
você não encontrará isto. A ideia do framework é construir interfaces por meio
de componentes. E se você precisa de algum recurso que o framework não ofe
rece, construa um componente. Não gostamos de escrever código HTML, CSS,
Gtk2 e jQuery, dentre outras tecnologias de apresentação dentro do códigofon
te da aplicação. Estes códigos podem e devem ficar escondidos dentro do fra
mework, encapsulados dentro de componentes orientados a objetos. Assim, o
desenvolvedor não precisa ser grande conhecedor destas tecnologias para cons
truir interfaces avançadas, basta conhecer os componentes. Como exemplo,
para criar componentes utilizados em um formulário (texto, data, combo, den
tre outros), declaramos da seguinte maneira:
<?php
$nome = new TEntry('nome');
$senha = new TPassword('senha');
$nascimento = new TDate('nascimento');
$curriculo = new TText('curriculo');
?>
Multiinterface
Esta é talvez a característica que mais diferencie o Adianti Framework de outros
frameworks. O Adianti permite ao desenvolvedor criar aplicações Web e Desk
top. A ideia é bastante simples, você escreve um códigofonte que roda em duas
interfaces. A interface Web a maioria de vocês já conhece e a interface desktop
é fornecida pela biblioteca Gtk, ou PHPGTK. Assim, dependendo da aplicação,
você pode escolher o frontend mais adequado sem precisar aprender outra tec
nologia. Na figura a seguir é exibido um fragmento de uma aplicação com fron
tend Web à esquerda e Gtk à direita.
Figura 1 Formulários Web e Gtk da mesma aplicação
2 INSTALAÇÃO E CONFIGURAÇÃO
CAPÍTULO 2
Instalação e configuração
Neste capítulo vamos aprender a dar os primeiros passos com o fra
mework. Inicialmente vamos abordar a instalação dos prérequisitos tan
to em ambientes web quanto desktop. Em seguida vamos dar os primei
ros passos, aprendendo a configurar sua aparência por meio de templa
tes.
Instalação Web
A instalação do ambiente Web é simples e rápida, vejamos:
# sudo su
# apt-get install apache2
# apt-get install libapache2-mod-php5 php5 php5-sqlite php5-pgsql php5-mysql
# /etc/init.d/apache2 restart
Obs: Durante o período de desenvolvimento, certifiquese que a exibição de erros
(display_errors = On) esteja habilitada no php.ini
Instalação Desktop
A preparação do ambiente desktop envolve a instalação do PHPGTK. Deve ser
realizado o download do mesmo a partir do site http://phpgtk.com.br/linux.
28 Amostra do livro Adianti Framework para PHP
Template
A página de entrada index.web.php faz basicamente a apresentação do templa
te, armazenado no arquivo layout.html. Mas quais são os principais aspectos
que devemos aprender sobre um template ? Em primeiro lugar, o template deve
ter um <div> com o ID adianti_div_content. É neste quadro que o conteúdo
do sistema (formulários, listagens) são carregados dinamicamente. Em segundo
lugar, o template deve ter outro <div> com o ID adianti_online_content. Nes
te segundo são carregados conteúdos como janelas sobrepostas ao conteúdo
principal. Por fim, mas não menos importante, todos os links do sistema <a
href> que tiverem o atributo generator=”adianti” são “sequestrados” via
jQuery e carregados por meio da função JavaScript __adianti_load_page(). O
objetivo desta função é processar os links do framework e apresentálos dentro
de <div id="adianti_div_content">.
Obs: A versão completa deste arquivo encontrase na página de downloads do fra
mework.
app/templates/theme1/layout.html
<html>
<head>
<title>Adianti Framework :: Wellcome</title>
{LIBRARIES}
{HEAD}
...
<script type="text/javascript">
$('[generator="adianti"]').live('click', function()
{
__adianti_load_page($(this).attr('href'));
return false;
});
</script>
</head>
<body>
<div class="container">
<div class="body">
<div id="menuDiv">{MENU}</div>
<div id="adianti_div_content" class="content"></div>
<div id="adianti_online_content"></div>
...
</div>
</div>
<script type="text/javascript" id="adianti_placeholder">
//#javascript_placeholder#
</script>
</body>
</html>
Capítulo 2 - Instalação e configuração - amostra do livro 31
Motor de execução Web
O arquivo engine.php é o motor de execução do framework para aplicações
Web. Todas requisições de páginas passam por ele. Basicamente em seu início,
são realizadas as mesmas definições do index.web.php, envolvendo configura
ções de idioma, timezone, e declarações de algumas constantes. Ao final, é exe
cutado o método run() da classe TApplication. Esta classe, por sua vez, é filha
de TCoreApplication, uma classe do framework responsável por interpretar e
executar as ações vindas de uma requisição HTTP.
Caso seja necessário acrescentar um controle de acesso (permissões), este pode
ser realizado dentro do método run() de TApplication, observando se o usuá
rio possui permissão para visualizar aquele conteúdo requisitado. Um controle
deste tipo é realizado na aplicação Library, estudada posteriormente.
Obs: As classes da aplicação são carregadas automaticamente a partir das pastas
app/model, app/control, app/view e app/lib, o que é feito pela TAdiantiLoader.
engine.php
<?php
// define o autoloader
include_once 'lib/adianti/util/TAdiantiLoader.class.php';
spl_autoload_register(array('TAdiantiLoader', 'autoload_web'));
// lê configurações
$ini = parse_ini_file('application.ini');
date_default_timezone_set($ini['timezone']);
TAdiantiCoreTranslator::setLanguage( $ini['language'] );
TApplicationTranslator::setLanguage( $ini['language'] );
// define constantes
define('APPLICATION_NAME', $ini['application']);
define('OS', strtoupper(substr(PHP_OS, 0, 3)));
define('PATH', dirname(__FILE__));
TApplication::run(TRUE);
?>
Obs: O parâmetro booleano do método run() define se as mensagens de exceção serão
detalhadas para debug (TRUE), ou resumidas para ambientes em produção (FALSE).
O padrão é TRUE. Quando a aplicação entrar em produção, altere para FALSE.
34 Amostra do livro Adianti Framework para PHP
app/control/WellcomeView.class.php
<?php
class WellcomeView extends TPage
{
function __construct()
{
parent::__construct(); // é fundamental executar o construtor da classe-pai
$image = new TImage('app/images/frontpage.png');
// adiciona a imagem à página.
parent::add($image);
}
}
?>
Obs: Não se preocupe se você não compreendeu muito bem a classe controladora,
mais adiante criaremos diversos outros tipos.
Obs: Para um melhor aproveitamento do livro, em vários pontos as aplicações são
apresentadas em forma de fragmentos. O código completo encontrase no tutor.
3 MODELOS E PERSISTÊNCIA
CAPÍTULO 3
Modelos e persistência
Todo o acesso a bancos de dados dentro do Adianti Framework passa
por uma camada orientada a objetos que torna a maioria das operações
transparentes ao desenvolvedor. Esta camada de manipulação visa dar
maior agilidade na criação das aplicações, bem como fazer com que todo
o acesso aos dados ocorra de uma maneira orientada a objetos. Assim,
na grande maioria das vezes, você não precisará mais escrever os tradici
onais INSERT, UPDATE e DELETE, mas irá simplesmente mandar os ob
jetos serem persistidos ou excluídos.
contato (objeto parte) é parte de somente um objeto cliente (objeto
todo);
❏ Um objeto Customer (cliente) possui uma agregação com nenhum ou
vários objetos do tipo com Skill (habilidade). Isto significa que um ob
jeto habilidade (objeto parte) pode ser parte de diferentes objetos cliente
(objeto todo).
Figura 14 Modelo de classes
Obs: Você encontra maiores informações sobre orientação a objetos em PHP com o li
vro “PHP Programando com orientação a objetos”, do mesmo autor.
app/control/dbsamples/ManualQuery.class.php
<?php
class ManualQuery extends TPage
{
public function __construct()
{
parent::__construct();
try
{
TTransaction::open('samples'); // abre uma transação
$conn = TTransaction::get(); // obtém a conexão
// realiza a consulta
$result = $conn->query('SELECT id, name from customer order by id');
// exibe os resultados
foreach ($result as $row)
{
print $row['id'] . '-';
print $row['name'] . "<br>\n";
}
TTransaction::close(); // fecha a transação.
}
catch (Exception $e)
{
new TMessage('error', $e->getMessage());
}
}
}
?>
Obs: Não entraremos em detalhes sobre o funcionamento da classe PDO por tratarse
de uma classe nativa do PHP. Maiores informações em http://www.php.net/pdo.
42 Amostra do livro Adianti Framework para PHP
“An object that wraps a row in a database table or view, encapsula
tes the database access, and adds domain logic on that data.”
Um Active Record é um objeto que representa uma linha de uma tabela (ou
view) e encapsula ao mesmo tempo o acesso aos dados e a lógica de negócios
daquela entidade. Para exemplificar, podemos pensar em um objeto Livro. Este
objeto pode ter métodos como registrarEmprestimo() e
registrarDevolucao() que são métodos de negócio e também pode ter méto
dos como store(), delete() e load() que são métodos de acesso aos dados
(persistência).
Geralmente os objetos Active Record não implementam estes métodos de aces
so aos dados store(), delete() e load(), uma vez que nossos objetos teriam
misturado em um mesmo local métodos de negócio e de persistência. Para re
solver isso, os objetos Active Record generalizam estas operações, que são im
plementadas por superclasses. No caso do Adianti Framework, os métodos de
persistência são implementados pela classe TRecord. Assim, todos os objetos de
domínio da aplicação devem ser subclasses de TRecord, herdando um conjunto
de métodos de persistência.
Figura 16 Um objeto Active Record
44 Amostra do livro Adianti Framework para PHP
app/control/dbsamples/ObjectStore.class.php
<?php
class ObjectStore extends TPage
{
public function __construct()
{
parent::__construct();
try
{
TTransaction::open('samples'); // abre uma transação
Figura 17 Carregamento de objetos com repositório
Como podemos ver na figura, a aplicação (programa) interage com uma classe
que implementa o padrão Repository (TRepository). Esta classe disponibiliza
métodos para carregar (load), contar (count) e excluir (delete) coleções de
objetos. Antes de realizar a operação desejada, é necessário identificar o con
junto de objetos a ser manipulado. A identificação do conjunto de objetos é rea
lizada por um critério (objeto TCriteria). Um critério identifica regras de sele
ção de objetos na base de dados.
A classe TRepository realiza um acesso à base de dados e interage com os obje
tos selecionados pelo critério. No exemplo demonstrado pela figura estamos
carregando objetos (load). Neste caso, vários objetos do tipo Active Record são
instanciados (conforme o critério) e retornados para a aplicação como vetor.
Capítulo 3 - Modelos e persistência - amostra do livro 63
app/control/dbsamples/CollectionSimpleDelete.class.php
<?php
class CollectionSimpleDelete extends TPage
{
public function __construct()
{
parent::__construct();
try
{
TTransaction::open('samples');
$repository = new TRepository('Customer');
$repository->where('address', 'like', 'Rua Porto%')
->where('gender', '=', 'M')
->delete();
Figura 18 Exemplo de associação
Capítulo 3 - Modelos e persistência - amostra do livro 71
3.5.3 Agregação
A agregação também é um relacionamento todo/parte, tal qual a composição.
Assim, também temos um objeto “todo” composto de uma ou mais “partes”. A
diferença primordial entre os dois tipos de relacionamento é que na agregação,
um objeto “parte” não é exclusivo do “todo”, ou seja, pode pertencer à diferen
tes objetos “todo”. A figura a seguir mostra o exemplo de agregação utilizado
neste livro. Neste exemplo, temos objeto Customer (cliente) com uma agrega
ção com o objeto Skill (habilidades).
Figura 22 Relacionamento de agregação
Como vimos, na agregação um objeto “parte” pode estar vinculado à diferentes
objetos “todo”. Neste caso em específico, um cliente pode ter diferentes habili
dades (esportes, literatura, música) e uma habilidade pode pertencer à diferen
tes clientes. Dessa forma, não é possível representar essa estrutura em banco de
4 COMPONENTES DE APRESENTAÇÃO
CAPÍTULO 4
Componentes de apresentação
No último capítulo vimos como manipular objetos. Em alguns momen
tos, criamos páginas para exibir resultados (subclasses de TPage), mas
como o foco do capítulo era persistência, a apresentação ficou em segun
do plano. O foco deste capítulo é explorar os componentes de apresenta
ção do framework. Portanto, vamos explorar tabelas, painéis e notebo
oks; componentes para criação de formulários e datagrids; diálogo de
mensagens, dentre outros.
app/control/Presentation/HelloWorld.class.php
<?php
class HelloWorld extends TPage
{
public function __construct()
{
parent::__construct(); // é fundamental executar o construtor da classe pai
parent::add(new TLabel('Hello World'));
}
}
?>
Para exibir um controlador de páginas na Web, podemos editar o layout da apli
cação (ver seção 2.3.1) e acrescentar um link para index.php, identificando a
classe que gostaríamos que o framework exibisse por meio do parâmetro class:
<a href="index.php?class=HelloWorld" generator="adianti"> Hello World</a>
Ou também podemos simplesmente digitar no navegador:
http://localhost/tutor/index.php?class=HelloWorld
O resultado da execução pode ser visto na figura a seguir.
Figura 24 Resultado da execução do Hello World
Já no ambiente desktop (Gtk), para exibirmos uma página, basta executarmos
o método loadPage() da classe TApplication, da seguinte forma:
TApplication::loadPage('HelloWorld');
Também podemos utilizar o controlador de páginas TWindow para criar novas
páginas. O conteúdo das subclasses de TWindow é exibido em janelas sobre o sis
tema. A seguir temos uma página subclasse de TWindow e o resultado de sua
execução.
app/control/Presentation/HelloWorldWindow.class.php
<?php
class HelloWorldWindow extends TWindow
{
public function __construct()
{
parent::__construct();
parent::add(new TLabel('Hello World Window'));
}
}
?>
Capítulo 4 - Componentes de apresentação - amostra do livro 89
4.2.6 Scroll
Normalmente quando construímos interfaces, sabemos antecipadamente a
quantidade de campos a colocar na tela. Entretanto, às vezes a criação da inter
face se dá de maneira dinâmica e não temos como antecipar quantos campos
serão colocados. Nestes casos, precisamos de componentes com barras de rola
gem (scrolling). O Adianti Framework possui o componente TScroll, que se
trata de uma área com barras de rolagem, podendo comportar mais componen
tes que sua área visual inicial.
O componente TScroll possui o método setSize(), responsável por determi
nar o tamanho da área de rolagem e também o método add(), responsável por
adicionar um conteúdo dentro da área de rolagem. Podemos adicionar ao scroll
qualquer container, como uma tabela ou painel por meio do método add().
No próximo exemplo, construímos uma página contendo uma área de rolagem
($scroll). Determinamos o tamanho da área de rolagem com 400 pixels de
largura e 200 pixels de altura por meio do método setSize(). Em seguida, cri
amos uma tabela (new TTable) que será acrescentada à área de rolagem por
meio do método add(). Após, o programa entra em um FOR com 20 iterações,
sendo que cada iteração cria um objeto de entrada de texto (TEntry) e adiciona
uma linha na tabela. Esses 20 elementos criados já são suficientes para perce
bermos o efeito das barras de rolagem.
app/control/Presentation/Containers/ContainerScrollView.class.php
<?php
class ContainerScrollView extends TPage
{
function __construct()
{
parent::__construct();
// cria o scroll
$scroll = new TScroll;
$scroll->setSize(400, 200);
Obs: A segunda ação, que representa a resposta “Não” é opcional. Caso ela não for in
formada, a opção “Não” simplesmente fecha o diálogo de questionamento.
Na próxima figura, podemos ver o resultado da execução deste programa.
Figura 37 Mensagem de questionamento no ambiente web
4.4 Formulários
Nas seções anteriores, vimos como organizar visualmente os elementos em uma
interface por meio de containers e também como apresentar informações ao
usuário por meio de diálogos. Nesta seção, veremos como utilizar formulários
para obter e registrar a entrada de informações na aplicação por meio de com
ponentes que acompanham o Adianti Framework. Esta seção será dividida em
tópicos, onde cada tópico apresentará uma característica diferente do uso de
formulários.
app/control/Presentation/Forms/FormQuickView.class.php
<?php
class QuickFormView extends TPage
{
private $form;
function __construct()
{
parent::__construct();
$combo_items = array();
$combo_items['a'] ='Item a';
$combo_items['b'] ='Item b';
$combo_items['c'] ='Item c';
$list->addItems($combo_items);
$this->form->addQuickAction('Save',
new TAction(array($this, 'onSave')),'ico_save.png');
parent::add($this->form);
}
Na próxima figura, podemos ver o resultado da execução deste programa.
Figura 38 Formulário rápido no ambiente web
4.4.4 Validações
Os exemplos anteriores nos permitiram dominar as técnicas básicas de monta
gem de formulários rápidos e também de formulários personalizados. Também
vimos como criar ações e obter os dados do formulário. Não basta somente ob
termos os dados do formulário, é preciso que os mesmos sejam válidos. Para ga
rantir que os dados obtidos de um formulário sejam válidos, o Adianti Fra
mework possui uma série de validadores para campos de formulários.
Para acrescentar validação a um formulário, basta utilizarmos o método addVa
lidation() sobre o campo que desejamos validar e, no momento de obter os
dados do formulário, executar o método validate(). Inicialmente, para cada
campo do formulário que deve passar por algum tipo de validação, deve ser
executado o método addValidation(). Este método recebe como parâmetros:
um nome para descrever o campo (a ser utilizado em mensagens de validação);
um objeto de validação (Ex: TMinValidator); e parâmetros específicos para
aquele tipo de validação. Veja na tabela a seguir os validadores que acompa
nham o framework.
Tabela 3. Validadores
Validador Descrição
TRequiredValidator Valida se o campo foi preenchido (obrigatoriedade).
TNumericValidator Valida se o campo contém um número válido.
TMinLengthValidator Valida a quantidade mínima de caracteres do campo.
TMaxLengthValidator Valida a quantidade máxima de caracteres do campo.
TMinValueValidator Valida o valor mínimo que deve estar presente no campo.
TMaxValueValidator Valida o valor máximo que deve estar presente no campo.
TEmailValidator Valida se o campo contém um email válido.
TCNPJValidator Valida se o campo contém um CNPJ válido.
TCPFValidator Valida se o campo contém um CPF válido.
O objetivo desse exemplo, que pode ser visto no códigofonte a seguir, é criar
um formulário que demonstre alguns dos principais tipos de validações que po
demos acrescentar a um formulário. Assim como fizemos no exemplo anterior,
neste criamos um formulário (TForm) contendo uma tabela (TTable) em seu in
terior para a organização dos campos e colocamos este formulário dentro de
um notebook (TNotebook) para uma melhor disposição visual.
Capítulo 4 - Componentes de apresentação - amostra do livro 113
Figura 41 Validação de formulário no ambiente web
app/lib/validator/TDateValidator.class.php
<?php
class TDateValidator extends TFieldValidator
{
/**
* Valida uma data
* @param $label Identifica o campo, em caso de exceção
* @param $value Valor a ser validado
* @param $parameters Parâmetros adicionais (ex: máscara)
*/
public function validate($label, $value, $parameters = NULL)
{
$mask = $parameters[0];
$year_pos = strpos($mask, 'yyyy');
$month_pos = strpos($mask, 'mm');
$day_pos = strpos($mask, 'dd');
4.5 Datagrids
Ao longo do livro já vimos como organizar o visual da aplicação por meio de
containers, como interagir com o usuário por meio de diálogos e também como
coletar informações por meio de formulários. O próximo passo está em apre
sentar as informações ao usuário no formato de listagens, permitindo que o
mesmo possa interagir sobre os dados tomando ações. No Adianti Framework,
as informações são apresentadas ao usuário por meio de datagrids. Uma data
grid geralmente apresenta uma coleção de Active Records vindos da base de
dados. Entretanto, antes de interagirmos com a base de dados, vamos aprender
os conceitos básicos sobre datagrids trabalhando com dados estáticos. Trabalha
remos integrando componentes visuais e banco de dados no próximo capítulo.
Obs: Normalmente datagrids são construídas com a intenção de exibir objetos Active
Record. Nos exemplos dessa seção utilizaremos objetos simples (StdClass) por moti
vos didáticos. No próximo capítulo, construiremos formulários e listagens integrados
aos Active Record.
Capítulo 4 - Componentes de apresentação - amostra do livro 139
Logo após definir quais serão as colunas da datagrid, adicionamos duas ações à
datagrid por meio do método addQuickAction(). As ações em uma datagrid
são relativas a uma linha. O método addQuickAction() recebe alguns parâme
tros como: nome da ação, ação a ser executada (TDataGridAction), nome do
atributo a ser passado para a ação como parâmetro e uma imagem represen
tando o ícone da ação.
Após definir as características básicas da datagrid como colunas e ações, o mé
todo createModel() deve ser executado. Este método cria a estrutura básica de
uma datagrid em memória. A partir deste momento, registros já poderiam ser
inseridos na datagrid. Por fim, a datagrid é acrescentada à página.
app/control/Presentation/Datagrid/DatagridQuickView.class.php
<?php
class DatagridQuickView extends TPage
{
private $datagrid;
// cria a datagrid
$this->datagrid = new TQuickGrid;
$this->datagrid->setHeight(260);
Logo após construirmos a datagrid no método construtor, partirmos para a so
brecarga do método show() da página. Ao sobrecarregarmos o método show(),
sempre que a página for exibida, o método onReload() será executado. O obje
tivo do método onReload() é carregar a datagrid com alguns objetos. Cada ob
jeto possui alguns atributos e estes devem corresponder aos nomes indicados
como segundo parâmetro do método addQuickColumn().
Capítulo 4 - Componentes de apresentação - amostra do livro 153
O objetivo do método onSave() é somente exibir quais botões de checagem fo
ram selecionados. Para tal, ele obtém os dados do formulário e monta uma
string contendo cada botão de checagem (check1, check2, check3, etc...). O
método show() deve ser reescrito para executar o método onReload().
public function onSave($param)
{
$data = $this->form->getData(); // obtém os dados do form
$this->form->setData($data); // mantém o formulário preenchido
// exibe a mensagem
new TMessage('info', $message);
}
function show()
{
$this->onReload();
parent::show();
}
}
?>
Na figura a seguir, podemos conferir o resultado da execução deste programa
no ambiente Web.
Figura 57 Datagrids com checagem no ambiente Web
function onStep3()
{
$data = $this->form->getData();
$data->field5 = 'Hi '. $data->field4;
$this->notebook->setCurrentPage(2);
$this->form->setData($data);
$this->step->select('Step 3');
}
function onSave()
{
$this->notebook->setCurrentPage(2);
$this->form->setData($this->form->getData());
new TMessage('info', str_replace('"field', '<br>"field ',
json_encode($this->form->getData())));
$this->step->select('Step 3');
}
}
?>
Na próxima figura, podemos ver o resultado da execução deste programa.
Figura 59 Formulário passo a passo
4.7 Relatórios
A utilização de datagrids oferece um meio bastante utilizado para listagem e vi
sualização das informações já registradas pelo sistema. Entretanto, as datagrids
não substituem relatórios. Os usuários frequentemente desejam imprimir docu
mentos contendo quantidades maiores de dados a partir do sistema. Neste caso,
precisamos usar formatos mais adequados para a impressão. O Adianti Fra
mework disponibiliza um conjunto de classes para geração de relatórios em ta
belas nos formatos: HTML, PDF e RTF. O ponto positivo na utilização desta bi
blioteca é que você escreve o relatório somente uma vez, e pode exportar para
os três formatos sem a menor necessidade de nova programação.
Obs: As classes para geração de relatórios vistas aqui foram propostas pela primeira
vez no livro “Criando relatórios com PHP”, do mesmo autor.
Para demonstrar a utilização das classes para geração de relatórios, construire
mos um formulário para seleção de clientes. Este formulário permite filtrar por
partes do nome, cidade e categoria. O usuário poderá preencher um ou mais fil
tros neste formulário. O programa deverá buscar todos os clientes na base de
dados pelos filtros selecionados. Para tal, utilizaremos coleções, como visto no
capítulo 3. A partir da coleção de clientes carregada em memória, procedere
mos com a escrita do relatório. O relatório poderá ser extraído em um dos três
formatos: HTML, PDF ou RTF conforme pode ser visto na figura a seguir.
Na próxima figura, podemos ver o formulário de seleção de clientes.
Figura 61 Tela de filtragem do relatório na web
O programa inicia com a criação do formulário (TForm) e de uma tabela que irá
dentro do formulário para conter os campos (TTable). Logo em seguida, são
criados os campos do formulário e adicionadas algumas opções (html, pdf, rtf)
no rádio button, bem como definidas algumas características dos campos como
o tamanho. Este formulário também possui um botão de busca de registros de
cidades (TDBSeekButton). Após criarmos os objetos, adicionamos os vários cam
pos de filtragem à tabela que estará dentro do formulário. Ao final do método
Capítulo 4 - Componentes de apresentação - amostra do livro 171
Na figura a seguir, podemos ver o gráfico gerado.
Figura 64 Gráfico de barras
app/control/Presentation/Chart/PieChartView.class.php
<?php
class PieChartView extends TPage
{
function __construct()
{
parent::__construct();
// cria o gráfico
$chart = new TPieChart(new TPChartDesigner);
$chart->setTitle('Chart title', NULL, NULL);
$chart->setSize(500, 300);
$chart->setOutputPath('app/output/piechart.png');
// adiciona as fatias
$chart->addData('maria', 40);
$chart->addData('pedro', 30);
$chart->addData('joao', 30);
$chart->generate();
ject} não será substituída simplesmente por um valor escalar (integer, string,
float), mas por um objeto instanciado a partir de um componente visual do fra
mework, como um TForm, ou TDataGrid.
app/resources/content.html
<!--[main]-->
<table class="customform" style="border:1px solid #B7B7B7">
<tr>
<td colspan="2" class="formtitle">Customer data</div></td>
</tr>
<tr>
<td width="50%">Name</td>
<td width="50%">{$name}</td>
</tr>
<tr>
<td>Address</td>
<td>{$address}</td>
</tr>
<!--[object]-->
<tr>
<td class="sectiontitle" colspan=2>Embedded object</td>
</tr>
<tr bgcolor="#e0e0e0">
<td colspan="2">A Framework object ({$name})</td>
</tr>
<tr>
<td colspan="2">{$object}</td>
</tr>
<!--[/object]-->
</table>
<!--[/main]-->
Além de renderizar o conteúdo do HTML, criaremos dois botões de ação: “Acti
on 1” e “Action 2”. Estes botões de ação serão criados via programação e não
pelo template. Na figura a seguir temos a tela inicial do programa, onde somen
te a seção main é exibida, sem o conteúdo da seção object. Os botões de ação
são vistos no topo.
Figura 68 Template View com uma seção simples habilitada
O objetivo do botão “Action 1” é habilitar a seção object, e inserir nessa seção
um formulário TQuickForm no lugar da marcação {$object}, como pode ser
visto na figura a seguir.
Capítulo 4 - Componentes de apresentação - amostra do livro 185
// exibe os dados
new TMessage('info', $message);
}
}
?>
CAPÍTULO 5
Organização e controle
Chegamos em um ponto do livro onde já aprendemos a manipular o
banco de dados, a criar interfaces com diversos componentes, mas ainda
não integramos os dois, ou seja, ainda não criamos interfaces que mani
pulam registros da base de dados. Pois o objetivo deste capítulo é justa
mente abordar a criação de interfaces com formulários, listagens, buscas,
edições para registros na base de dados por meio de padrões como Acti
ve Record e Repository.
app/control/Organization/StandardControls/StandardFormView.class.php
<?php
class StandardFormView extends TStandardForm
{
protected $form;
function __construct()
{
parent::__construct();
// cria o formulário
$this->form = new TQuickForm('form_City');
$this->form->class = 'tform'; // define a classe CSS
// cria os campos
$id = new TEntry('id');
$name = new TEntry('name');
$id->setEditable(FALSE);
function onEdit($param)
{
try
{
if (isset($param['key'])) // verifica se o parametro foi informado
{
$key=$param['key']; // obtém a chave do registro
TTransaction::open('samples'); // abre a transação
$object = new City($key); // instancia o Active Record
$this->form->setData($object); // preenche o formulário
TTransaction::close(); // fecha a transação
}
else
{
$this->form->clear(); // limpa o formulário
}
}
catch (Exception $e) // em caso de exceção
{
new TMessage('error', '<b>Error</b> ' . $e->getMessage());
TTransaction::rollback(); // desfaz operações
}
}
}
?>
Obs: Todos os métodos de manipulação de base de dados, como onSave() e onEdit(),
devem realizar as operações dentro de um bloco de controle de exceções try/catch,
pois as classes de manipulação da base de dados lançam exceções em caso de erros.
Figura 77 Controlador manual de datagrids na web
Capítulo 5 - Organização e controle - amostra do livro 215
mulário clientes, para o cadastro de novos registros, e outro que permitirá ex
portar a datagrid no formato CSV, para abertura em forma de planilha.
A datagrid terá os tradicionais botões de edição e exclusão, bem como uma pa
ginação de registros. Nas figuras a seguir, podemos conferir o resultado deste
exemplo nos ambientes web e desktop.
Figura 79 Datagrid de clientes na web
Figura 80 Datagrid de clientes no desktop
Conforme pode ser visto no códigofonte a seguir, iniciamos a criação da página
pelo formulário (TForm). Este formulário terá dois campos de buscas (name e
city_name) e três ações (TButton), que são: “Busca”, que utilizará os campos
nome do cliente ou da nome da cidade para filtrar a datagrid, por meio do mé
todo onSearch(); “Novo”, que direcionará o usuário para o formulário de ca
dastro, representado pela classe CustomerFormView, que será criada no próximo
exemplo; e “CSV”, que permite exportar os dados da datagrid neste formato,
por meio da execução do método onExportCSV().
Capítulo 5 - Organização e controle - amostra do livro 229
Para cada código retornado, é instanciado um objeto Skill para que este seja
então adicionado ao cliente por meio do método addSkill().
Por fim, o cliente é armazenado na base de dados por meio do método
store(). Quando este método é executado, as relações de composição com
contatos (Contact) e de agregação com habilidades (Skill) são tratadas inter
namente na classe Customer, o que já foi implementado no capítulo 3.
function onSave()
{
try
{
TTransaction::open('samples'); // abre a transação
// obtém os dados do formulário como um Active Record Customer
$customer = $this->form->getData('Customer');
if ($customer->contacts_list)
{
foreach ($customer->contacts_list as $contact)
{
$customer->addContact($contact); // adiciona Contact ao Customer
}
}
if ($customer->skill_list)
{
foreach ($customer->skill_list as $skill_id)
{
// adiciona o objeto Skill ao Customer
$customer->addSkill(new Skill($skill_id));
}
}
$customer->store(); // armazena o objeto na base de dados
$this->form->setData($customer);
Assim como o método onSave() teve características específicas em função dos
relacionamentos de composição e agregação da classe Customer, também o
método onEdit() terá uma implementação diferente. No caso do método onE
dit() os cuidados devem ser no momento de carregar as informações para pre
encher o formulário.
Logo após abrir a transação com a base de dados, carregamos o cliente (Custo
mer) conforme a chave do registro 'key' identificada pelos parâmetros. Em se
guida, carregamos a lista de contatos no atributo contacts_list do formulário,
por meio do método getContacts(). Com isso, estaremos preenchendo em tela
238 Amostra do livro Adianti Framework para PHP
Por fim, o método show() é sobrecarregado para garantir que a datagrid seja
carregada antes da exibição da página.
function show()
{
// verifica se a datagrid já foi carregada
if (!$this->loaded)
{
$this->onReload();
}
parent::show();
}
}
?>
Figura 87 Relação entre Projeto e Backlog (Atividades)
6 ESTUDOS DE CASO
CAPÍTULO 6
Estudos de caso
Após cinco capítulos estudando o framework, já nos sentimos prepara
dos para criar nossas primeiras aplicações, uma vez que já vimos como
manipular entidades da base de dados, criar uma interface orientada a
objetos, bem como controlar o fluxo de execução da aplicação. Entretan
to, é nesse momento que alguns aspectos vêm à tona como: login, con
trole de permissões, internacionalização, dentre outros. Estes aspectos
variam de aplicação para aplicação e, para ensinar, nada melhor do que
mostrar exemplos reais. Dessa forma, conheceremos aplicações reais de
senvolvidas com o Adianti Framework e estudaremos como elas resolve
ram essas questões.
Para acessar o sistema corretamente, preparamos para você uma tabela com os
logins que podem ser utilizados. Nesta tabela, temos três logins, sendo um para
cada papel de usuário no sistema.
Tabela 5. Logins e senhas para a aplicação Library
Papel Template
Login app/templates/theme1/login.html
Administrador app/templates/theme1/admin.html
Bibliotecária app/templates/theme1/librarian.html
Operador app/templates/theme1/operator.html
Obs: Partes significativas dos códigosfonte a seguir sofreram cortes durante a edição.
Você encontra a versão completa juntamente com o download da aplicação Library.
Basicamente a estrutura dos templates é a mesma. Dessa forma, a parte do có
digo responsável pela carga das bibliotecas jQuery, CSS e trechos de JavaScript
são exatamente iguais entre um template e outro. O que difere entre um tem
plate e outro será somente a parte responsável por exibir as opções do perfil.
No template a seguir podemos conferir o template do operador. Neste template,
destacamos em negrito as opções acessadas pelo operador. O trecho do templa
te com destaque em negrito corresponde à porção que contém as opções do
operador, que são basicamente cadastro de membros (MemberList), de catego
254 Amostra do livro Adianti Framework para PHP
Obs: Partes significativas dos códigosfonte a seguir sofreram cortes durante a edição.
Você encontra a versão completa juntamente com o download da aplicação Library.
index.web.php
<?php
include_once 'lib/adianti/util/TAdiantiLoader.class.php';
spl_autoload_register(array('TAdiantiLoader', 'autoload_web'));
...
$template = 'theme1';
if (TSession::getValue('logged'))
{
TTransaction::open('library');
$member = User::newFromLogin(TSession::getValue('login'));
if ( $member-> role -> mnemonic == 'LIBRARIAN' )
{
$content = file_get_contents("app/templates/{$template}/librarian.html");
}
else if ( $member-> role -> mnemonic == 'OPERATOR' )
{
$content = file_get_contents("app/templates/{$template}/operator.html");
}
else if ( $member-> role -> mnemonic == 'ADMINISTRATOR' )
{
$content = file_get_contents("app/templates/{$template}/admin.html");
}
TTransaction::close();
}
else
{
$content = file_get_contents("app/templates/{$template}/login.html");
}
$content = TApplicationTranslator::translateTemplate($content);
$content = str_replace('{URI}', $link, $content);
$content = str_replace('{template}', $template, $content);
$content = str_replace('{login}', TSession::getValue('login'), $content);
...
?>
O controle genérico é realizado dentro do método run() da classe TApplicati
on. Ali, podemos verificar se o usuário está logado por meio da classe TSession.
Também precisamos considerar a classe LoginForm como uma exceção, uma
vez que o usuário deve poder executála, mesmo sem estar logado, uma vez
que seu propósito é justamente realizar o login no sistema.
Obs: Como já vimos anteriormente no capítulo 2, algumas configurações são lidas do
arquivo application.ini, tais como timezone e o nome da aplicação
(APPLICATION_NAME), sendo que este último influencia diretamente no armazenamento
das sessões, que são segmentadas por aplicação.
engine.php
<?php
include_once 'lib/adianti/util/TAdiantiLoader.class.php';
spl_autoload_register(array('TAdiantiLoader', 'autoload_web'));
$ini = parse_ini_file('application.ini');
date_default_timezone_set($ini['timezone']);
define('APPLICATION_NAME', $ini['application']);
define('OS', strtoupper(substr(PHP_OS, 0, 3)));
define('PATH', dirname(__FILE__));
if ($_REQUEST)
{
// descobre a classe que está sendo requisitada
$class = isset($_REQUEST['class']) ? $_REQUEST['class'] : '';
// executa normalmente
parent::run($debug);
}
}
}
TApplication::run(TRUE);
?>
Capítulo 6 - Estudos de caso - amostra do livro 273
Figura 98 Diagrama de classes do template
Quando um usuário estiver vinculado à um grupo, automaticamente terá aces
so a todos os programas daquele grupo. Este modelo permite que se concedam
permissões de programas para grupos inteiros ou a usuários.
A princípio, quando os acessos aos programas forem somente por grupos, não é
necessário conceder programas especificamente à um usuário (por meio da
agregação SystemUser – SystemProgram). Mas esta agregação é útil, quando
desejamos conceder direitos específicos para um determinado usuário, além da
permissão que o mesmo possui por meio de seu grupo.
276 Amostra do livro Adianti Framework para PHP
Figura 101 Formulário de login
Neste caso, vamos suprimir o método construtor, onde a interface é construída,
e nos concentrar o método onLogin(), que é executado sempre que o usuário
clicar no botão “Login”. Este método inicialmente irá autenticar o usuário por
meio do método SystemUser::autenticate(). Este método recebe o login e a
senha e retorna o usuário (SystemUser) correspondente com aquele login caso
a senha seja igual a do cadastro. Caso contrário, uma exceção é lançada.
Caso o usuário seja autenticado, são obtidos os programas que o mesmo tem
acesso por meio do método getPrograms(). Estes programas são armazenados
em uma variável de sessão, por meio do método TSession::setValue(). Por
fim, caso o usuário tenha uma página de entrada (Front page) cadastrada, ele
será direcionado para esta página por meio do método TApplication::gotoPa
ge(), caso contrário, será direcionado para uma página vazia (EmptyPage).
app/control/admin/LoginForm.class.php
<?php
class LoginForm extends TPage
{
protected $form; // form
protected $notebook;
function onLogin()
{
try
{
TTransaction::open('permission');
$data = $this->form->getData('StdClass');
$this->form->validate();
// autentica o usuário
$user = SystemUser::autenticate( $data->login, $data->password );
if ($user) // se autenticou
{
$programs = $user->getPrograms(); // busca os programas que tem acesso
$programs['LoginForm'] = TRUE;
Capítulo 6 - Estudos de caso - amostra do livro 281
Figura 102 Cadastro de programas
Outro cadastro administrativo é o de grupos de usuários, que pode ser visto na
figura a seguir. Para cada grupo que cadastrarmos, será possível relacionar uma
série de programas, por meio de um componente TMultifield. É importante
lembrar que um grupo pode conter muitos programas, o que se dá pelo relacio
namento de agregação entre SystemGroup e SystemProgram.
Figura 103 Cadastro de grupos
7 DESENVOLVIMENTO ÁGIL COM STUDIO PRO
CAPÍTULO 7
Ao utilizarmos um framework para desenvolvimento de sistemas, ga
nhamos uniformidade no códigofonte, maior qualidade e padronização.
Para agilizar ainda mais o desenvolvimento de aplicações foi desenvolvi
da a ferramenta Adianti Studio Pro, uma IDE para desenvolvimento de
sistemas que automatiza a criação do códigofonte voltado ao Adianti
Framework, tornando muito mais ágil o desenvolvimento de novos siste
mas.
7.1 Introdução
7.1.1 Organização da interface
O Adianti Studio é uma IDE multiplataforma para desenvolvimento de siste
mas que conta com uma série de características, dentre as quais podem ser des
tacadas: autocomplete para PHP e para os métodos de classes do projeto, sinta
xe colorida, comparação gráfica de arquivos, bookmarks, possibilidade de cria
ção de plugins, integração com subversion, dentre outras. Na figura a seguir po
demos conferir a tela inicial do Adianti Studio Pro. Veja a seguir o significado de
cada item:
B Barra de ferramentas padrão: Contém as principais funcionalidades da
ferramenta, tais como: novo, abrir, salvar, identar, aplicar plugin, sair, etc;
C Barra de ferramentas Adianti: Contém as funções da versão “pro”, que
agilizam o processo de criação de novas aplicações;
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 291
bre os mesmos. Para que seja possível editarmos os registros de uma tabela, é
preciso que a mesma tenha as chaves primárias registradas no banco de dados.
Também podemos excluir registros, bem como criar novos registros na tabela.
Figura 116 Janela de navegação de tabela
Figura 117 Barra de ferramentas de geração de código no Adianti Studio Pro
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 295
mente derivada a partir do modelo de classes por meio de técnicas de mapea
mento objetorelacional amplamente conhecidas. Dentro do menu “Novo ban
co” da barra de ferramentas Adianti, temos a opção “A partir de um modelo
XMI”, que nos permite criar um modelo relacional por meio da linguagem SQL
a partir de um modelo de classes.
Figura 122 Menu de opções para criação do banco de dados a partir de modelo XMI
Modelos de classe são armazenados em arquivos do tipo XMI (XML Metadata
Interchange), que são arquivos XML utilizados para representar modelos de
projeto de software orientados a objetos. Arquivos XMI podem ser gerados por
ferramentas de modelagem conhecidas como: ArgoUML, Astah, Rational Rose,
StarUML, Umbrello, dentre outros. Na figura a seguir temos a representação de
um modelo de classes dentro da ferramenta StarUML. Este modelo pode ser ex
portado para o formato XMI e posteriormente importando pelo Adianti Studio
Pro para criação da base de dados.
Figura 123 Modelo de classes na ferramenta StarUML
298 Amostra do livro Adianti Framework para PHP
address TEXT,
phone TEXT,
birthdate DATE,
status CHAR(1),
email TEXT,
gender CHAR(1),
category_id INTEGER NOT NULL,
city_id INTEGER NOT NULL,
FOREIGN KEY(city_id) REFERENCES city(id),
FOREIGN KEY(category_id) REFERENCES category(id)
);
...
Obs: A partir do momento em que temos as instruções SQL necessárias para criação
do banco de dados, basta rodar estas instruções no SGBD ou mesmo na linha de co
mando por meio de utilitários como: psql, mysql ou sqlite3.
A partir do assistente de modelos
A opção “A partir do assistente de modelos”, que pode ser vista na próxima figu
ra, permitenos realizar a criação das classes de modelo da aplicação por meio
de uma tela passo a passo, também conhecida como Wizard.
Figura 127 Menu de opções para criação de novo modelo a partir de assistente
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 303
Figura 134 Menu de opções para criação de novo formulário
Ao acessarmos a opção “Novo formulário”, o assistente será aberto. Nesta pri
meira etapa, é necessário selecionar a base de dados (neste caso, library) e em
seguida o modelo (Active Record) que será manipulado pelo formulário (neste
caso, Member). Em seguida selecionamos o tipo de formulário a ser gerado:
❏ Formulário completo: criado com o formuláriopadrão (TForm) e méto
dos como onEdit() ou onSave() declarados de maneira completa;
❏ Formulário padrão: utilizará formulários rápidos (TQuickForm), bem
como controladorespadrão do framework (TStandardForm).
Figura 135 Primeira etapa do assistente de criação de formulários
306 Amostra do livro Adianti Framework para PHP
Figura 139 Menu de opções para criação de nova listagem
A partir do momento em que clicamos na opção “Nova listagem”, a janela do
assistente de criação de páginas será exibida, conforme pode ser visto na figura
a seguir. Nesta janela, precisamos indicar o banco de dados sobre o qual a lista
gem será gerada e também a classe de modelo (Active Record) que será mani
pulada pela listagem.
Em seguida, indicamos o tipo de lista que será gerada, que poderá ser:
❏ Listagem completa: utiliza os componentes padrão para criação de da
tagrids (TDatagrid, TDataGridColumn) e métodos de manipulação
como onReload() e onDelete() declarados de maneira completa;
❏ Listagem padrão: utiliza datagrids rápidas (TQuickGrid) e também
controladores padrão do sistema (TStandardList).
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 307
Com ambas opções, temos uma datagrid funcional. Ao utilizarmos a opção “Lis
tagem padrão”, a quantidade de código gerada será bem menor, uma vez que
estaremos utilizando os controladorespadrão do sistema. Entretanto, sempre
que quisermos alterar o comportamento padrão da listagem, devemos utilizar a
“Listagem completa”, uma vez que esta apresenta os métodos de manipulação
declarados de maneira completa.
Por fim, precisamos definir o nome da classe a ser gerada e também o campo
que será utilizado para filtragem da datagrid.
Figura 140 Primeira etapa do assistente de criação de listagens
Após as definições da primeira etapa do assistente de criação de listagens, é exi
bida a segunda etapa. Na segunda etapa, que pode ser vista na próxima figura,
são exibidas as colunas do modelo (Active Record) escolhido, lidas diretamente
a partir da tabela da base de dados.
Na listagem de campos devemos excluir as colunas que não desejamos que se
jam exibidas na datagrid. Para as colunas que serão exibidas, devemos editar o
seu nome (nome da coluna na tabela), rótulo correto (título da coluna), seu ta
manho em pixels, o alinhamento da coluna (esquerda, centro, direita), se a co
luna é ordenável, e também se a coluna é editável.
308 Amostra do livro Adianti Framework para PHP
Figura 141 Segunda etapa do assistente de criação de listagens
A partir das definições realizadas na segunda etapa do assistente de criação de
listagens, podemos clicar no botão “Salvar” para gerar o código da página. A
partir desse momento, o código do programa para manipulação da listagem é
gerado em memória completamente funcional e respeitando as definições reali
zadas no assistente. A partir deste momento, basta salvarmos o arquivo na pas
ta app/control com o nome indicado da classe para poder acessar suas funcio
nalidades.
Figura 142 Programa para manipulação de listagens gerado pelo assistente
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 309
Na figura a seguir, temos o resultado da execução do programa gerado pelo as
sistente de criação de listagens. Veja que a página possui um formulário de bus
cas com o campo que indicamos na primeira etapa do assistente. A listagem é
gerada com as opções de edição (que redireciona para a página de formulário)
e exclusão. Além disso, as colunas configuradas para serem ordenadas possuem
este recurso, bastando clicar sobre o título da coluna, sendo que ainda é criado
um navegador de páginas abaixo da listagem.
Figura 143 Página criada por meio do assistente de criação de listagens
Figura 144 Menu de opções para criação de novo form/list
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 313
Figura 150 Principais áreas do Studio Form Designer
A barra de ferramentas do Studio Designer contém as funcionalidades básicas
para operação de um formulário, conforme pode ser visto na figura a seguir.
Figura 151 Botões da barra de ferramentas
As funcionalidades enumeradas pela figura são:
B Novo: Cria um novo formulário;
C Abrir: Permite abrir um formulário existente na extensão .form.xml;
D Salvar: Salva o formulário atual na extensão .form.xml;
E Selecionar: Permite selecionar um objeto na tela ou movêlo;
F Excluir: Permite excluir um objeto do formulário;
G Recortar: Permite selecionar um objeto para ser recortado para a memó
ria;
H Copiar: Permite selecionar um objeto para ser copiado para a memória;
I Colar: Permite selecionar uma região para colar o objeto que está na me
mória;
314 Amostra do livro Adianti Framework para PHP
J Desfazer: Desfaz a última operação;
K Refazer: Refaz a última operação desfeita;
L Exibir grade: Exibe ou esconde o fundo em forma de grade;
M Exportar para PNG: Permite exportar o formulário como imagem;
N Gerar códigofonte: Gera o códigofonte PHP que irá controlar e exibir o
formulário desenhado.
Na figura a seguir, podemos visualizar os principais containers e widgets que
podem ser utilizados na construção de um formulário.
Figura 152 Containers e widgets disponíveis
Os containers e widgets enumerados pela figura são:
B Notebook: Permite acrescentar um container do tipo TNotebook ao for
mulário. O container poderá ter várias abas, basta clicar 2x sobre o obje
to para adicionar uma nova. Para excluir uma aba, basta clicar no botão
“x” da aba;
C Frame: Permite acrescentar um container do tipo TFrame ao formulário.
Um frame poderá ter um título (definido no painel de propriedades);
320 Amostra do livro Adianti Framework para PHP
Figura 159 Interface com vários containers criada no Studio Form Designer
No momento em que criamos um objeto da classe TUIBuilder, é como se esti
véssemos criando um TPanel, por isso em seu método construtor informamos
as dimensões do painel. A classe TUIBuilder possui alguns métodos como set
Controller(), para definir qual a classe controladora do formulário desenhado
e setForm() para definir qual o objeto formulário (TForm) ao qual a interface
faz parte.
O método responsável pela interpretação do XML é o método parseFile(), que
recebe o caminho de um arquivo XML, lê o seu conteúdo, e cria os objetos em
memória como se estes fossem instanciados manualmente pelo desenvolvedor.
Após, adicionamos o objeto TUIBuilder ao formulário por meio do método
add() e chamamos o método setFields() do formulário, para passar para o
formulário em memória, os campos lidos do formulário XML.
app/control/Presentation/Designer/DesignContainerView.class.php
<?php
class DesignContainerView extends TPage
{
private $form;
function __construct()
{
parent::__construct();
// cria o formulário
$this->form = new TForm;
try
{
// cria o painel TUIBuilder
$ui = new TUIBuilder(500, 400);
326 Amostra do livro Adianti Framework para PHP
Figura 166 Criando uma datagrid no Studio Form Designer
Após criarmos a datagrid e a paginação, precisamos acrescentar colunas à data
grid, o que é representado pelo passo 1 da figura a seguir. Além disso, precisa
mos definir um nome para cada coluna (name), o que é indicado pela seta no
passo 2. O nome da coluna é muito importante, pois como adicionamos objetos
à datagrid, o nome representa também o atributo do objeto que será apresenta
do naquela coluna da datagrid.
Figura 167 Acrescentando colunas à datagrid pelo Studio Form Designer
336 Amostra do livro Adianti Framework para PHP
Além dos campos de entrada de dados, criamos dois botões de ação. O primeiro
botão é “Save”, que será responsável por armazenar os dados do formulário
como um Active Record Customer e estará conectado ao método onSave().
Neste momento, devemos prestar atenção ao atributo Template (save.php) do
formulário de propriedades. Ao preenchermos este campo, estamos indicando
ao designer qual o códigofonte padrão que será gerado para este botão pelo
gerador de código, visto a seguir.
Figura 174 Formulário de cadastro de um novo cliente
A outra ação será “New”, que limpará os dados do formulário e estará conecta
do ao método onEdit() e utilizará o template edit.php. O método onEdit()
também será utilizado para a edição do formulário a partir da datagrid. Este
método só limpa os dados do formulário quando não recebe uma chave de re
gistro como parâmetro.
A partir do momento em que definimos as ações, podemos escrever manual
mente o controlador do formulário, ou também podemos utilizar o botão “gerar
códigofonte”, último botão da barra de ferramentas. Este botão gera o código
fonte padrão para manipulação do formulário, utilizando os templates de códi
go indicados. Para gerar códigofonte, basta selecionarmos o banco de dados e
o modelo (Active Record) manipulado, bem como indicar um nome para a clas
se controladora.
346 Amostra do livro Adianti Framework para PHP
Figura 183 Botão para acessar o Studio PDF Designer
A partir do momento em que clicamos no botão “PDF Designer”, a janela do
Designer é aberta, conforme a figura a seguir. Veja o significado de cada item:
B Barra de ferramentas: Funcionalidades básicas como novo, abrir e sal
var arquivo, configurar página, visualizar impressão, zoom, posicionar
objeto (cima e baixo), copiar, recortar, colar e excluir objeto;
C Painel de componentes: Formas que podem ser utilizadas para compor
um PDF como: Retângulo, Elipse, Texto, Imagem, Linha, além de Baseli
ne e Âncora;
D Área de desenho: Área de livre desenho de um PDF;
E Propriedades do objeto: Exibe as propriedades do objeto selecionado.
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 347
Figura 184 Principais áreas do Studio PDF Designer
Obs: Documentos criados pelo Adianti PDF Designer podem ser facilmente comple
mentados com dados via programação, o que será visto em seguida.
A barra de ferramentas do Studio PDF Designer contém as funcionalidades bá
sicas para operação de um arquivo, conforme pode ser visto na figura a seguir.
Figura 185 Botões da barra de ferramentas
As funcionalidades enumeradas pela figura são:
B Novo: Cria um novo desenho;
C Abrir: Permite abrir um desenho existente na extensão .pdf.xml;
D Salvar: Salva o desenho atual na extensão .pdf.xml;
E Configurar página: Permite alterar as propriedades da página, como for
mato (A4, A5) e orientação (retrato, paisagem);
F Visualiza impressão: Permite visualizar o resultado em PDF;
G Aumenta o zoom: Permite aumentar o zoom em 1 nível;
H Diminui o zoom: Permite diminuir o zoom em 1 nível;
I Trazer para frente: Permite mover o objeto para a frente;
350 Amostra do livro Adianti Framework para PHP
mos a presença de uma âncora. Como as âncoras são pequenas, foi colocada
uma seta no desenho a seguir para indicar a presença da mesma. Uma âncora
possui um nome e é a referência de uma localização que pode ser substituída
por um outro elemento qualquer em tempo de execução.
Obs: As âncoras representam uma posição (coordenada) no desenho. Posteriormente
podemos usar métodos da biblioteca FPDF para desenhar nestas posições.
Figura 187 Desenho com formas e textos criado no Studio PDF Designer
Para demonstrar o primeiro exemplo, vamos criar um formulário. Neste formu
lário o usuário digitará um nome qualquer. Este nome será utilizado para subs
tituir a variável {name} presente no PDF desenhado. Na figura a seguir, pode
mos conferir o formulário.
Figura 188 Formulário para geração do documento PDF
O código a seguir demonstra como foi criado o formulário. Este formulário ba
sicamente possui um campo para digitação de um nome (name) e um botão de
ação que aciona o método onGenerate() sempre que for clicado.
352 Amostra do livro Adianti Framework para PHP
function onGenerate()
{
try
{
$data = $this->form->getData(); // obtém os dados
$this->form->validate();
$file = 'app/output/pdf_shapes.pdf';
if (!file_exists($file) OR is_writable($file))
{
$designer->save($file);
parent::openFile($file);
}
else
{
throw new Exception(_t('Permission denied') . ': ' . $file);
}
Podemos conferir o resultado em PDF deste programa na figura a seguir.
Figura 189 Documento gerado com formas e textos
Capítulo 7 - Desenvolvimento ágil com Studio Pro - amostra do livro 353
7.4.3 Relatórios
No exemplo anterior, vimos como realizar pequenas substituições de texto, e
também como produzir novos elementos no PDF, com base na posição das ân
coras. O objetivo deste novo exemplo é construir um relatório com várias linhas
de dados com base em um cabeçalho desenhado em PDF.
A figura a seguir demonstra o desenho criado no Studio PDF Designer. Basica
mente construímos um retângulo com um texto em seu interior para o título, e
mais alguns retângulos para determinar os cabeçalhos das colunas. Além disso,
criamos uma pequena âncora (apontada pela seta) chamada “details”, que é
onde os dados de nosso relatório começarão a ser exibidos.
Figura 190 Relatório com cabeçalho e títulos em PDF
Para gerar este relatório, faremos um formulário simples, somente com um bo
tão de ação. Quando este botão for clicado, o método onGenerate() é executa
do. Vamos nos concentrar apenas no método onGenerate() neste exemplo. Po
deríamos fazer um formulário mais elaborado com filtros por vários campos,
mas já vimos como fazer isso no exemplo de relatórios do capítulo 4, e para o
exemplo não ficar muito extenso, vamos focar na classe TPDFDesigner.
No método onGenerate(), simplesmente abrimos uma transação com a base de
dados, e obtemos todos os clientes da mesma. Em seguida, obtemos os dados
do formulário pelo método getData(), e validamos estes pelo método valida
te(). Após instanciarmos um objeto da classe TPDFDesigner, o arquivo criado
pelo Studio PDF Designer é lido pelo método fromXml(), e gerado em memória
pelo método generate().
Após gerar o documento em memória, começamos a adicionar conteúdo dinâ
mico no documento. Para tal, usamos o método gotoAnchorXY(), para nos posi
cionarmos na âncora chamada “details”. Em seguida, definimos a fonte e a cor
do texto pelos métodos SetFont() e setFillColorRGB().
356 Amostra do livro Adianti Framework para PHP
Na figura a seguir, podemos ver o modelo construído no Studio PDF Designer
(app/reports/nfe.pdf.xml). Basicamente o modelo é constituído por uma sé
rie de retângulos alinhados e textos dentro de seus respectivos cantos superio
res. Dentro de cada retângulo, há também uma âncora, que será posteriormen
te substituída por um elemento via programação.
Neste exemplo, substituiremos as âncoras por textos fixos. Mas na prática, o
conteúdo deverá vir do banco de dados, de uma tabela que armazene as infor
mações de uma Nota Fiscal. Mas como aqui o objetivo é ensinar o uso da biblio
teca, vamos nos focar nos aspectos visuais de geração do documento.
Figura 192 Nota Fiscal desenhada no Studio PDF Designer
Para gerar a Nota Fiscal, vamos construir um formulário somente com um bo
tão para sua geração. Este formulário terá um botão para geração da Nota Fis
cal, que executa o método onGenerate(). Vamos nos concentrar neste método.
Com foi dito anteriormente, neste exemplo não serão coletados dados do banco
de dados, pois a Nota Fiscal será gerada com valores fixos. A seguir, temos o
método onGenerate(), que inicia com a interpretação do modelo da Nota Fis
cal, que está armazenada no arquivo nfe.pdf.xml, o que é realizado por meio
do método fromXml(). Em seguida, usamos o método generate() para gerar a