Integração do EzComponents com o Zend Framework.

November 9th, 2008

Introdução

Recentemente em meu trabalho foi necessário gerar alguns gráficos e então fomos estudar o que havia disponível no mercado o que nos atenderia melhor.
Encontramos o ezGraph, componente do excelente ezComponents, que atendia a todas as nossas necessidades, além de ser open-source e possuir uma licença bem amigável.

O único problema que encontramos foi que o ezComponents utiliza uma estrutura de autoloading própria e o Zend Framework também possui uma estrutura similar que é opcional, mas estávamos utilizando, que é o autoload do Zend_Loader.

O intuito deste post é mostrar como integrar o ezComponents à estrutua de desenvolvimento baseada em Zend Framework mantendo os dois mecanimsmos de autoloading funcionando em paralelo.

Mãos à obra

Para fazer esta integração, precisamos estender a classe Zend_Loader e sobre-escrever alguns métodos.
Eu normalmente crio um diretório lib em minha aplicação e posteriormente um sub-diretório onde eu coloco minhas classes derivadas das classes do Zend Framework.
Neste post, vamos entender que temos uma pasta lib devidamente incluída no include_path do PHP e as nossas classes ficam em um diretório chamado Blog. Ok?

Tendo a estrutura acima criada, vamos criar um arquivo PHP chamado Loader.php dentro do diretório Blog. O conteúdo dele deverá ficar conforme exemplo abaixo:

<?php
include_once 'Zend/Loader.php';

class Blog_Loader extends Zend_Loader
{
public static function loadClass ($class, $dirs = null)
{
parent::loadClass($class);
}

public static function autoload ($class)
{
try {
if ('ezc' == substr($class, 0, 3)) {
include_once 'Base/src/base.php';
ezcBase::autoload($class);
} else {
self::loadClass($class);
}
return $class;
} catch (Exception $e) {
return false;
}
}
}

Como podemos ver, reescrevemos o método autoload, que é o método do Zend Framework que se encarrega de realizar o autoload das classes quando necessário.
Neste método, nós verificamos a cada interceptação, se o nome da classe começa com ezc (que é o padrão adotado pelo ezComponents), se começar com ezc, o método estático autoload da classe ezcBase é invocado informando o nome da classe. A partir daí o ezComponents se encarrega de importar suas classes.

Caso não seja uma classe do ezComponents, o método loadClass da classe Zend_Loader é invocado e o Zend Framework faz o resto.
Simples não?

Para usar, no bootstraper é necessário informar que iremos usar esta classe e para fazer isso é bem simples:

<?php

// Início do seu bootstraper

// Carregando o Zend_Loader
include_once 'Blog/Loader.php';
Zend_Loader::registerAutoload('Blog_Loader');

// Final do seu bootstrapper

Agora já era, você não vai mais precisar lembrar que precisa fazer includes.

Considerações finais

Tanto o Zend Framework quanto o ezComponents possuem uma empresa que os mantém, possuem uma documentação bem feita e completa em seus respectivos sites, então o uso em conjunto dessas ferramentas podem tornar o nosso dia-a-dia mais fácil e nossos softwares mais poderosos (vamos conquistar o mundo :-) ) porque aí nos focamos mais nos nossos negócios deixando a abstração da nossa estrutura de desenvolvimento a cargo dessas ferramentas.

Existem controvérsias a respeito de se usar ou não o autoload e aí você que é responsável pela aplicação deverá colocar os pró e contras de se usar autoloading em uma balança e decidir se vale a pena ou não.

O Zend Framework pode ser encontrado em: http://framework.zend.com e o ezComponents em: http://www.ezcomponents.org/

Espero que este dica seja útil pra você.
Um abraço.

A melhor cena de filme de todos os tempos

September 30th, 2008

Pelo menos para mim, a melhor cena de filme de todos os tempos. Melhor até mesmo que qualquer cena de qualquer filme de zumbi que eu já tenha assistido :)

Eu me lembro quando eu era moleque e assistia esse filme no Corujão. Época boa…

Segue abaixo a cena da briga com os baseball furies.

De lambuja, segue abaixo a cena clássica do waaaaaaaarrioooorsss come out to plaaaaaaaayyyy:

Você também se lembra desse filme ou sou eu que tô ficando velho?

Zend_Form: Um simples tutorial

September 14th, 2008

Introdução

Depois de algum tempo sem escrever algo sobre o Zend Framework, venho hoje mostrar rapidamente um exemplo de como usar o Zend_Form e de quebra vou mostrar o Zend_Translator, que pode ser usado em internacionalização.

O Zend_Form é um componente que permite que formulários sejam criados e mantido em um objeto, aumentando produtividade e mantendo um padrão de desenvolvimento. É possível também com o Zend_Form, a implementação de formulários com herança, ou seja, você tem um formulário genérico (ex: UsuarioForm) que pode ser utilizado para criação de outros (ex: UsuarioAdminForm) que possuiriam apenas alguns campos adicionais além do form padrão.

Ele também possui componentes que permitem a utilização de todos os Filters e Validators do Zend, bem como a implementação de Componentes personalizados.

Mãos à obra

Vamos criar um formulário de contato com o Zend_Form para ser o exemplo deste tutorial. Este formulário terá os campos Nome, Email, Assunto e Mensagem.

Se fôssemos criar um formulário da maneira convencional, serial algo assim:

<html>
<body>
<head>
<title>Exemplo de form</title>
</head>
<form>
Nome: <input type="text" id="nome" name="nome">
Email: <input type="text" id="email" name="email">
Assunto: <input type="text" id="assunto" name="email">
Mensagem: <textarea rows="5" cols="5" id="mensagem" name="mensagem"></textarea>
<button id="enviar">Enviar</button>
</form>
</body>
</html>

E se fôssemos usar os Zend_View_Helpers para criar os campos, ficaria mais ou menos assim:

<html>
<body>
<head>
<title>Exemplo de form</title>
</head>
<form>
Nome: <?php echo $this->formText('nome') ?>
Email: <?php echo $this->formText('email') ?>
Assunto: <?php echo $this->formText('assunto') ?>
Mensagem: <?php echo $this->formTextare('nome', null, array('rows' => 5, 'cols' => 5)) ?>
<?php echo $this->formButton('salvar', 'Salvar') ?>
</form>
</body>
</html>

Agora vem o Zend_Form

A diferença principal entre estas duas maneiras e a maneira utilizando Zend_Form é que nós podemos definir regras de validação no servidor diretamente no objeto do form. Antes de usar o form, nós devemos criar uma classe que deriva da classe Zend_Form. Antes de criarmos o código PHP do formulário, devemos criar um diretório para guardar estas classes. Eu normalmente crio um diretório forms dentro do diretório da minha aplicação e o incluo no meu include_path. Eu já vi algumas pessoas colocando os forms dentro do diretório de models. Enfim, o Zend Framework te dá uma flexibilidade para definir o que é melhor para você. Vejamos o código do formulário, que se chama ContatoForm.php e está no meu diretório forms conforme citado acima:

<?php
class ContatoForm extends Zend_Form
{

public function __construct($options = null)
{
parent::__construct($options);
$this->generate();
}
private function generate()
{
$this->setName('contato');

$nome = new Zend_Form_Element_Text('nome');
$nome->setLabel('Nome')->setRequired(true)
->addFilter('StripTags')
->addValidator('NotEmpty');
$email = new Zend_Form_Element_Text('email');
$email->setLabel('email')->setRequired(true)
->addFilter('StripTags')
->addValidator('NotEmpty');
$assunto = new Zend_Form_Element_Select('assunto');
$assunto->setLabel('Etapa')
->setRegisterInArrayValidator(false)
->setRequired(true)
->addFilter('StripTags')
->addValidator('NotEmpty');
$arrOpcoes = array('Selecione',
'criticas'    => 'Críticas',
'sugestoes'   => 'Sugestões',
'informacoes' => 'Informações' );
$assunto->addMultiOptions($arrOpcoes);
$mensagem = new Zend_Form_Element_Textarea('mensagem');
$mensagem->setAttrib('rows', '5');
$mensagem->setAttrib('cols', '5');
$mensagem->setLabel('mensagem')->setRequired(true)
->addFilter('StripTags')
->addValidator('NotEmpty');

$submit = new Zend_Form_Element_Submit('submit');
$submit->setAttrib('id', 'salvar');
$submit->setAttrib('class', 'verde buttonBar');
$this->addElements(array($nome, $email, $assunto, $mensagem,  $submit));
}
}

Analisando o código acima, é possivel ver que utilizamos os plugins do Zend_Form para criar os campos e botão do nosso formulário,  e em cada elemento do form nós definimos o filtro StripTags e o Validator NotEmpty, que  acredito devem ter ficado claros para que que servem. :D

No campo assunto, todos os elementos do select são definidos no array $arrOpcoes, sendo o indice o value e o valor o texto. Sendo assim, é muito fácil colocar dados que estão em banco de dados no select.

No campo da mensagem, no TextArea, nós definimos os atributos rows e cols utilizando o método setAttrib. Isso vale para qualquer componente.

No final, associamos estes campos no form e o form está pronto.

Criação do Controller

Agora, vamos fazer um controller para receber estes dados:

<?php
class ExemploGridController extends Zend_Controller_Action
{
public function indexAction()
{
$this->view->titulo = 'Contato!';

$form = new ContatoForm();
$form->submit->setLabel('Enviar');
$this->view->form = $form;

if ($this->_request->isPost()) {

$formData = $this->_request->getPost();

if ($form->isValid($formData)) {
// Implementa a rotina para envio de email
} else {
// Mostra os erros e popula o form com os dados enviados
$form->populate($formData);
}
}
}

}

No Controller, nós obtemos o objeto do formulário e associamos ao objeto Zend_View, depois verificamos se a requisição é do tipo POST (se for, o form foi submetido) e então verificamos se os dados enviados são válidos (os filters e validators que colocamos no form). Se forem válidos, enviaria o email (este exemplo simula um form de contatos, lembra ? :D ) senão, popula o form e mostra as mensagens de erro. Se a requisição não for do tipo POST, o form é renderizado na tela.

No arquivo de template (index.phtml) nós apenas damos um echo no form (echo $this->form).
Abaixo teremos um screenshot do form antes de ser submetido e outra do form após ser submetido com dados incorretos para mostrar os erros retornados pelo objeto.

Form criado com Zend_FormForm criado com Zend_Form - Erros em Inglês

Se você viu a segunda screenshot, percebeu que as mensagens de erro estão em inglês, certo? Isso ocorre porque o idioma padrão para o ZF é o inglês e é aí que vai entrar o Zend_Translate, que usaremos para traduzir estas mensagens de erro.

Traduzindo as mensagens de erro

Conforme a documentação do Zend Framework, o Zend_Translate é a solução para aplicações multilinguisticas.

Existem diversas formas de se criar um objeto Zend_Translate e você pode obter maiores detalhes na documentação. Eu irei usar neste tutorial o meio que julgo ser o mais simples, que é criando o dicionário em um array e depois associar ele com o objeto Zend_Translate.

Vejamos:

Eu criei um diretório em minha aplicação chamado i18n e da mesma maneira coloquei-o no include_path. Dentro dele, o arquivo pt_Br.php foi criado e nele contém o array com as traduções.

Eu vou colocar o array aqui de maneira reduzida para não ficar muito extenso:

<?php
// Traducao para o Portugues
$portugues = array();
$portugues['isEmpty']= 'Este campo não pode ser vazio';

// Email
$portugues['emailAddressInvalid'] = 'não é um email válido no formato nome@servidor';

Como podemos ver, isEmpty e emailAddressInvalid são palavras-reservadas dos filtros usados no Zend_Form. Eu senti uma dificuldade para encontrar estas informações na documentação, até onde pesquisei esta parte ainda não havia sido documentada, então para encontrar as palavras reservadas eu tive que abrir as classes, uma a uma para traduzi-las.

Agora nós devemos associar este array com o objeto Zend_Translator para então informar ao Form que ele deve ser traduzido. Vamos lá:

// Carregando arquivo de internacionalização

include_once 'i18n.php';
$translate = new Zend_Translate('array', $portugues, 'pt_BR');
$registry->set('translate', $translate);

Eu crio o objeto Zend_Translate, passando o array $portugues que criei no arquivo i18n.php e guardo este objeto na Registry para poder ser usado posteriormente. Existem outras formas de persistir este objeto, mas eu prefiro desta maneira, então sinta-se a vontade para mudar se achar uma maneira mais conveniente para você.

No Zend_Form eu digo para ele usar este arquivo, adicionando o código abaixo no metodo init() do ContatoForm:
$translate = Zend_Registry::get('translate');
$this->setTranslator($translate);

Pronto! Agora seus erros serão traduzidos, conforme screenshot abaixo:

Form criado com Zend_Form - Erros em Português

Simples não? Uma vez criado o objeto Zend_Translate, você pode tornar esse processo de tradução dinâmico, daí o trabalho será feito apenas uma única vez.

Considerações Finais

Espero que eu tenha conseguido ser claro neste tutorial e que ele seja proveitoso para você. Aproveito para lembrar que este foi um tutorial básico, apenas uma introdução ao Zend_Form, que possui diversos recursos que não abordamos hoje. Espero em breve poder mostrá-los para vocês.

Eu estou usando o Zend_Form no meu dia-a-dia no trabalho e nossa equipe teve um aumento na produtividade muito grande.

Bem, tentem implementar um exemplo como esse e qualquer dúvida poste aqui no blog que a gente tenta se ajudar. Se tiver alguma dica adicional, deixa-e aqui também.

Vamos lá, o que está esperando para testar? :D

Abraços.