quarta-feira, 29 de abril de 2009

Agrupando Erros do Zend_Form em uma mesma linha

Toda vez que utilizamos o método isValid para validar nossos campos e emitir os erros no formulário, por padrão o ZF mostra os erros em baixo de cada Elemento, que é onde fica o decorate "Errors". E talvez gostaríamos de mostrar ao usuário os erros de uma vez só, jogando tudo em apenas uma linha.

Para isso, nós utilizaremos os decorators da classe Zend_Form.

Nosso resultado final será como a figura abaixo:


Para o nosso exemplo, a seguinte classe esta montada:


class MeuForm extends Zend_Form
{

public function __construct($options = null)
{

parent::__construct($options);

$this->setMethod(’post’);

$username=new Zend_Form_Element_Text(’login’, array(

‘required’ => true,

‘label’ => ‘Login:’,

‘filters’ => array(’StringTrim’, ‘StringToLower’),

‘validators’ => array(

‘Alnum’,

array(’Regex’,false,array(’/^[a-z][a-z0-9]{2,}$/’))

)
));

$username->removeDecorator(’Errors’);



$password=new Zend_Form_Element_Password(senha’, array(

‘required’ => true,

‘label’ => ‘Senha:’,

‘filters’ => array(’StringTrim’),

‘validators’ => array(

‘NotEmpty’,

array(’StringLength’, false, array(6))

)
));

$password->removeDecorator(’Errors’);



$save=new Zend_Form_Element_Submit(’save’, array(

‘label’ => ’Salvar’,

‘required’=> false,

‘ignore’ => true,
));


$this->addElements(array($username, $password, $save));

$this->setDecorators(array(

‘FormElements’,

‘FormErrors’,

‘Form’

));

}

}




As linhas principais da nossa mudança são as seguintes:

$username->removeDecorator(’Errors’);
$password->removeDecorator(’Errors’);

Se você não utilizar o parametro removeDecorator, com certeza os erros apareceram em baixo de cada elemento de seu formulário.
Para os erros aparecerem agrupados, o seguinte decorator foi criado:
$this->setDecorators(array(

‘FormElements’,

‘FormErrors’,

‘Form’

));

quer incrementar mais ainda?
Então no lugar de criar o decorator acima, crie o seguinte decorator:

$this->setDecorators(array(

‘FormElements’,

new Zend_Form_Decorator_FormErrors(array(

‘ignoreSubForms’=>true,

‘markupElementLabelStart’=> ‘<b>’,

‘markupElementLabelEnd’=> ‘</b>’,

‘markupListStart’=>’<div>’

‘markupListEnd’ => ‘</div>’,

‘markupListItemStart’=>’<span>’,

‘markupListItemEnd’=>’</span>’,


)),

‘Form’

));


O código acima irá colocar os "Índices" dos erros em um div e em negrito e os erros dos validators (StringLength, Alnum, NotEmpty) em uma tag span.

Tenho estudado sobre como utilizar o Dojo ToolKit no ZF. Os formulários ficam show de bola!
Espero postar sobre o Dojo ToolKit no ZF ;)

Abraços Pessoal.

sexta-feira, 24 de abril de 2009

Integrando Smarty com Zend Framework

E ai pessoal...
Dando continuidade ao aprendizado do Zend Framework, escreverei como integrar o Zend framework com o Smarty Template Engine.

Com o smarty nós conseguimos separar nossas views(Front controllers) em templates. Apesar do Zend adotar o padrão MVC (Movel View Controller), nós temos algumas limitações visuais para organizar nosso código de forma que um webdesigner reconheça ou tenha uma grande noção do que está acontecendo em cada bloco de código de nossos arquivos de layout do sistema e, pelos seguidores do Smarty, não há outro template engine melhor que ele.

Um exemplo:
Toda vez que formos mostrar valores, fazer loops e decisões em nossas páginas e juntarmos tudo ao código HTML, nós temos um visual poluido de nossos arquivos deixando a manutenção mais exaustiva, sem contar que em alguns editores usados pelos webdesigners como o Dreamweaver, a tentativa de interpretação do código do dreamweaver muitas vezes desestrutura o layout do nosso site em fase de desenvolvimento.
Uma diferença de um código sem e com Smarty.
Sem Smarty: < ?php echo $nomedavariavel ? >
Com Smarty: {$nomedavariavel}

Eu li alguns artigos explicando como integrar o Smarty com o Zend...mas não gostei. Vou postar aqui da forma que eu achei menos confusa e mais fácil para manutenção:

INSTALANDO, INSTANCIANDO E CONFIGURANDO O SMARTY

Faça o download do smarty pelo link: http://www.smarty.net/download.php
Crie um diretório chamado Smarty dentro do diretório Library da sua aplicação ZF.
Copie o conteúdo da pasta Lib do arquivo de download(Smarty) para o novo diretório criado.

Dentro do diretório application do ZF, crie os seguintes diretórios: templates, templates_c e templates_cache.


include "Zend/Loader.php";
// Instancia as classes necessárias automaticamente (inclusive a do Smarty)
Zend_Loader::registerAutoload();

//Cria objeto do smarty e configura suas propriedades
$smarty = new Smarty();
$smarty->debugging = false;
$smarty->force_compile = true;
$smarty->caching = true;
$smarty->compile_check = true;
$smarty->cache_lifetime = -1;
$marty->template_dir = './application/templates/';
$smarty->compile_dir = './application/templates_c';
$smarty->cache_dir = './application/templates_cache';
//Registra o objeto criado. É por esse registro que iremos referenciar o objeto smarty em nossos controllers
Zend_Registry::set('smarty', $smarty);


Em seu controller, crie uma variável privada chamada $smarty:
class MeuController extends Zend_Controller_Action
{
private $smarty;
...
}


Chame o smarty da seguinte forma na function init() do seu controller:
public function init(){
$this->smarty = Zend_Registry::get('smarty');
}

E dentro de suas actions, passe os valores necessários para o smarty, Ex.:
public function indexAction()
{
//Cria uma variável chamada Hello com o valor Hello Word!
$this->smarty->assign('Hello', 'Hello Word!');
//Diz ao smarty qual é seu arquivo de template para ser renderizado
$this->smarty->display('arquivo_template.tpl');
}

Não esqueça de criar seu arquivo de template(dados html) dentro do diretório templates que criamos.
Caso esteja trabalhando com módulos no Zend, vc também pode fazer isso sem problemas que funciona da mesma forma.

PLUG-IN DO SMARTY PARA ECLIPSE

Como eu uso o Eclipse, existe um Suporte do Smarty para o eclipse PDT.
Vocês podem baixar nesse endereço: http://code.google.com/p/smartypdt/
Basta descompactar o arquivo no seu diretório do eclipse.
Ele é bom para verificar erros de sintaxe do Smarty e além disso, caso não tenhamos esse plugin, o eclipse fica mostrando aqueles warnings como se fossem erros de HTML.


Bom pessoal, é isso!
Hasta luego!!
;)

quarta-feira, 22 de abril de 2009

Módulos no Zend Framework

E ai pessoal,
Há um tempo atrás eu passei um sufoco ao tentar criar a separação dos meus controllers e diretórios por módulos. Nas minhas pesquisas para resolver meu problema, verifiquei que há muitas pessoas encontrando esta dificuldade e sem soluções.
Vamos imaginar que você possui um site que terá a área default(front com os usuários) e a parte de administração - admin(front dos administradores do site). É dessa forma que veremos como criar esses módulos.
Eu fiz o teste do exemplo utilizando o XamppLite 1.7.0 e o Appserv 2.5.10.
Obs.: Caso esteja tendo problemas com o .htaccess, leia mais no final do post (Dicas).

Eu cheguei a fazer testes com o Application server, mas deu um problema com relação a segurança e redirecionamentos do .htaccess. Estou entrando em contato pelo site do application server para poder solucionar o problema, mas pelo xampplite deu tudo certo.

ESTRUTURA DE DIRETÓRIOS

Deve existir várias formas de separar os módulos. Postarei a forma que obtive sucesso após bater a cabeça.
A estrutura do nosso diretório ficará como a figura abaixo:



Note que dentro de application eu criei um diretório chamado admin e outro chamado default(marquei de vermelho), que serão nossos módulos e conterão seus próprios controllers, models e scripts.

Para cada área da administração eu criei um controller, onde vc pode inserir as Actions de add, edit, etc...Assim como os arquivos phtml.
Os nomes dos arquivos phtml precisam ser iguais ao de suas Actions. Por exemplo, dentro do Controller NoticiasController, terei as seguintes actions:
public function addAction(){...}
public function editAction(){...}
e o nome de seus templates: add.phtml e edit.phtml

É dessa forma que o Zend trabalha. Caso tenha alguma outra forma que você saiba e tenha se sentido incomodado com minha observação, pode postar um comentário que ficarei feliz de saber outra forma. :)

CONTROLLERS

Como nós separamos nosso exemplo em módulos, devemos dizer ao index.php onde ficarão esses módulos.

No seu index.php, adicione a seguinte linha:
//Cria a instrancia do front_controller
$controller = Zend_Controller_Front::getInstance();

//Indica o topo do nosso diretório. por exemplo, caso o seu endereço fique: http://localhost/sistemas/Exemplo, o seu setBaseUrl deverá ficar com o valor '/sistemas/Exemplo'. No meu caso, estarei acessando http://localhost/ex_modulo
$controller->setBaseUrl('/Ex_modulo');

// mostra os erros em modo de execução
$controller->throwExceptions(true);

//Diz onde está os controllers do nosso módulo default
$controller->setControllerDirectory('./application/default/controllers');

//Aqui nós dizemos ao ZF que existe um módulo chamado admin e que seus controllers estão no diretório passado por parâmetro.
$controller->addControllerDirectory('./application/admin/controllers', 'admin');



Note que nos diretórios de controllers eu já criei os controllers para cada área de nossa administração: IndexControllers.php, NoticiasController.php e BlogsController.php .
Quando criamos nosso projeto sem módulos, o nome da classe dos módulos no nosso caso ficaria +/- assim:

public class NoticiasController extends Zend_Controller_Action(){...}
Se você tentar executar seu projeto o Zend reclamará que ele não conseguiu achar os controllers requisitados.
Como separamos nosso projeto em módulos, as nossas classes deverão conter o nome do nosso Módulo (com a primeira letra em maiúsculo) + underline"_" + NomedomoduoloController
Ficou confuso? bom, o resultado final ficaria assim:
public class Admin_IndexController extends Zend_Controller_Action(){...}
public class Admin_NoticiasController extends Zend_Controller_Action(){...}
public class Admin_BlogsController extends Zend_Controller_Action(){...}


DICAS

1 - No seu index.php indique seus include paths do seguinte modo:
setlocale(LC_ALL, 'BRA');
date_default_timezone_set('America/Sao_Paulo');
set_include_path('.' . PATH_SEPARATOR . '..' . PATH_SEPARATOR . './library'
. PATH_SEPARATOR .'./application/default/models/'
. PATH_SEPARATOR .'./application/admin/models/'
. PATH_SEPARATOR
. get_include_path());

E para facilitar nossa vida, você pode utilizar a o autoload do Zend:

include "Zend/Loader.php";
Zend_Loader::registerAutoload();

2 - Inclua o arquivo .htaccess no diretorio raiz do seu projeto que no nosso caso é o Ex_modulo:
Arquivo .htaccess:
# Rewrite Engine config
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule !\.(gif|jpg|png|css|js|controller.php|tpl|trans.php|service.php)$ index.php

# Coloca UTF-8 como charset padrao
AddDefaultCharset iso8859-1

# Desabilita a auto insercao de escapes (\)
php_flag magic_quotes_gpc off

# Desabilita as Variaveis globais
php_flag register_globals off

No appserv e wampp, é necessário descomentar a seguinte linha no httpd.conf do apache:
LoadModule rewrite_module modules/mod_rewrite.so
se não vc vai obter o erro: Internal Server error .
O Xampplite já vem com a linha descomentada por padrão (pelo menos nessa versão).

Veja que eu inseri o Charset Iso8859-1 no arquivo htacces.
Caso você não lembre que estamos setando essa configuração no .htaccess e você quer q seu projeto rode com o charset utf8 e não lembrar de mudar no seu .htaccess, você vai ter sérias dores de cabeça procurando onde esta seu problema de CharSet.

Bom pessoal, em caso de dúvidas ou caso queiram que eu envie os arquivos do Exemplo, comentem ou me enviem e-mail que enviarei os arquivos de exemplo.

Abraços e até +

quinta-feira, 9 de abril de 2009

Upload de arquivos com Zend Framework

E ai pessoal,
Depois de um longo tempo sem escrever devido à mudança de emprego que tive, escreverei hoje sobre um framework que tenho estudado, o Zend Framework.

Lembra de quando você fazia o código para upload de arquivos do seu site e tinha uma "dor de cabeça" para obter tamanho de arquivo, verificar extensão, tamanho e etc?

O Zend já faz essa brincadeira para nós. É aquela velha história de não termos que reinventar a roda ou perder tempo criando nossas proprias classes e, além de criar, fazer testes exaustivos.
Então, pq não usar um framework de confiança e já testado?

Para este tutorial, você precisa ter uma base de como funciona o Zend Framework, como carregar(include) seus arquivos com o Zend_Loader por exemplo e saber como o Zend visualiza a estrutura de arquivos do seu projeto.
Para isso, eu indico um bom tutorial para iniciantes:

http://akrabat.com/wp-content/uploads/iniciando-com-zend-framework_130.pdf

AS CLASSES

O Zend possui uma classe Zend_File_Transfer que além de nos permitir trabalhar com uploads, também nos dá uma mão para a segurança em download de arquivos do nosso site.

Para conseguirmos indicar para onde irá nossos arquivos e checar algumas configurações, utilizaremos a classe Zend_File_Transfer _Adapter_Http

EXEMPLOS


Vamos criar um formulário que conterá um input file 'uploadedfile', que será responsável por carregar nosso arquivo (lembrando que precisamos ter o enctype preenchido sempre que formos mexer com arquivos em nossos formulários).


Arquivo:




Além de fazer o formulário de envio via HTML, podemos usar também a classe
Zend_Form_Element_File (O que eu acho melhor, veja o pq).
Exemplo:


$element = new Zend_Form_Element_File('uploadedfile');
$element->setLabel('Enviar arquivo:')
->setDestination('c:\Temp');

// Quero que o usuário envia apenas 1 arquivo
$element->addValidator('Count', false, 1);
// com o tamanho limite de 100K
$element->addValidator('Size', false, 102400);
// apenasJPEG, PNG, e GIFs
$element->addValidator('Extension', false, 'jpg,png,gif');
$form->addElement($element, 'foo');


//Setando o destino de nossos arquivos de upload (Caso use o exemplo de formulário em html)
$adapter = new Zend_File_Transfer_Adapter_Http();

$adapter->setDestination('C:\temp');

if (!$adapter->receive()) {
$messages = $adapter->getMessages();
echo implode("\n", $messages);
}


//Carregando os arquivos para o servidor
$upload = new Zend_File_Transfer();

// Retorna as informações referente ao arquivo
$files = $upload->getFileInfo();

foreach ($files as $file => $info) {
//O usuário escolheu um arquivo ou o campo esta vazio?
if (!$upload->isUploaded($file)) {
print "Pq vc nao escolheu o seu arquivo e deixou o campo vazio?";
continue;
}

// Tudo ok?
if (!$upload->isValid($file)) {
print "Desculpe, mas o arquivo $file não é o que queremos.";
continue;
}
}

//Envia para o servidor
$upload->receive();

// Obtem o nome do arquivo
$names = $upload->getFileName('
uploadedfile');

// Retorna o tamanho do arquivo
$size = $upload->getFileSize(
'uploadedfile');

// Retorna o mimetype do arquivo (Se é jpeg, gif, pdf, etc)
$type = $upload->getMimeType('
uploadedfile');


Que ajuda o Zend nos fornece né?
Bom, é isso ai!
Para dúvidas, consultem o manual da Zend:

http://framework.zend.com/manual/en/zend.file.html