Visão geral
Para Programadores
( Componentes)
V 1. 0
Índice
Índice .......................................................................................................................................iii
Índice de Figuras ..................................................................................................................... v
Índice de Tabelas.................................................................................................................... vii
1
O Joomla para programadores ........................................................................................ 9
1.1
Desenvolvendo componentes para o Joomla................................................................................. 16
1.2
Instalando um componente ............................................................................................................ 18
1.3
Definindo a lógica............................................................................................................................ 20
1.4
Definindo a apresentação ............................................................................................................... 21
iii
Índice de Figuras
Figura 9 Diagrama de do processamento de um pedido no Joomla. _________________________________ 11
Figura 10 Estrutura de ficheiros típica de um componente ________________________________________ 18
v
Índice de Tabelas
Tabela 6 Principais ficheiros da raiz do site Joomla ______________________________________________ 9
Tabela 7 Variáveis globais mais importantes usadas num programa Joomla __________________________ 10
Tabela 8 Nomenclatura usada nos principais ficheiros de um componente ____________________________ 17
vii
Visão Geral para Programadores
1 O Joomla para programadores
O primeiro aspecto a reter quando se começa a desenvolver no Joomla é o facto de que o
Joomla per si não é um produto de software, é apenas uma framework interpretadora de
componentes, módulos, mambots e templates (conhecidos por extensões) dos quais o Joomla
é completamente alheio do que fazem ou do seu aspecto. É um programa escrito em PHP, usa
como motor de base de dados o MySQL e o APACHE como servidor. Outro aspecto muito
importante e que geralmente não é mencionado é que não existe o conceito de pagina Web
como o conhecemos, pois tudo o que aparece no browser é gerado a partir de um único
ficheiro, o típico e conhecido index.php que se encontra na raiz do site.
Devido á abstracção do Joomla relativamente as suas extensões é possível desenvolver
subsistemas que podem ser publicados separadamente sem o sistema original. Isto permite
manipular, gerir ou remover parte do sistema sem afectar o resto do sistema.
Qualquer um pode desenvolver uma extensão para o Joomla desde que cumpra os métodos
prescritos para a criação dos mesmos. Mais acerca do funcionamento das extensões pode ser
encontrado nos próximos capítulos.
Para entender como funciona a plataforma Joomla vamos analisar como são processados os
pedidos ao servidor e entender quais são os ficheiros envolvidos e as principais classes,
variáveis globais envolvidas no processo. Primeiro vamos conhecer melhor a hierarquia de
ficheiros do Joomla.
Tabela 1 Principais ficheiros da raiz do site Joomla
Nome
Descrição
Administrator
Pasta onde se encontram todos os ficheiros que tratam da parte
administrativa do site.
Components
Todos os ficheiros dos componentes instalados, excepto os da parte
administrativa.
Includes
Ficheiros do núcleo do Joomla
Laguages
Todos os ficheiros de linguagem
[email protected]
9
Visão Geral para Programadores
Manbots
Todos os ficheiros dos mambots do site.
Modules
Todos os ficheiros dos módulos de “front-end” instalados.
Templates
Ficheiros de todos os templates de “front-end”.
Index.php
Ficheiro de inicio do “front-end” do site.
Index2.php
Ficheiro de inicio do “back-end” do site.
Configuration.php
Ficheiro que contem várias variáveis de configuração do site.
Globals.php
Ficheiro que trata de declarar várias variáveis globais usadas durante a
execução do programa.
Agora uma nota sobre algumas variáveis que nos irão acompanhar ao longo deste relatório
bem como em qualquer programa desenvolvido na plataforma Joomla.
Tabela 2 Variáveis globais mais importantes usadas num programa Joomla
Nome
Descrição
$_VALID_MOS
Permite implementar uma medida de segurança que
impede o acesso directo aos ficheiros de código
URL ou POST
NÃO
excepto index.php
$option
Especifica qual o componente a carregar
SIM
$act
Especifica o tipo de informação a carregar
SIM
$task
Especifica o que fazer ao tipo de informação
especificada em $act, por exemplo guardar ou apagar.
$Itemid
SIM
Especifica o id único do elemento que está a fazer um
pedido, por exemplo o id de um link de menu. Indica
SIM
qual o conteúdo a apresentar.
$database
Um objecto de conexão à base de dados. Implementa
vários métodos que facilitam a manipulação dos
NÃO
dados.
[email protected]
10
Visão Geral para Programadores
$mainframe
Objecto que possui muitas rotinas de interacção com o
Joomla.
NÃO
Na tabela em cima o modificador de “url ou post” significa que esta variável é iniciada
algures no código a partir das variáveis get ou post com o mesmo nome, recebidas no servidor
após os pedidos pelo utilizador. Estas variáveis são usadas para que o servidor execute as
tarefas que foram pedidas pelo utilizador.
Figura 1 Diagrama de do processamento de um pedido no Joomla.
1- Carregar índex.php e definir $_VALID_MOS
2- Existe o ficheiro configuration.php?
3- Carregar configuration.php
4- Carregar joomla.php
5- Carregar database.php
6- Carregar frontend.php
[email protected]
11
Visão Geral para Programadores
7- Existem as variáveis option ou itemid?
8- Criar objecto de base de dados (variável $database)
9- Tentar obter uma option se não foi especificado em 7
10- Criar objecto mosMainframe
11- Criar o array $_MOS_OPTION
12- Carregar o componente
13- Carregar o template
14- Carregar frontend.html.php
15- mosShowHead
16- mosLoadModules
17- mosMainBody
18- Mostrar a página
No diagrama em cima cada passo é da cor do ficheiro que está na realidade a executar o
código, os ficheiros de cor branca indicam que executam apenas código de apoio a algumas
tarefas. Para explicar cada passo iremos usar a letra D para representar o diagrama seguido do
ponto decimal e o número do passo (exemplo [D.3]).
Alguns passos foram omitidos por uma razão de simplicidade, pois correspondem apenas à
garantia de compatibilidade com antigas versões do PHP e do Joomla.
Sempre que um utilizador visita o site, escrevendo o endereço ou carregando num link, o
Joomla recebe um pedido e executa uma série de tarefas para determinar o tipo de utilizador
que fez o pedido, a secção pretendida e o conteúdo em particular a ser exibido.
Como seria de esperar o primeiro ficheiro a ser executado é o index.php [D.1] encontrado no
directório de raiz do site. Se examinarmos este ficheiro podemos ver que não tem nenhum
código html próprio. Isto é porque este ficheiro apenas executa uma quantidade de tarefas e
delega funções mas não gera nenhum conteúdo. Note que no diagrama a sua execução só
termina quando o conteúdo é apresentado ao utilizador. O conteúdo exibido é recolhido e
[email protected]
12
Visão Geral para Programadores
formatado por outros ficheiros – os componentes e módulos – que são incluídos pelo
index.php.
A primeira tarefa do index.php é definir a variável global $_VALID_MOS com o código
define (‘_VALID_MOS’, 1), assim a primeira linha em todos os outros do Joomla é:
defined ( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
Isto é uma medida de segurança que impossibilita o acesso directo aos ficheiros do Joomla
excepto ao index.php. Assim, se tentar-mos aceder, por exemplo, ao ficheiro
mod_mainmenu.php directamente pelo seu url, $_VALID_MOS, que é definida em
index.php, não terá sido definida logo o utilizador só verá uma mensagem que dirá ‘Direct
Access to this location is not allowed.'.
De seguida index.php verifica a existência de configuration.php [D.2]. Este ficheiro contém a
configuração básica do Joomla que é usada pelo núcleo do site, os seus componentes,
módulos e templates. Se o ficheiro configuration.php não existir o Joomla carrega um script
de instalação que permite instalar o Joomla com as definições por defeito bem como alguma
informação inserida pelo utilizador como o nome da base de dados e o nome de usuário e
palavra-chave do MySQL. Este ficheiro é uma lista de variáveis usadas para guardar
informação de caminhos para directórios internos, nome de usuário e palavra-chave do
MySQL, fuso horário e outras informações de administração. Se o ficheiro configuration.php
existir então é carregado [D.3] e a execução do Joomla corre o seu rumo normal.
O próximo passo é carregar o joomla.php [D.4]. Este é um dos ficheiros com maior carga de
trabalhos da API do Joomla e contém muitas classes e funções que tornam o trabalho do
programador muito mais fácil. Algumas destas classes e funções serão descritas mais a frente
mas para já interessa saber que este ficheiro é muito importante e é aconselhável perder algum
tempo a conhece-lo melhor.
Outro ficheiro muito importante para o programador é database.php. Este ficheiro é carregado
pelo Joomla [D.5] e contém todas as classes e funções necessárias para interagir com a base
de dados tornando estas capacidades acessíveis a todos os ficheiros subsequentes. Entraremos
em pormenor mais a frente mas para já é importante saber que este ficheiro oferece um vasto
leque de funções de query com diferentes tipos de retorno e funções de debugging.
[email protected]
13
Visão Geral para Programadores
O próximo ficheiro de núcleo a ser carregado é o frontend.php [D.6], que trabalha em série
com Joomla.php para levar a cabo a maior parte das tarefas do Joomla como iniciar e carregar
módulos ou carregar o conteúdo principal de uma página. Os templates interagem
directamente com este ficheiro pois ele está directamente ligado à apresentação do conteúdo.
Depois de todos os ficheiros do núcleo do Joomla serem carregados o index.php tenta
identificar o estado de ‘option’ e ItemId’ [D.7] que são passadas pela url query string ou pelo
post dependendo do tipo de pedido, para identificar qual o conteúdo pretendido pelo
utilizador. Se este passo falhar o Joomla simplesmente passa para o próximo passo.
De seguida é criado um novo objecto de base de dados [D.8], criando uma instancia da classe
database que naturalmente se encontra em database.php. Como o HTTP não mantém uma
ligação permanente ao servidor sempre que é feito um novo pedido é necessário criar um
novo objecto de conexão á base de dados.
Em [D.9] o Joomla volta tratar da questão do ‘option’ e ‘Itemid’. Se em [D.7] ‘option’ não foi
definido mas foi definido um ‘Itemid’ então o Joomla tenta descobrir qual o componente a
carregar procurando na base de dados pelo item de menu especificado em ‘itemid’ que, por
sua vez, contém toda a informação do conteúdo desse link. Se o anterior falhar então o Joomla
baseia-se na ‘option’ e ‘Itemid’ do primeiro elemento do menu principal que se assume ser a
página inicial do site. Note que tudo isto só acontece se não for especificado um componente
através do ‘option’ caso contrario o componente será carregado e tratado no próximo passo.
O próximo passo é criar um objecto mosMainframe [D.10] na variável global $mainframe.
Este objecto proporciona uma grande carga de trabalhos por ter muitas rotinas de interacção
com o sistema. Muitas das rotinas deste objecto serão usadas pelo componentes que virá a ser
carregado, por exemplo para ler do ficheiro configuration.php carregado em [D.3], determinar
o template usado, colocar alguma informação na parte ‘header’ e ‘metadata’ do código HTML
da página. O mosMainframe também iniciará uma sessão ou actualizará no caso de esta não
ter expirado. As sessões permitem que um utilizador previamente autenticado navegue de
página para página sem ter de inserir novamente as suas credenciais.
[email protected]
14
Visão Geral para Programadores
Neste momento, o Joomla irá preparar-se para executar o código do componente que foi
determinado nos passos 7 ou 9. Apesar de tudo o conteúdo resultante desta execução ainda
não será apresentado, em vez disso é guardado num ‘buffer’ temporário para que mais tarde
possa ser “misturado” com o HTML do template. No ficheiro index.php é criado um array
chamando $_MOS_OPTION [D.11] e de seguida é usada a capacidade de “buffering” do PHP
para capturar o conteúdo de saída do componente. Isto é feito da seguinte forma:
- Chamar o comando PHP ob_start()
- Executar o código do componente
- Retirar o conteúdo do “buffer” usando ob_get_contents()
- Colocar o conteúdo em $_MOS_OPTION para mais tarde ser usado
- Limpar o “buffer” com ob_end_clean()
Finalmente chega o momento de carregar o “template” [D.13]. Este deverá ter chamadas a
procedimentos do “frontend.php” mosShowHead, mosLoadModules e mosMainBody. Para
carregar os módulos para uma dada posição o ficheiro “frontend.php” primeiro carrega
“frontend.html.php” [D.14] e só depois inicia os módulos escrevendo o HTML. O
“frontend.html.php” primeiro verifica se um módulo em particular é um módulo instalado ou
um módulo “stored”, sendo que a diferença é que os módulos instalados são ficheiros
separados no directório dos módulos e os módulos “stored” são criados na área de
administração dos módulos e guardados na base de dados. Depois de carregado o
“frontend.html.php”, a função mosShowHead() [D.15] chama a função do objecto
mosMainframe, getHead() que retorna a informação do “header” previamente tratada no
passo 10.
O mosLoadModules() poderá ser chamado quantas vezes for necessário dependendo das
regiões definidas no “template”. O Joomla permite no máximo 26 posições com nomes como
Top, Left, Right, Bottom, user1, user2… Estas posições organizam os módulos em grupos.
Quando no mosLoadModules() é passado um parâmetro(primeiro) indicando a posição, o
Joomla carrega todos os módulos do grupo dessa posição.
Após executar o código do modulo o “frontend.php” envolve-o em código HTML adicional
se for especificado um parâmetro (segundo) adicional de estilo em mosLoadModules(). Por
exemplo mosLoadModules('left', -1) indica que 'left' é a grupo de posição e -1 o estilo do
[email protected]
15
Visão Geral para Programadores
módulo. Neste caso -1 indica que não é necessário adicionar mais nenhum HTML e que o
título não deve ser mostrado. O parâmetro de estilo ‘0’ é o estilo por defeito e indica que o
módulo deve ser envolvido numa tabela da classe “moduletable”.
A parte final do código a ser executada é o mosMainBody() [D.17] que é uma função muito
simples pois a sua única tarefa é ir buscar o conteúdo de saída do componente ao array
$_MOS_OPTION que foi por sua vez guardado em $GLOBALS no passo 12.
Neste momento todo o HTML de saída dos componentes, módulos e Joomla é junto para
mostrar a página gerada ao utilizador [D.18].
1.1 Desenvolvendo componentes para o Joomla
Como já vimos em capítulos anteriores os componentes são compostos por uma parte de
administração e uma parte visível ao utilizador. Em termos de hierarquia de ficheiros estas
duas
partes
encontram-se
separadas,
a
parte
de
administração
encontra-se
em
“administrator/components/com_*” e parte de “front-end” em “components/com_*” (todos os
componentes começam com “com_” seguidos no seu nome).
Podemos fazer absolutamente tudo o que quisermos com eles desde que se usem os métodos e
regras necessárias a sua integração no Joomla.
Essas regras incluem usar determinadas nomenclaturas nos ficheiros do componente, criar um
ficheiro xml com a lista dos ficheiros do componente e informação de instalação, usar
métodos da framework para tarefas internas, criar ficheiros de instalação e remoção.
Embora o Joomla ofereça vários métodos e classes de apoio ao desenvolvimento de
extensões, estas não são indispensáveis para o funcionamento dos mesmos. Se, por exemplo,
tivermos um programa em PHP que queremos integrar no Joomla como componente podemos
facilmente, dependendo da complexidade do programa, fazer a transição apenas com
pequenas alterações de código para garantir a segurança e alguma integração com outros
componentes.
Geralmente o desenvolvimento de componentes segue uma arquitectura bem definida e
simples que embora não sendo obrigatória é bastante aconselhada pois simplifica muito a
compreensão de todos os aspectos do programa. Basicamente é aconselhada a separação de
[email protected]
16
Visão Geral para Programadores
tarefas de lógica e de apresentação em ficheiros separados. As tarefas de lógica podem ser
gravar, listar, ler da base de dados, que fazem chamadas a métodos da parte de apresentação
que se encarregam de imprimir todo o HTML para formulários, listagens de conteúdo, etc. O
ficheiro de apresentação é constituído sempre por pelo menos uma classe com vários métodos
e sem construtor que será usada como camada de apresentação do componente. Um terceiro
ficheiro que é muito frequente usar é o de classes da base de dados. Este contém classes que
são representações das tabelas da base de dados usadas pelo componente. Estas classes podem
ser uma extensão da classe do Joomla chamada “mosDBTable” e fazer uso de algumas
funções que ai estão implementadas para simplificar a comunicação com a base de dados.
Tabela 3 Nomenclatura usada nos principais ficheiros de um componente
Nomenclatura
Ficheiro
Administração
“front-end”
Lógica
admin.(*).php
(*).php
Apresentação
admin.(*).html.php
(*).html.php
Classes
admin.(*).class.php
(*).class.php
(*) - Nome do componente.
É muito importante usarmos a nomenclatura descrita em cima porque quando o Joomla
carrega um componente, baseia-se no nome deste para descobrir qual o ficheiro inicial do
programa, que como já deve ter suspeitado é o ficheiro de lógica. Outra vantagem de usar esta
nomenclatura é o facto de existirem algumas funções internas que facilitam, por exemplo, a
inclusão dos vários ficheiros bastando para isso indicar se quer o de classes, de apresentação
ou de lógica.
[email protected]
17
Visão Geral para Programadores
1.2 Instalando um componente
Os componentes são publicados no formato de compressão zip e seguem uma hierarquia de
ficheiros própria que é necessária para que o Joomla os reconheça como válidos. É prática
corrente usar directórios separados para os diferentes tipos de ficheiros, assim tipicamente
existirá um directório de imagens, um directório de javascripts, um directório de folhas de
estilo css e na raiz todos os ficheiros de código fonte PHP.
Figura 2 Estrutura de ficheiros típica de um componente
Para instalar o componente o Joomla começa por procurar nos elementos do componente um
ficheiro xml com o mesmo nome do componente (na figura em cima podemos ver o ficheiro
gilt.xml). Este ficheiro contém a descrição de todos os ficheiros do componente, que usa para
copiar e criar os directórios na área de font-end e de back-end, os comandos sql necessários
para interagir com a base dados (criando assim a estrutura de dados usada pelo componente) e
outra informação acerca do componente.
[email protected]
18
Visão Geral para Programadores
O esquema seguinte exemplifica uma possível estrutura do ficheiro xml de instalação.
<?xml version="1.0"?>
<mosinstall type="component" version="4.5.1">
<name>Gilt</name>
<creationDate>May 2006</creationDate>
<author>Hugo Jorge Soares</author>
<copyright>All rights reserved</copyright>
<authorEmail>[email protected]</authorEmail>
<authorUrl>gilt.isep.ipp.pt</authorUrl>
<version>1.0</version>
<description>Gilt component</description>
<files><filename>gilt.php</filename></files>
<images><filename>images/logo.gif</filename></images>
<install>
<queries>
<query>CREATE TABLE inscricoes (total INT(11) NULL ,name
VARCHAR( 80 ) NOT NULL ,email VARCHAR( 80 ) NOT NULL ,morada VARCHAR( 150 )
,telefone INT( 9 ) ,events TEXT NOT NULL,id TINYINT auto_increment NOT NULL
,PRIMARY KEY ( id )) ENGINE = INNODB;</query>
</queries>
</install>
<uninstall><queries>
<query>DROP TABLE Pessoa_Events;</query></queries>
</uninstall>
<installfile>install.gilt.php</installfile>
<uninstallfile>uninstall.gilt.php</uninstallfile>
<administration>
<menu>GILT</menu>
<submenu><menu act="peo">People</menu></submenu>
<files><filename>admin.gilt.php</filename></files>
</administration>
</mosinstall>
Como podemos ver começa-mos por descrever alguma informação sobre o componente como
o autor a data, etc. De seguida temos uma lista de ficheiros que devem ser copiados para a
área de front-end (files e images). Nas secções install e uninstall temos a possibilidade de
escrever os comandos sql necessários para a instalação ou remoção do componente, que serão
[email protected]
19
Visão Geral para Programadores
executados nessa altura. Os nódulos xml installfile e uninstallfile indicam respectivamente
qual o ficheiro a carregar aquando da instalação ou remoção do componente. A última parte é
respeitante à área de administração e permite construir o menu de administração do
componente indicando quais os links e os valores a serem passados nas variáveis de url. Tal
como para p front-end também é obrigatória a descrição dos ficheiros que compõem esta área.
Como já foi dito o Joomla carrega um ficheiro aquando da instalação ou remoção do
componente. No caso de instalação o Joomla tenta correr a função com_install() e na remoção
com_uninstall(). Estas funções têm de existir forçosamente e nelas podemos inserir comandos
adicionais para completar a instalação ou remoção. Isto é particularmente útil para fazer
algum tipo de integração com componentes ou módulos existentes como por exemplo a
criação de links de menu.
1.3 Definindo a lógica
Para definir as tarefas a executar o ficheiro de lógica usa as variáveis que já conhecemos, $act
e $task, em duas cláusulas switch encadeadas como exemplifica o código seguinte:
switch($act){
case ‘eventos’:
switch ($task){
case ‘save’:
save($option,$act);
break;
case ‘list:
list($option);
break;
}
break;
case ’pessoas’:
….
}
[email protected]
20
Visão Geral para Programadores
Desta forma podemos direccionar a execução do código no sentido pretendido pelo pedido do
utilizador, fazendo as chamadas das respectivas funções que tratam da tarefa requerida.
Todas as funções que tenham como resultado final a apresentação de conteúdo devem fazer
chamadas a métodos do ficheiro de apresentação. No entanto previamente à chamada destes
métodos toda a lógica deve ser tratada, incluindo leituras à base de dados o que implica enviar
apenas os dados a serem mostrados. Isto é feito usando a classe de acesso a dados “database”
que se encontra no ficheiro database.php e tem como variável global $database. Nesta
camada temos a possibilidade de obter dados da base dados sob a forma de arrays de objectos
representativos das tabelas, que usaremos para enviar os dados para a camada de apresentação
do componente.
As funções que tenham como resultado apenas a interacção com a base de dados (gravar,
actualizar, apagar) apenas fazem chamadas à camada de acesso a dados do Joomla e
geralmente não interagem com mais nenhum ficheiro. Estas Funções podem fazer uso das
classes do ficheiro de classes para facilitar a interacção com a base de dados. Geralmente são
chamadas em resposta a um envio de um formulário usando o método post.
1.4 Definindo a apresentação
O ficheiro de apresentação é constituído por pelo menos uma classe geralmente com o nome
lógico de HTML pois é só disto que ela trata. Esta classe não possui construtor porque não
existe necessidade de ser instanciada pois apenas os seus métodos são de interesse. Estes
métodos efectuam tarefas bem específicas pelo que geralmente englobam todo o
processamento no seu corpo. Recebem como parâmetro, sob a forma de arrays, os dados que
devem mostrar e escrevem o HTML para formatar e apresentar esse conteúdo. Na realidade o
componente só tratará de escrever algum do HTML do bloco “body” da página o resto faz
parte dos módulos e claro do “template”.
Existem alguns cuidados a ter quando estamos a desenvolver em HTML especialmente no
que respeita aos formulários pois o Joomla coloca algumas regras, nomeadamente:
•
Os atributos name, id e class da tag form têm que ser “adminForm”
[email protected]
21
Visão Geral para Programadores
•
O atributo action da tag form deverá ser “index.php” para o “front-end” e “index2.php”
para o “back-end”.
•
Como o formulário irá ser tratado na parte de lógica então teremos de colocar em
elementos escondidos o valor das variáveis $option, $act e $task. Desta forma quando o
formulário for submetido ao servidor o Joomla carregará o nosso componente através de
$option, $act indicará qual a acção e $task a tarefa.
Por exemplo:
<input type="hidden" name="option" value="com_gilt" />
<input type="hidden" name="act" value="eventos" />
<input type="hidden" name="task" value="gravar" />
Neste caso quando o formulário fosse submetido o Joomla iria carregar o componente
“gilt” e chamar o método que trata de gravar os eventos.
•
Usar o método addCustomHeadTag( $html ) do objecto mosMainframe para inserir algum
código necessário no bloco head da página (lembrar que todo o html só é inscrito numa
fase posterior, dai a necessidade de um método deste género).
•
Ter bastante cuidado com o uso de javascript para que não existam conflitos com o scripts
que o Joomla usa para o seu funcionamento.
•
Usar os métodos do Joomla para criar as barras de ferramentas que se usam para as
tarefas de autoria, pois estas incluem automaticamente alguns scripts necessários para
interagir com outros elementos do formulário.
Quanto ao aspecto do conteúdo deveremos sempre que possível usar os atributos class dos
elementos HTML para definirmos o seu estilo. Existem standards para os nomes de classes
css que os “templates” devem usar, logo se usarmos esses nomes para os atributos class,
temos a garantia de que o aspecto de toda a página será homogéneo. Para conhecermos estes
nomes temos de investigar o css do template que está ser usado.
[email protected]
22
Visão Geral para Programadores
Este trabalho está licenciado sob uma Licença Creative Commons Atribuição-Uso NãoComercial-Compartilhamento pela mesma Licença 2.5. Para ver uma cópia desta licença,
visite http://creativecommons.org/licenses/by-nc-sa/2.5/ ou envie uma carta para Creative
Commons, 559 Nathan Abbott Way, Stanford, California 94305, USA
[email protected]
23
Download

Joomla - Viso geral para programadores