Sunteți pe pagina 1din 64

ADIANTI FRAMEWORK PARA PHP

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ódigo­fon­
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');
?>

Multi­interface
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ódigo­fonte que roda em duas 
interfaces. A interface Web a maioria de vocês já conhece e a interface desktop 
é fornecida pela biblioteca Gtk, ou PHP­GTK. 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.

2.1 Instalação do ambiente


2.1.1 Ambiente Linux
Nesta  seção, será abordada a instalação dos pré­requisitos para rodar o Adianti 
Framework em Linux Ubuntu 12.04. Dessa forma, instalamos o apache, o PHP, 
bem como o suporte aos bancos de dados SQLite, PostgreSQL e Mysql. O supor­
te ao sqlite é fundamental visto que a maioria das aplicações de exemplo que 
acompanham o framework, utilizam este banco de dados.

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, certifique­se 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 PHP­GTK. Deve ser 
realizado o download do mesmo a partir do site http://php­gtk.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 encontra­se 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__));

class TApplication extends TCoreApplication


{
static public function run($debug = FALSE)
{
new TSession;
if ($_REQUEST) {
parent::run($debug);
}
}
}

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

2.4 Um controlador de página


Até esta parte do livro, vimos como construir templates, mas ainda não chega­
mos na parte que mais importa que é o conteúdo do sistema. Para isto, teremos 
capítulos inteiros mais adiante como os capítulos 4 e 5. Mas para entendermos 
melhor o funcionamento do Adianti Framework, em seguida apresentamos um 
exemplo básico de uma classe controladora. Toda classe controladora do fra­
mework é necessariamente filha de TPage ou de TWindow. As controladoras fi­
lhas de TPage são exibidas no quadro central do template e as filhas de TWindow
são sempre exibidas em uma nova janela.
Esta é a classe controladora que acompanha o framework. Sua função é exibir 
uma imagem de boas­vindas, o que é realizado pela criação de um objeto TIma­
ge. Logo em seguida este objeto é adicionado à página pelo método add().

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.

2.5 A aplicação tutor


Praticamente todos os códigos abordados neste livro integram uma aplicação 
chamada tutor. A aplicação tutor é um pequeno sistema construído com o Adi­
anti Framework que pretende demonstrar todas as suas funcionalidades. O tu­
tor não pretende ser uma aplicação para usuário final, mas apenas demonstrar 
as características do framework para desenvolvedores. Você deve instalá­lo para 
um melhor acompanhamento das lições presentes neste livro e executar os 
exemplos a medida em que vai lendo. Ele pode ser baixado pelo endereço:
http://www.adianti.com.br/framework­tutorial  

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 encontra­se 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.

3.1 Modelo utilizado


3.1.1 Modelo de classes
Ao longo deste capítulo, trabalharemos com vários exemplos envolvendo acesso 
a banco de dados. Mas antes de pensar na estrutura do banco de dados, mode­
lamos a estrutura da aplicação com seus objetos, atributos, métodos e relacio­
namentos. Para os exemplos deste capítulo, elaboramos um modelo simplifica­
do com apenas 5 classes: Customer (cliente), Category (categoria), City (cida­
de), Contact (contato) e Skill (habilidade). As relações entre os objetos são as 
seguintes:
❏ Um objeto Customer (cliente) está associado a um objeto do tipo Cate­
gory (categoria). Categoria pode ser: frequente, casual, varejista;
❏ Um objeto Customer (cliente) está associado a um objeto do tipo City
(cidade);
❏ Um objeto Customer (cliente) possui uma composição com nenhum ou 
vários objetos do tipo  Contact  (contato). Isto significa que um objeto 
36 Amostra do livro Adianti Framework para PHP

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.

3.1.2 Modelo relacional


Um modelo de classes pode ser facilmente convertido em um modelo relacional 
por meio de técnicas de mapeamento objeto­relacional (M.O.R.). A partir do 
modelo de classes exposto anteriormente, derivamos um modelo relacional 
contendo as tabelas para armazenar os objetos da aplicação. As seguintes con­
versões foram realizadas:
❏ O objeto Customer (cliente) está relacionado com Category (categoria) e 
com  City  (cidade) por meio de chaves estrangeiras (foreign key map­
ping);
❏ A relação de composição entre Customer (cliente) e Contact  (contato) 
foi mapeada por meio de uma chave estrangeira (foreign key mapping), 
uma vez que em uma relação de composição, a parte é exclusiva do ob­
jeto todo;
❏ A relação de agregação entre Customer (cliente) e Skill (habilidade) foi 
mapeada   pela   tabela   associativa   (association   table   mapping) 
customer_skill já na agregação, a parte não é exclusiva do todo.
Capítulo 3 - Modelos e persistência - amostra do livro 41

3.2.4 Abertura de transações


Na grande maioria das vezes em que iremos interagir com a base de dados, será 
por meio de objetos (veremos mais adiante). Mas mesmo assim, é interessante 
sabermos como realizar consultas de maneira manual na base de dados por 
meio do framework. Toda a interação com a base de dados ocorre dentro de 
uma transação, que é aberta e fechada por meio da classe TTransaction. Esta 
classe abre conexão com uma base de dados configurada na pasta app/config
e recebe o próprio nome do arquivo como parâmetro do método open().
A classe TTransaction possui o método get(), que retorna um objeto da classe 
PDO do PHP já instanciado. Então, neste ponto, basta utilizarmos os seus méto­
dos como query() para realizar uma consulta. 

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 tratar­se 
de uma classe nativa do PHP. Maiores informações em http://www.php.net/pdo.
42 Amostra do livro Adianti Framework para PHP

3.3 Manipulação de objetos


3.3.1 O padrão Active Record
Todos os objetos da camada de modelo de uma aplicação Adianti Framework 
são objetos Active Record. Um Active Record é um dos padrões de projeto (de­
sign patterns) mais conhecidos e implementado em praticamente todas lingua­
gens de programação orientadas a objetos. Conforme Martin Fowler, um objeto 
Active Record é:

“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

3.3.3 Criação de novo objeto


Criar novos objetos a partir do momento em que temos a classe Active Record 
definida é muito simples. Para tal, basta criarmos um objeto da classe Active Re­
cord (Customer  neste caso). A partir de então, basta indicarmos na forma de 
atributos do objeto, cada um dos campos da tabela que o objeto irá armazenar. 
Neste caso, o atributo name será utilizado para preencher a coluna de mesmo 
nome na tabela customer.
Ao final, o método store() é utilizado para armazenar o objeto na base de da­
dos, causando um INSERT no mesmo. A partir desta gravação, o objeto recebe 
um ID em memória, correspondente à chave primária da base de dados. Neste 
caso, chamadas posteriores do método store() causariam um UPDATE no banco 
de dados.

app/control/dbsamples/ObjectStore.class.php
<?php
class ObjectStore extends TPage
{
public function __construct()
{
parent::__construct();
try
{
TTransaction::open('samples'); // abre uma transação

// cria novo objeto


$giovani = new Customer;
$giovani->name = 'Giovanni Dall Oglio';
$giovani->address = 'Rua da Conceicao';
$giovani->phone = '(51) 8111-2222';
$giovani->birthdate = '2013-02-15';
$giovani->status = 'S';
$giovani->email = 'giovanni@dalloglio.net';
$giovani->gender = 'M';
$giovani->category_id = '1';
$giovani->city_id = '1';
$giovani->store(); // armazena o objeto

new TMessage('info', 'Objeto armazenado com sucesso');


TTransaction::close(); // fecha a transação.
}
catch (Exception $e)
{
new TMessage('error', $e->getMessage());
}
}
}
?>
Capítulo 3 - Modelos e persistência - amostra do livro 55

3.4 Manipulação de coleções


3.4.1 O padrão Repository
O padrão Active Record nos permite trabalhar com um objeto que representa 
uma linha do banco de dados, ou seja, ele individualiza os registros fazendo 
com que cada um seja representado por um objeto em memória. E quando de­
sejamos trabalhar com uma coleção (um conjunto) de objetos? Podemos utili­
zar o padrão Repository. O padrão Repository é implementado por uma classe 
que disponibiliza uma interface para manipular coleções de objetos como repre­
sentado pela figura a seguir.

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();

new TMessage('info', 'Records Deleted');


TTransaction::close();
}
catch (Exception $e)
{
new TMessage('error', $e->getMessage());
}
}
}
?>

3.5 Relacionamentos entre objetos


3.5.1 Associação
Associação é um relacionamento entre dois objetos onde um objeto possui uma 
referência para outro. Assim, o objeto que possui a referência pode solicitar ao 
objeto associado a realização de ações por meio da invocação de métodos.
Dentro do modelo utilizado neste capítulo, a relação de associação ocorre entre 
objetos da classe Customer e Category e também entre Customer e City. Como 
a relação é direcional, um objeto da classe Customer possui uma referência para 
um objeto Category e também City.

Figura 18 Exemplo de associação
Capítulo 3 - Modelos e persistência - amostra do livro 71

// adiciona os contatos ao cliente


$customer->addContact($contact1);
$customer->addContact($contact2);

$customer->store(); // armazena o cliente (e seus contatos)

new TMessage('info', 'Contatos adicionados');


TTransaction::close(); // fecha a transação
}
catch (Exception $e)
{
new TMessage('error', $e->getMessage());
}
}
}
?>

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.

4.1 Conceitos básicos


4.1.1 Controlador de páginas
Qualquer elemento a ser apresentado pelo Adianti Framework, seja Web ou 
desktop, deve estar contido em uma página. Para criarmos uma nova página, 
devemos criar uma nova classe. Assim, cada página a ser exibida no framework 
será uma classe. No framework existem basicamente dois controladores de pá­
ginas: TPage e TWindow. Assim, qualquer página deve ser subclasse de um des­
ses dois controladores padrão. Enquanto subclasses de TPage são exibidas den­
tro do layout do sistema, subclasses de TWindow são exibidas em uma janela so­
bre o sistema. A seguir temos o exemplo de uma página simples contendo ape­
nas uma mensagem de Hello World. No método construtor da página acrescen­
tamos seu conteúdo, por meio do método  add(). Aqui estamos utilizando o 
componente TLabel, que representa um rótulo de texto. Neste capítulo, abor­
daremos outros componentes visuais que podem ser utilizados.
78 Amostra do livro Adianti Framework para PHP

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);

// cria uma tabela para os campos


$fields_table = new TTable;
$scroll->add($fields_table);

// cria uma série de campos


for ($n=1; $n<=20; $n++)
{
$object = new TEntry('field'.$n);

// adiciona uma linha para cada campo


$row=$fields_table->addRow();
$row->addCell(new TLabel('Field:'.$n));
$row->addCell($object);
}
Capítulo 4 - Componentes de apresentação - amostra do livro 99

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.

4.4.1 Formulários rápidos


O Adianti Framework apresenta um bom nível de flexibilidade na montagem 
de formulários, o que será visto nos tópicos seguintes. Esta flexibilidade nos 
permite posicionar os elementos de um formulário com liberdade. Entretanto, 
esta flexibilidade nos faz escrever mais linhas de código. Muitas vezes precisa­
mos somente de um formulário simples com os campos organizados um abaixo 
do outro. Neste caso, podemos utilizar um componente para construção de for­
mulários rápidos, o TQuickForm.
Para melhor apresentação gráfica, um formulário pode ser “empacotado” den­
tro de outro componente, como um notebook ou um frame. Neste exemplo, cri­
aremos um formulário rápido  (TQuickForm)  e simplesmente definiremos sua 
classe CSS (tform). É importante lembrar que os objetos do Adianti Framework 
podem ser colocados dentro de diferentes containers e estes serem combinados 
em outros containers.
Capítulo 4 - Componentes de apresentação - amostra do livro 101

app/control/Presentation/Forms/FormQuickView.class.php
<?php
class QuickFormView extends TPage
{
private $form;

function __construct()
{
parent::__construct();

$this->form = new TQuickForm;


$this->form->class = 'tform'; // define a classe CSS do form
$this->form->setFormTitle('Quick form'); // define o título

$id = new TEntry('id');


$description = new TEntry('description');
$date = new TDate('date');
$list = new TCombo('list');
$text = new TText('text');

$combo_items = array();
$combo_items['a'] ='Item a';
$combo_items['b'] ='Item b';
$combo_items['c'] ='Item c';
$list->addItems($combo_items);

$this->form->addQuickField('Id', $id, 40);


$this->form->addQuickField('Description', $description, 200);
$this->form->addQuickField('Date', $date, 100);
$this->form->addQuickField('List', $list, 120);
$this->form->addQuickField('Text', $text, 120);

$this->form->addQuickAction('Save',
new TAction(array($this, 'onSave')),'ico_save.png');

parent::add($this->form);
}

Quando o botão de ação for clicado, o método  onSave()  da mesma classe é 


executado. Por padrão, todos métodos executados pelo Adianti Framework re­
cebem um vetor de parâmetros ($param), que corresponde aos parâmetros da 
URL ($_GET).
O método  onSave()  inicialmente obtém os valores digitados pelo usuário no 
formulário por meio do método  getData(). Este método retorna um objeto 
StdClass contendo os dados, onde cada atributo identifica um campo do formu­
lário. Este método recebe opcionalmente o nome de uma classe Active Record, 
que se informada designará o tipo do objeto retornado. O método setData() é 
usado para preencher o formulário novamente com os dados preenchidos, para 
que o mesmo não fique vazio após a postagem.
Após obter os dados postados, simplesmente montamos uma mensagem com 
os valores do formulário na forma de string e a apresentamos em tela por meio 
da classe TMessage.
102 Amostra do livro Adianti Framework para PHP

public function onSave($param)


{
// obtém os dados do formulário
$data = $this->form->getData();

// mantém o formulário preenchido após a postagem


$this->form->setData($data);
$message = 'Id: ' . $data->id . '<br>';
$message.= 'Description : ' . $data->description . '<br>';
$message.= 'Date : ' . $data->date . '<br>';
$message.= 'List : ' . $data->list . '<br>';
$message.= 'Text : ' . $data->text . '<br>';

new TMessage('info', $message);


}
}
?>

Na próxima figura, podemos ver o resultado da execução deste programa.

Figura 38 Formulário rápido no ambiente web

4.4.2 Formulários personalizados


No exemplo anterior vimos como construir um formulário rápido com alguns 
componentes dispostos um abaixo do outro. Entretanto, em várias situações 
precisamos de maior flexibilidade na construção de formulários, e isso será de­
monstrado neste exemplo. No exemplo anterior utilizamos a classe TQuickForm
para criar formulários e o método addQuickField() para acrescentar elementos 
ao formulário. Neste exemplo, utilizaremos a classe TForm. Esta classe não pos­
sui um método específico para adicionar elementos ao formulário. Para adicio­
nar elementos ao formulário, devemos empacotá­los em um container (TTable, 
TPanel) e então acrescentar este container ao formulário (TForm). O formulário 
110 Amostra do livro Adianti Framework para PHP

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 e­mail 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ódigo­fonte 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

4.4.5 Criando um validador


Por mais validadores prontos que existam, jamais conseguiríamos atender todas 
as necessidades que surgem durante o desenvolvimento de um sistema. Nesse 
caso, é preciso saber como criar um validador novo, o que veremos neste exem­
plo. No exemplo demonstrado a seguir, criaremos um validador de datas (TDa­
teValidator). Um validador recebe por padrão como parâmetros: um rótulo de 
texto que identifica o campo não validado na mensagem exceção; o valor pos­
tado do campo pelo formulário; e um vetor de parâmetros opcional.

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');

$year = substr($value, $year_pos, 4);


$month = substr($value, $month_pos, 2);
$day = substr($value, $day_pos, 2);

if (!checkdate((int) $month, (int) $day, (int) $year))


{
throw new Exception("O campo $label não é uma data válida ($mask)");
}
}
}
?>
138 Amostra do livro Adianti Framework para PHP

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.

4.5.1 Datagrids rápidas


Para começarmos a trabalhar com datagrids, nada melhor do que uma aborda­
gem rápida.  Existem duas maneiras  de construir datagrids no  Adianti  Fra­
mework: datagrids rápidas e datagrids personalizadas. Datagrids rápidas pro­
porcionam uma forma rápida e ágil para construir datagrids com poucas linhas 
de código, de maneira similar aos formulários rápidos (TQuickForm).
O objetivo deste exemplo é demonstrar o funcionamento das datagrids rápidas 
(TQuickGrid). Para tal, construiremos uma página com uma datagrid exibindo 
dados estáticos. Esta datagrid terá dois botões de ação. Neste exemplo veremos 
também como conectar um botão de ação de uma datagrid a um método.
Conforme pode ser visto no código­fonte a seguir, este exemplo inicia com a cri­
ação de uma datagrid rápida (TQuickGrid). Logo em seguida é determinada 
sua altura máxima (desktop). Após, são acrescentadas as colunas da datagrid 
por meio do método addQuickColumn(), com os parâmetros: Título da coluna, 
nome do atributo a ser exibido, alinhamento e largura em pixels. As datagrids 
foram concebidas para exibir objetos, sendo um em cada linha. Assim, o segun­
do parâmetro representa o nome atributo que será exibido naquela coluna.

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;

public function __construct()


{
parent::__construct();

// cria a datagrid
$this->datagrid = new TQuickGrid;
$this->datagrid->setHeight(260);

// adiciona colunas à datagrid


$this->datagrid->addQuickColumn('Code', 'code', 'right', 70);
$this->datagrid->addQuickColumn('Name', 'name', 'left', 180);
$this->datagrid->addQuickColumn('Address', 'address', 'left', 180);
$this->datagrid->addQuickColumn('Phone', 'fone', 'left', 180);

// adiciona ações à datagrid


$this->datagrid->addQuickAction('View',
new TDataGridAction(array($this, 'onView')),
'name', 'ico_find.png');
$this->datagrid->addQuickAction('Delete',
new TDataGridAction(array($this,
'onDelete')), 'code', 'ico_delete.png');
// cria o modelo da datagrid em memória
$this->datagrid->createModel();

// acrescenta a datagrid à página


parent::add($this->datagrid);
}

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

// adiciona demais objetos


}

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

// cria uma string com as opções selecionadas


$message = 'Check 1 : ' . $data->check1 . '<br>';
$message.= 'Check 2 : ' . $data->check2 . '<br>';
$message.= 'Check 3 : ' . $data->check3 . '<br>';
$message.= 'Check 4 : ' . $data->check4 . '<br>';

// 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

4.5.7 Datagrids com campos de entrada


Neste exemplo, será demonstrado como criar uma datagrid com campos de en­
trada de dados (TEntry). Já vimos como criar uma datagrid com checkbuttons 
e neste caso, o procedimento é parecido.
No método construtor, a datagrid (TQuickGrid) é construída com quatro colu­
nas (Code, Name, Address, e Phone). É importante notar que para que o envio 
de dados funcione, a datagrid precisa estar dentro de um formulário (TForm). 
Capítulo 4 - Componentes de apresentação - amostra do livro 159

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.6.2 Passo a passo entre formulários diferentes


No exemplo anterior, vimos como criar um formulário passo a passo formado 
por um notebook (TNotebook) com três abas. Apesar de simular o funciona­
mento de um passo a passo, o exemplo anterior era formado por um único for­
mulário, que apresentava diferentes informações conforme a etapa requerida 
por meio da troca da aba a ser exibida do notebook. Nem sempre um único for­
mulário é suficiente para construir uma tela passo a passo, sendo que em mui­
tos casos precisamos enviar a informação entre múltiplos formulários, ou seja, 
passar os dados preenchidos de uma tela para outra. O objetivo deste exemplo 
é demonstrar como criar uma navegação, com botões de avançar e retroceder, 
entre diferentes formulários.
O primeiro formulário tem como objetivo coletar os dados de login de um usuá­
rio (e­mail e senha). Esta tela direcionará o usuário para um próximo formulá­
164 Amostra do livro Adianti Framework para PHP

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

4.8.3 Gráfico de pizza


Gerar um gráfico de pizza difere pouco dos exemplos anteriores. Para criar o 
gráfico, em primeiro lugar devemos instanciar um objeto da classe TPieChart. 
Em seguida, podemos chamar alguns métodos já vistos anteriormente como: 
setTitle() para definir o título do gráfico; setSize() para definir suas dimen­
sões; e setOutputPath() para definir o caminho do arquivo gerado.
No gráfico de pizza não adicionamos séries de dados, e sim fatias. Cada fatia 
tem um determinado valor. Para adicionar uma fatia ao gráfico, podemos utili­
zar o método addData(), que recebe como parâmetros: o nome da fatia, e seu 
valor correspondente. Por fim, o gráfico é gerado pelo método generate().

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();

// adiciona o gráfico na página


parent::add(new TImage('app/output/piechart.png'));
}
}
?>
178 Amostra do livro Adianti Framework para PHP

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

public function onSave($param)


{
$data = $this->form->getData(); // obtém os dados do form
$this->form->setData($data); // mantém o form preenchido

// cria uma string com os dados do form


$message = 'Id: ' . $data->id . '<br>';
$message.= 'Description : ' . $data->description . '<br>';
$message.= 'Date : ' . $data->date . '<br>';
$message.= 'Time : ' . $data->time . '<br>';
$message.= 'Number : ' . $data->number . '<br>';
$message.= 'Text : ' . $data->text . '<br>';

// exibe os dados
new TMessage('info', $message);
}
}
?>

4.9.5 Criando novos componentes


Mesmo que o framework ofereça uma série de componentes, chegará o mo­
mento em que precisaremos de algo mais. Nesta situação, é importante que sai­
bamos estender o framework, acrescentando­o novos componentes. O objetivo 
deste exemplo é criar um componente que utiliza o jQuery Accordion. Um ac­
cordion divide a tela em várias porções, criando um efeito “acordeão”, com bo­
tões que podem ser clicados, expandindo uma área até então não visível. Para 
criar um elemento, na maioria das vezes podemos estender a classe TElement, 
que é base para todos elementos HTML.
No método construtor, chamamos o construtor da classe­pai, passando 'div'
como parâmetro, dizendo que o elemento que desejamos construir é um <div>. 
Nesse momento também definimos o ID do elemento e inicializamos o vetor 
elements, que armazenará os elementos do Accordion.
O método appendPage() é responsável por adicionar um objeto ao Accordion. 
Para tal, ele recebe o título, e o próprio objeto a ser adicionado. Já o método 
show() é responsável por exibir o conteúdo do componente. Para tal, ele per­
corre os elementos­filho (elements) um a um, adicionando­os no elemento­pai. 
Em seguida, é executado um script que chama a função accordion() da jQuery 
sobre o ID do objeto ($this->id), aplicando o efeito desejado.
5 ORGANIZAÇÃO E CONTROLE

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.

5.1 Controladores padrão


Vamos começar a abordar a criação de formulários e datagrids para manipula­
ção de registros de forma ágil. Para tal, o Adianti Framework disponibiliza con­
troladores padrão. Mas o que é um controlador padrão? Um controlador pa­
drão é uma classe que pode ser utilizada como base para criação de páginas 
como formulários e datagrids que já contém uma série de funcionalidades, faci­
litando muito a vida do desenvolvedor. Com um controlador padrão é possível 
criar um cadastro completo com poucas linhas de código.

5.1.1 Controlador de formulário


Para começar, vamos criar um formulário para edição de registros de cidades 
(City) utilizando o controlador padrão de formulários:  TStandardForm. Este 
controlador permite criar um formulário de cadastro com poucas linhas de có­
digo, uma vez que já contém definidos de maneira genérica, métodos para sal­
vamento e edição de registros. Nas próximas duas figuras, podemos ver o resul­
tado da execução deste exemplo nos ambientes web e desktop.
Capítulo 5 - Organização e controle - amostra do livro 191

app/control/Organization/StandardControls/StandardFormView.class.php
<?php
class StandardFormView extends TStandardForm
{
protected $form;
function __construct()
{
parent::__construct();

// define a base de dados


parent::setDatabase('samples');

// define o active record


parent::setActiveRecord('City');

// cria o formulário
$this->form = new TQuickForm('form_City');
$this->form->class = 'tform'; // define a classe CSS

// define o título do form


$this->form->setFormTitle('Standard Form');

// cria os campos
$id = new TEntry('id');
$name = new TEntry('name');
$id->setEditable(FALSE);

// adiciona os campos no formulário


$this->form->addQuickField('id', $id, 100);
$this->form->addQuickField('name', $name, 100);

// define as ações do formulário


$this->form->addQuickAction('Salva', new TAction(array($this, 'onSave')),
'ico_save.png');

$this->form->addQuickAction('Novo', new TAction(array($this, 'onEdit')),


'ico_new.png');

$this->form->addQuickAction('Lista', new TAction(array('StandardDataGridView',


'onReload')), 'ico_datagrid.gif');

// adiciona o formulário à página


parent::add($this->form);
}
}
?>

5.1.2 Controlador de datagrid


Agora que já aprendemos a criar um formulário de maneira rápida, vamos criar 
uma datagrid com poucas linhas de código. Para tal, vamos utilizar um contro­
lador padrão chamado  TStandardList. Este controlador contém implementa­
dos de maneira genérica os métodos mais utilizados na manipulação de data­
grids, como as opções de busca, carregamento de registros e exclusão. Nas pró­
ximas duas figuras, podemos ver o resultado da execução deste exemplo nos 
ambientes web e desktop.
202 Amostra do livro Adianti Framework para PHP

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.

5.2.2 Controlador de datagrid


Agora que já entendemos como construir um formulário completo, sem o auxí­
lio de controladores padrão do sistema, faremos o mesmo com uma datagrid. O 
objetivo deste exemplo é construir uma datagrid completa, com busca, edição e 
exclusão de registros de cidades (City) com os controladores totalmente pro­
gramados manualmente. Nas próximas duas figuras, podemos ver o resultado 
da execução deste exemplo nos ambientes web e desktop.

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ódigo­fonte 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);

new TMessage('info', 'Record saved');


TTransaction::close(); // fecha a transação
}
catch (Exception $e) // em caso de exceção
{
new TMessage('error', '<b>Error</b>' . $e->getMessage());
TTransaction::rollback(); // desfaz as operações
}
}

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();
}
}
?>

5.3.5 Tela de edição Mestre-Detalhe


Mestre­detalhe ou Master­detail é como frequentemente são chamadas telas 
que permitem a edição de um registro­pai, e a partir deste, permite também a 
edição de registros­filhos, que nada mais são do que registros de outras tabelas 
vinculados ao registro principal. Como exemplo de telas Mestre­detalhe, pode­
mos citar: um curso e suas disciplinas; um produto e seus estoques em diferen­
tes filiais; Um livro e seus exemplares; Um projeto e suas atividades. Em todos 
estes casos devemos ter a possibilidade de editar o registro principal e os regis­
tros­filhos relacionados, partindo de uma mesma tela.
Nestes casos, usar uma simples TMultifield (solução adotada para a composi­
ção entre Cliente e Contato) não resolveria, pois os registros relacionados (Con­
tato) são apagados e reinseridos sempre que editamos o registro­pai (Cliente). 
Na relação entre Cliente e Contato isso não era um problema, pois não existem 
outras tabelas no sistema que dependem de Contato (possuem chave estrangei­
ra para ela). Mas no caso de um Projeto e suas atividades (Backlog), a relação 
será modelada como uma associação (de Atividade para Projeto), pois certa­
mente existirão no sistema outras tabelas que estarão vinculadas à atividade, e 
não podemos apagar e reinserir as atividades sempre que editarmos o projeto.

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.

6.1 Aplicação Library


A primeira aplicação que vamos estudar chama­se Library (biblioteca). O objeti­
vo desta aplicação é fornecer os controles mínimos que uma biblioteca precisa 
para funcionar, sempre visando a demonstração do framework. Esta aplicação 
não tem como objetivo ser um sistema completo para gerenciamento de biblio­
tecas, uma vez que já existem inúmeros softwares com essa finalidade.
A aplicação Library fornece algumas funcionalidades como a catalogação de li­
vros, a classificação de livros, cadastro de leitores, autores, assuntos e editoras, 
empréstimo e devolução de livros, relatórios de livros, leitores e empréstimos, 
cadastro de usuários e de permissões.
A aplicação Library merece destaque pois ela possui diferentes perfis de usuári­
os, sendo que cada perfil possui acesso a um grupo de funcionalidades do siste­
ma. Poderemos ver melhor as funcionalidades acessadas por cada ator no dia­
Capítulo 6 - Estudos de caso - amostra do livro 251

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

Usuário Login Senha Papel


Administrator admin admin Administrador
Ana Librarian ana test Bibliotecária
Luciele Operator luciele test Operador

6.1.6 Separação de templates


Cada perfil de usuários (administrador, bibliotecária, operador) ao efetuar o lo­
gin no sistema, deve visualizar somente as opções que lhe competem (conforme 
o diagrama de Casos de Uso visto anteriormente). Para carregar diferentes visu­
alizações, no Library foram utilizados diferentes templates, sendo um para cada 
perfil de usuário. A tabela a seguir mostra a localização do template utilizado 
para cada perfil.
Tabela 6. Templates da aplicação Library por papel de usuário

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ódigos­fonte 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ódigos­fonte 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);
...
?>

6.1.8 Controlador de login


Na medida em que o usuário acessar o sistema pela primeira vez, terá acesso ao 
formulário de login, carregado por meio do seu respectivo template de login 
(login.html). Basicamente o formulário de login é um formulário comum com 
três campos: usuário, senha e linguagem. Dessa forma, além de realizar a au­
tenticação, o usuário poderá escolher o idioma da interface.
A tela de login será formada basicamente por um notebook (TNotebook), que 
irá conter um formulário (TForm), e este, uma tabela (TTable) com os campos 
de entrada de dados. Após, os campos são acrescentados à tabela e é criado um 
botão de ação para realizar o login, sendo que o mesmo está conectado ao mé­
todo onLogin().
258 Amostra do livro Adianti Framework para PHP

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__));

class TApplication extends TCoreApplication


{
static public function run($debug = FALSE)
{
new TSession;

$lang = TSession::getValue('language') ? TSession::getValue('language') : 'en';


TAdiantiCoreTranslator::setLanguage($lang);
TApplicationTranslator::setLanguage($lang);

if ($_REQUEST)
{
// descobre a classe que está sendo requisitada
$class = isset($_REQUEST['class']) ? $_REQUEST['class'] : '';

// controle de acesso genérico


if (!TSession::getValue('logged') AND $class !== 'LoginForm')
{
echo TPage::getLoadedCSS();
echo TPage::getLoadedJS();
new TMessage('error', 'Not logged');
return;
}

// executa normalmente
parent::run($debug);
}
}
}

TApplication::run(TRUE);
?>
Capítulo 6 - Estudos de caso - amostra do livro 273

6.3.2 Diagrama de classes


Na próxima figura, temos o diagrama de classes do sistema, com as classes da 
camada de modelo (app/model). A seguir, temos uma lista com as classes Active 
Record:
❏ SystemUser: Representa um usuário do sistema. Um usuário poderá ter 
agregação   com   grupo   (SystemGroup)   e   com   programa 
(SystemProgram).  Isto significa que um usuário poderá possuir vários 
grupos e vários programas;
❏ SystemGroup: Representa um grupo de usuários. Um grupo tem agrega­
ção com programa (SystemProgram). Isto significa que um grupo pode­
rá possuir vários programas;
❏ SystemProgram:   Representa   um   programa.   Um   programa   possui   um 
nome (name) e uma classe de controle  (controller). O atributo  con­
troller deve ser preenchido com o nome da classe de controle (classe 
filha de TPage), que desejamos dar acesso a alguém ou um grupo.

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

6.3.5 Tela de Login


Na medida em que o usuário acessar o sistema pela primeira vez, terá acesso ao 
formulário de login. Basicamente o formulário de login é um formulário co­
mum com dois campos: usuário e senha.

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

6.3.8 Telas de administração


O Template ERP já acompanha uma série de cadastros que permitem definir as 
permissões da aplicação. Para acessá­los, basta realizar login no sistema com o 
usuário admin, cuja senha já foi apontada anteriormente.
O primeiro cadastro é o de programas. Nesse cadastro, deveremos registrar 
cada classe (página) criada para o sistema, dando um nome, e apontando sua 
classe. As classes de administração (iniciam com System*), já estão cadastradas.

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

Desenvolvimento ágil com o Adianti


Studio Pro

Ao utilizarmos um framework para desenvolvimento de sistemas, ga­
nhamos uniformidade no código­fonte, 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ódigo­fonte 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 multi­plataforma 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

7.2 Geração de código


O Adianti Studio Pro adiciona um conjunto de funcionalidades em relação ao 
Adianti Studio Standard. Estas funcionalidades são voltadas a dar maior agili­
dade   no   desenvolvimento   de   aplicações   desenvolvidas   para   o   Adianti   Fra­
mework. Na figura a seguir podemos ver em destaque a barra de ferramentas 
Adianti. Esta barra de ferramentas contém algumas funcionalidades voltadas 
para agilizar a criação de aplicações Adianti Framework. Dentre as funcionali­
dades, podem ser destacadas a geração automática das classes de modelo e de 
páginas, baseadas em wizards.

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 objeto­relacional 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.

7.2.3 Criando as classes modelo


O Adianti Studio Pro permite a geração automática das classes de modelo da 
aplicação de duas maneiras: A partir do assistente de modelos e a partir de um 
modelo XMI. O assistente de modelos, que pode ser acessado pela opção “A par­
tir do assistente de modelos” é uma tela passo a passo que permite o usuário 
gerar a classe de modelo de maneira automatizada, cadastrando os relaciona­
mentos entre as classes por meio da interface. Quando temos um modelo de 
classes pronto no formato XMI, podemos importar este modelo para a ferra­
menta e gerar as classes de modelo por meio da opção “A partir de um modelo 
XMI”. Ambas opções estão presentes no menu “Novo modelo” da barra de fer­
ramentas Adianti.

A partir do assistente de modelos
A opção “A partir do assistente de modelos”, que pode ser vista na próxima figu­
ra, permite­nos 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

7.2.4 Criando formulários


O Adianti Studio Pro permite a criação de formulários e listagens com apenas 
alguns cliques por meio dos assistentes de criação de páginas. Como pode ser 
visto na figura a seguir, por meio do menu “Nova página” localizado na barra 
de ferramentas Adianti, temos as opções para criação de formulários e lista­
gens. Inicialmente criaremos uma página contendo um formulário por meio da 
primeira opção (Novo formulário). 

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ário­padrã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 controladores­padrão do framework (TStandardForm).

Figura 135 Primeira etapa do assistente de criação de formulários
306 Amostra do livro Adianti Framework para PHP

7.2.5 Criando listagens


Além de automatizar o processo de criação de formulários, podemos também 
criar listagens de maneira ágil. Por meio da opção “Nova listagem”, presente no 
menu “Nova página” da barra de ferramentas Adianti, temos acesso a um assis­
tente de criação de listagens.
As listagens geradas por meio do assistente são totalmente funcionais e apre­
sentam funções como: edição de registros (redirecionamento para formulário); 
exclusão de registros; ordenamento de campos e filtragem.

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 controladores­padrã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

7.2.6 Criando formulários com listagens


Além de criar controladores para formulários e listagens, também podemos cri­
ar páginas com formulários e listagens atuando conjuntamente. Esta aborda­
gem pode ser acessada pela opção “Novo form/list” no menu Nova página.

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ódigo­fonte: Gera o código­fonte 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ódigo­fonte 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ódigo­fonte”, ú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ódigo­fonte, 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

7.4 Studio PDF Designer


7.4.1 Introdução
No capítulo 4 vimos como gerar relatórios tabulares, o que se demonstrou ser 
uma tarefa bastante simples, em virtude de termos um conjunto de classes 
(TTableWriterHTML,  TTableWriterPDF, e  TTableWriterRTF) que facilitam bas­
tante o trabalho, abstraindo detalhes das bibliotecas reais usadas na construção 
deste tipo de documento.
Entretanto, em algumas situações precisamos lidar com documentos mais com­
plexos como: diplomas, notas fiscais, recibos, dentre outros, que precisam de 
um visual mais elaborado e a utilização de elementos visuais (formas) como re­
tângulos, elipses e um refinamento maior no posicionamento destes objetos.
Pensando na facilidade de criação de documentos, o Studio Pro disponibiliza o 
Studio PDF Designer, uma ferramenta voltada para o desenho de documentos 
para o Adianti Framework, que pode ser acessado por meio do botão “PDF De­
signer” da barra de ferramentas Adianti, como pode ser visto na figura a seguir.

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();

$designer = new TPDFDesigner;


$designer->fromXml('app/reports/forms.pdf.xml'); // lê o XML
$designer->replace('{name}', $data->name ); // substitui o texto
$designer->generate(); // gera

$designer->gotoAnchorXY('anchor1'); // posiciona na âncora


$designer->SetFontColorRGB('#FF0000');
$designer->SetFont('Arial', 'B', 18);
$designer->Write(20, 'Dynamic text !'); // escreve o texto

$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);
}

new TMessage('info', 'Report generated. Please, enable popups...');


}
catch (Exception $e)
{
new TMessage('error', '<b>Error</b> ' . $e->getMessage());
TTransaction::rollback();
}
}
}
?>

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 

S-ar putea să vă placă și