Beruflich Dokumente
Kultur Dokumente
(parte 1)
Seg, 05 de Setembro de 2005 10:17 Matheus Mendes
Continuando a série de tutoriais que começaram com o Mambo 4.5.2 e agora continuarão para as versões do
Joomla! aqui está a primeira parte (de 3) explicando como fazer um componente para o recém-nascido CMS.
{mosauthorinfo} Este tutorial foi divido em 3 partes e pretende abordar os conceitos básicos da construção de um
simples (porém útil) componente para joomla. O exemplo utilizado será um componente de catálogo aonde o
administrador poderá enviar imagens através de um formulário e depois poderá cadastrar produtos e vincular um
produto a uma imagem (ou vários produtos a uma imagem). Esses produtos serão listados e haverá a
possibilidade do visitante selecionar quais ele tem interesse e depois envie um e-mail ao proprietário do site.
- Primeiro iremos abordar os aspectos básicos: o arquivo de instalação, as classes de banco de dados, arquivos
de controle, menus e design.
- Na segunda parte, iremos avançar um pouquinho e adicionaremos o recurso de envio de imagem e atribuição de
uma imagem a um produto.
- Na terceira e última parte, adicionaremos o recurso de ordenação e faremos um front-end para o nosso
componente.
É evidente que mesmo um tutorial longo como esse, não aborda todos os recursos que podem ser empregados em
um componente, mas a idéia é que se tenha um ponto de partida. Como em todos os outros tutoriais, a idéia não é
ensinar ninguém a programar em PHP pois há muito material na internet com esse propósito. O tutorial foi escrito
partindo do princípio de que o leitor está habituado com a programação PHP e quer começar a programar
componentes para joomla. (uma leitura prévia dos tutoriais anteriores é recomendável porém não é obrigatória).
Como a idéia é que ao final de cada parte você tenha um componente pronto para rodar para que você possa ver
o seu progresso, eu criei três componentes (um para cada etapa) e os aspectos já explicados não serão
abordados novamente.
Este nosso primeiro componente conterá apenas arquivos básicos. O 'mínimo' necessário para se fazer um
componente descente para joomla (a idéia é fazer um componente que seja compatível com os padrões adotados
pela equipe de desenvolvedores e que seja fácil de manter)
- admin.pedidos.php - Arquivo que será chamado quando nosso componente for acessado na parte administrativa
do site. Este arquivo deverá controlar todas as ações do componente.
- admin.pedidos.html.php - Arquivo que conterá as telas do componente. O modo encontrado de separar o código
do design (as últimas versões do joomla já permitem que seja utilizado o patTemplate).
- pedidos.class.php - Este arquivo conterá as classes abstratas que ligarão o nosso componente ao banco de
dados.
- toolbar.pedidos.php - Assim como o admin.pedidos.php controla os eventos do componente. Este arquivo
controla os menus.
- toolbar.pedidos.html.php - Este arquivo conterá as chamadas dos menus para cada parte do menu e será
chamado pelo toolbar.pedidos.php.
- pedidos.xml - O arquivo responsável pela instalação, nele serão armazenadas todas as informações (arquivos,
imagens, sql, menus,...) que possibilitarão que o componente seja instalado.
- install.pedidos.php - Arquivo que será chamado ao final da instalação do componente.
- uninstall.pedidos.php - Arquivo que será chamado quando o componente for removido.
Não se preocupe em copiar e colar os códigos pois uma versão .zip do componente estará disponível para
download no final deste tutorial.
admin.pedidos.php
Este arquivo será o cérebro do nosso componente. Todas as ações que forem executadas na parte administrativa
referentes ao nosso componente, o joomla irá passar para este arquivo. Perceba que todas as ações são
direcionadas para este arquivo, ou seja, as variáveis serão utilizadas em diversas funções e as vezes com
propósitos diferentes (explico isso no decorrer do tutorial).
O bloco a seguir determina quais as ações o nosso componente terá. (nas próximas partes você verá que este
bloco será incrementado conforme o nosso componente possuir mais funcionalidades (dã!). Por enquanto só
temos a parte do produto. Então vamos lá (como o bloco está bem comentado, não irei me ater a comentar linha-a-
linha pois a única coisa que ele faz é chamar as funções que terão responsabilidade sobre as ações):
switch ( $task ) {
/* - - - P R O D U T O S - - - */
/* listar produtos */
case 'list_produtos':
list_produtos( $option );
/* para o list só preciso passar o nome do meu componente. */
break;
/* inserir produto */
case 'new_produtos':
mnt_produtos( 0, $option );
/* um novo produto, nada mais é do que a edição de um produto com o id zero. Ou seja,
se eu passar um id que não existe, o joomla irá criá-lo. */
break;
/* manutenção de produtos (alterar) */
case 'mnt_produtos':
mnt_produtos( $id, $option );
/* estou passando o valor $id (veja que este valor foi resgatado no início do código) */
break;
/* armazenar no banco, os dados de um produto. */
case 'save_produtos':
save_produtos( $option );
/* por que não estou passando o id que eu quero salvar?! :D depois eu te conto. */
break;
/* apagar um ou mais produtos */
case 'rm_produtos':
rm_produtos( $cid, $option );
/* veja que estou usando $cid pois poderá ser mais de um id ;P */
break;
}
Agora que já sei o que eu devo fazer... vamos ver COMO fazer. A primeira situação de acordo com o nosso switch é
listar os produtos já cadastrados. (é interessante manter a mesma ordem das funções para facilitar a manutenção)
O objeto $database contém as informações referentes ao banco de dados. e do objeto $mainframe nós iremos
utilizar os métodos para construir a nossa paginação (esta classe possui diversos métodos úteis para a
programação
de componentes)
$arrProdutos = $database->loadObjectList();
Agora eu pego o resultado e jogo tudo pra dentro de um vetor que irá conter os dados dos produtos. (por
padrão, os elemtnso do vetor são tratados como objetos.
A segunda função fará a manutenção de produtos (por manutenção entenda inserção e edição). Ele vai trazer do
banco
os dados referente ao id que for passado para ela.
function mnt_produtos( $id=0, $option ) {
global $database; // novamente nosso objeto com as informações do banco.
$lista = array(); // bom, eu esqueci de tirar a parte das imagens daqui. Isso será visto no segundo tutorial.
Pronto, agora que já montei as telas que listam os ítens já inscritos, e a tela de manutenção, está faltando a função
que irá salvar os dados que foram digitados na tela de manutenção montada acima. E esta função é extremamente
fácil de ser implementada:
if (!$obj->bind( $_POST )) {
echo "<script> alert('".$obj->getError()."'); window.history.go(-1); </script>n";
exit();
}
Bom, o método bind(array) vai 'ligar' cada atributo do objeto ao valor da chave de um array (associativo),
exemplo, o $obj->id valerá $_POST['id']. (note que ligar não quer dizer que esta informação já foi armazenada no
banco)
if (!$obj->check()) {
echo "<script> alert('".$obj->getError()."'); window.history.go(-1); </script>n";
exit();
}
O método check é chamado após o bind() para verificar se deu tudo certo na hora de ligar o objeto ao vetor.
Na verdade este método existe para ser sobreescrito pelas classes que herdem a mosDBTable para verificar a
consistência do objeto aonde as informações foram carregadas.
if (!$obj->store()) {
echo "<script> alert('".$obj->getError()."'); window.history.go(-1); </script>n";
exit();
}
Agora sim, pego o objeto ($obj) e armazeno este objeto no meu banco de dados. (insert? update? nããoo..
deixa o joomla cuidar disso!) Lembre-se que ele sabe a qual tabela inserir pois estamos usando o objeto da classe
mosProdutos e como você verá mais adiante, esta classe já contém essas informações.
mosRedirect("index2.php?option=$option&task=list_produtos" );
Pronto! Agora eu redireciono o usuário para uma página qualquer. Normalmente é a página do LIST pois a
função save é sempre chamada pela manutenção (veja a explicação dos menus mais tarde) e o usuário vai querer
ver o novo ítem que foi inserido!
Certo. Recapitulando: Já listamos, modificamos, inserimos e atualizamos os ítens. O que está faltando? Apagar :P
Então vamos à nossa função que irá apagar um *vetor* de ítens (como faremos um checkbox ao lado do list, o
número de ítens a serem apagados poerá ser mais de um).
if (count( $cid )) {
$cids = implode( ',', $cid );
Utilizo a função 'implode' pois preciso transformar meu vetor em uma string separada por vírgulas para
poder fazer toda a exclusão em um sql apenas.
$query = "DELETE FROM #__joomla_produtos"
. "n WHERE id IN ($cids)" ;
essa será minha sql.
$database->setQuery( $query );
ainda não executei! Apenas passei a minha string que será a sql, para o objeto do banco de dados.
if (!$database->query()) {
echo "<script> alert('".$database->getErrorMsg()."'); window.history.go(-1); </script>n";
}
agora sim. Acabou-se o que era doce. Os ítens foram excluídos.
}
mosRedirect("index2.php?option=$option&task=list_produtos" );
Agora redirecionamos o nosso usuário para uma tela amigável (de preferência aonde ele possa ver o efeito de
sua última ação)
}
Pronto! O Cérebro de nosso componente está feito. Vamos nos preocupar um pouco com as telas agora
Você deve ter notado que por diversas vezes nós chamamos uma classe abstrata HTML_pedidos e você
provavelmente ficou se perguntando o que ela faz não é? Pois bem, ela será a responsável por receber os dados e
desenhar as telas da parte administrativa do nosso componente. Sim, só isso. Ela existe para deixar mais fácil (ou
menos difícil) a vida dos designers.
Uma observação é que hoje em dia já é possível utilizar patTemplates para separar completamente o layout dos
códigos.
class HTML_pedidos {
essa é a classe que conterá as telas. As funções são bastante simples e não contém nada que um programador
acostumado com php não entenda. Vou dar atenção apenas as partes importantes.
function html_list_produtos( $rows, $option, $pageNav ) {
Esta função é responsável pela tela de lista de produtos. Ela está recebendo três variáveis:
$rows : um vetor de objetos que contem as informações que serão mostradas.
$option : o nome do nosso componente. Será utilizada para fazer os links e as páginas do redirecionamento
$pageNav : um objeto que ficará responsável por construir a paginação de resultados (deixe o joomla cuidar
disso)
A única coisa a se prestar atenção neste trecho é o nome do formulário: 'adminForm' que é obrigatório. '<th>'
foram utilizados pois eles contém os estilos para deixar o componente no padrão do joomla. Agora veremos o laço
principal:
$k = 0;
for ($i=0, $n=count( $rows ); $i < $n; $i++) {
$row = &$rows[$i];
$link = 'index2.php?option='.$option.'&task=mnt_produtos&hidemainmenu=1&id='. $row->id;
o $link diz respeito à ação que será executada quando a palavra for clicada. Veja que no nesse caso
a $task irá valer 'mnt_produtos'. hidemainmenu=1 significa que o menu principal deverá ser escondido quando a
ação for executada, em funções de manutenção você esconde o menu (na nova versão ele será apenas
desabilitado).
Vamos utilizar esse metodozinho da API do joomla que verifica se o ítem está ou não sendo editado
por outro usuário. Na verdade este ítem não é utilizado nesta primeira parte do componente pois ainda não
implementamos o recurso de 'bloquear' um ítem para outros usuários.
?>
<tr class="<?php echo "row$k"; ?>">
<td align="center">
<?php echo $pageNav->rowNumber( $i ); ?>
</td>
<td align="center">
<?php echo $checked; ?>
</td>
<td>
<a href="<?php echo $link; ?>" title="Editar produto">
<?php echo $row->titulo; ?>
</a>
</td>
<td align="center">
<div align="center"><a href="javascript: void(0);" onclick="return listItemTask('cb<?php echo $i;?>','<?php echo
$task;?>')">
<img src="images/<?php echo $img;?>" width="12" height="12" border="0" alt="<?php echo $alt; ?>" />
</a>
</div></td>
Agora vamos cuidar da tela de manutenção. Esta tela será um formulário normal, a única diferença são alguns
campos hidden e modo com que o editor WYSIWYG será chamado.
Aqui estão os nossos campos hidden que servirão de controle para o joomla. O campo 'option' irá armazenar o
nome do nosso componente (foi passado para a função), precisamos de um campo 'task' que será manipulado
pelo menu (veremos isso depois), o campo hidemainmenu fará o controle do menu, hidemainmenu 0, quer dizer
que na próxima tela, o menu principal será mostrado. Finalmente, o campo ID contém o id do ítem que está sendo
editado. Quando estivermos inserindo um novo ítem, este campo será nulo. O restante é um formulário normal....
Aqui mais uma diferença, estamos chamando o editor para dar mais possibilidades de formatação de
texto para o nosso usuário. note que o segundo parâmetro é o conteúdo que estará no editor.
?>
</td>
</tr>
</table>
</form>
<?
}
Pronto. Aí está a 'cara' do nosso componente. O próximo passo é fazer a classe que fará a interface com o banco
de dados.
A classe que irá manipular a maior parte dos nossos dados é bastante simples, ela apenas irá extender a classe
mosDBTable do joomla que contém os métodos importantes. Vamos lá.
arquivo pedidos.class.php
cada campo da minha tabela foi transformado em uma variável. Isso é muito importante para o bom funcionamento
do seu
componente.
no construtor, eu chamo o método principal da mosDBTable passando para ela o nome da tabela, qual é a
chave primária e passo o objeto que contém a conexão com o banco de dados (normalmente é o objeto
$database)
O funcionamento dos menus no joomla é bastante simples pois a api já está toda pronta e você só precisa informar
os parâmetros. Bom, como já foi dito, para manipular os menus vamos precisar de dois arquivos (na verdade não
são obrigatórios os dois arquivos, mas como estamos fazendo um componente dentro do padrão do joomla, iremos
utilizar os mesmos procedimentos que os membros do core utilizam).
arquivo toolbar.pedidos.php
Este arquivo será chamado automaticamente junto com a parte administrativa do nosso componente. Ele também
receberá o conteúdo da variável $task (na verdade ele receberá o conteúdo de todas as variáveis que forem
passadas ao componente... mas utilizaremos apenas a $task) e irá disparar os métodos da classe abstrata
menuPEDIDOS. Esta classe conterá os botões propriamente ditos.
switch($task) {
/* produtos */
case 'list_produtos':
menuPEDIDOS::LIST_PRODUTOS();
break;
case 'new_produtos':
case 'mnt_produtos':
menuPEDIDOS::MNT_PRODUTOS();
break;
}
Como você pode perceber, para menus nós temos apenas duas opções que são as duas telas... Um dos menus irá
mostrar os botões quando estamos mostrando a lista de produtos e outro irá mostrar os botões para quando
estivermos editando ou criando um novo ítem. Bastante simples né? Ok, última parte da criação de menus! here we
goOoOOo!
Lembra que nós fizemos um arquivo separado para as 'telas' dos formulários? Este aqui, são as 'telas' dos menus.
Mas não vamos precisar inserir nada de código HTML nele pois já está tudo na API, só vamos usar. Nesta primeira
etapa, vamos criar menus simples.
arquivo: toolbar.pedidos.html.php
class menuPEDIDOS {
function LIST_PRODUTOS() {
mosMenuBar::startTable();
o método startTable() inicia a tabela que irá conter os menus. Como você pode ver, há também um
método chamado endTable() e acho que você já entendeu o que ele fará xD
mosMenuBar::addNewX('new_produtos');
O método addNew desenha o botão padrão do joomla para ítens novos. e estou passando um parâmetro
chamado 'new_produtos'. Este parâmetros será o valor da $task (lembre-se: tudo aponta para o index.php e é
controlado pela $task, ou seja, a ação que o componente executará quando este botão for clicado, será definida
dentro dos parênteses).
mosMenuBar::spacer();
este método desenha uma pequena coluna na vertical para separar os botões... perfumaria ;)
mosMenuBar::editListX('mnt_produtos');
mosMenuBar::spacer();
mosMenuBar::deleteList('','rm_produtos');
Veja que no metodo deleteList há um novo parâmetro, ele é opcional, eu coloquei aqui só para você
saber que existe. Ele é uma mensagem que poderá ser mostrada ao usuário. E o segundo parâmetro é a task.
mosMenuBar::spacer();
mosMenuBar::endTable();
Você notou que o método addNew e editList estão escritos com um X no final não é? Bom, isso foi
adicionado no mambo 4.5.2 e serve para alterar o estatus do hidemenu, um parâmetro que está escondido nos
formulários. É um controle para evitar que o usuário feche a janela sem salvar ou cancelar (causando aquele
inconveniente de você ter de ir lá e dar um global checkin - desbloqueio global, em português)
Você pode usar tanto com o 'X' como sem o X a única diferença é esse parâmetro que ele tenta trocar nos
formulários.
}
function MNT_PRODUTOS() {
mosMenuBar::startTable();
mosMenuBar::save('save_produtos');
mosMenuBar::spacer();
mosMenuBar::back();
mosMenuBar::spacer();
mosMenuBar::endTable();
Finalmente, vamos criar dois arquivos extramente simples que serão chamados um na instalação e outro na
desinstalação. Estes arquivos são chamados após o componente ser instalado/desintalado. Normalmente só
contém uma mensagem explicativa (alguns componentes botam as SQL de criação de banco nesses arquivos. eu
prefiro usar a api do joomla para isso).
arquivo install.pedidos.php
function com_install() {
echo "Parte 1 - Componente Exemplo - by Matheus Teixeira Mendes - bigodines - http://www.joomla.com.br";
}
arquivo uninstall.pedidos.php
function com_uninstall() {
echo "Parte 1 - Componente Exemplo - by Matheus Teixeira Mendes - bigodines - http://www.joomla.com.br";
}
na verdade a única coisa que trocou foi o nome da função (e do arquivo, óbvio).
Bom, agora nosso componente está quase pronto. Só falta fazer o arquivo de instalação para que o joomla saiba o
que criar, aonde e quais os bancos serão necessários. Talvez um dos recursos mais impressinoantes do joomla
seja a facilidade de instalar novos componentes. Como você já leu os outros tutorias (o de criação de módulos e
de mambots) você já está familiarizado com muitas das informações deste arquivo. Vou me ater apenas às
novidades. Por favor, quem ainda não leu os outros tutoriais, as explicações sobre o que faz cada parte do xml
podem ser encontradas lá.
<name>Pedidos</name>
<creationDate>May, 2005</creationDate>
<author>Matheus Mendes (bigodines)</author>
<copyright>This software was released under comercial license.</copyright>
<authorEmail> matheus@metasig.com.br</authorEmail>
<authorUrl>http://www.joomla.com.br</authorUrl>
<version>Tutorial</version>
as informações gerais.. como sempre aqui o nome, o autor, site, versão.. e-mail e essa coisa toda.
<files>
<filename>pedidos.class.php</filename>
</files>
aqui vai uma lista dos arquivos que deverão ser copiados para dentro do servidor. Aqui ficam os arquivos que
irão para a pasta /componentes/com_seu_componente/*. Os que vão para a parte administrativa, vão mais abaixo.
A seguir, começa o bloco de instalação. Aqui, listamos os comandos sql que farão a criação das novas
tabelas. Devemos separar cada comando dentro de uma <query> O número de queries é ilimitado.
<install>
<queries>
<query>
DROP TABLE IF EXISTS `#__joomla_produtos`;
</query>
<query>
CREATE TABLE `jos_joomla_produtos` (
`id` int(11) NOT NULL auto_increment,
`titulo` varchar(100) default NULL,
`preco` varchar(30) default '00,00',
`descricao` text NOT NULL,
`checked_out` int(11) default '0',
`checked_out_time` datetime default '0000-00-00 00:00:00',
PRIMARY KEY (`id`)
);
</query>
</queries>
</install>
E quando formos desintalar este componente, devemos dizer ao joomla quais comandos devem ser
executados (temos que eliminar as tabelas que criamos)
<uninstall>
<queries>
<query>
DROP TABLE IF EXISTS `#__joomla_produtos`;
</query>
</queries>
</uninstall>
Depois nós temos de avisar ao joomla qual será o arquivo que irá coordenar a instalação e qual deverá ser
chamado para desinstalar. Esses arquivos são bem simples... o joomla cuida de tudo para nós.
<installfile>
<filename>install.pedidos.php</filename>
</installfile>
<uninstallfile>
<filename>uninstall.pedidos.php</filename>
</uninstallfile>
Agora sim, vamos cuidar da parte administrativa. O primeiro passo é dizer qual o menu será criado e quais os
submenus ele conterá
<administration>
<menu>Pedidos de orçamento - Parte 1</menu>
<submenu>
<menu task="list_produtos">Produtos</menu>
o parametro 'task' quer dizer que quando este submenu for clicado, a variável $task deverá receber
'list_produtos'. Posso ter vários menus dentro do submenu. Nunca tentei com mais de dois níveis, não creio que
seja possível.
</submenu>
pronto... rápido e indolor. Espero que todo mundo tenha entendido a idéia.
Para ver como o componente ficou, faça o download do zip na próxima página. Não esqueça de ler as
considerações finais;
Bom amigos, com esta série de tutoriais iremos cobrir a parte mais importante do desenvolvimento para joomla!
gostaria de receber o retorno de vocês que leram até aqui para que possa melhorar ou continuar o trabalho para
os próximos tutoriais. Estou direto no http://forum.opensourcematters.org (provavelmente já deve haver uma thread
falando sobre esse tutorial lá) e a sua opinião é importante.
Este tutorial está sendo lançado num momento de turbulência (troca do nome, novo logo, slogan, domínio e tudo
mais), como eu comecei a escrever quando o Joomla! ainda era Mambo, os fontes do .zip estão todos
referenciando ao nome antigo. Peço desculpas por isso.
Gostaria de agradecer ao Ronildo que mantém o joomla.com.br atualizado, à equipe de tradução (especialmente
ao Fabio, Marcelo e Fabrício) que estão sempre dando idéias e colaborando com a nossa comunidade (a equipe
de tradução tem mais gente, mas os 'macacos-velhos' merecem um agradecimento especial. Outro agradecimento
para todo o pessoal que participa do http://forum.opensourcematters.org (em especial àqueles que não fazem só
perguntas e que tentam dar a sua contribuição para a comunidade).
Finalmente algumas explicações: Esse texto foi feito ao longe de 15-20 dias. Usando alguns minutos do tempo
livre que eu tinha por dia. Portanto, muitas partes podem estar redundantes. Perdoe-me por isso. Aproveita que
está perdoando e perdoe-me pelos erros de português (eu faço computação, não faço letras!).
Bom, faça o download dessa nossa primeira parte do nosso componente. Vejo você na segunda parte. Não
esqueça de avaliar este texto! CLIQUE AQUI
Até lá pessoal.