====== Como montar um plugin no MantisBT ====== O intuito deste tutorial é ensinar como desenvolver um plugin para o sistema de "bug tracking” MantisBT ===== Definição ===== Por ser um sistema open-source (de código-fonte aberto), o MantisBT possibilita a integração com plugins. Os plugins são desenvolvidos de forma independente, ou seja, não é preciso alterar a estrutura principal do MantisBT, nem alterar qualquer código fonte dentro do mesmo, no entanto, é possível alterar o comportamento padrão de certos eventos, como veremos depois. Neste tutorial iremos desenvolver um plugin nomeado **Exemplo**. Para desenvolver um plugin é preciso seguir algumas restrições do MantisBT. ===== Estrutura ===== O código-fonte do plugin deve ser inserido dentro de um diretório na estrutura de diretórios do MantisBT. O local é mantis/plugins/ Dentro desse diretório deve-se criar um diretório com o nome do seu plugin Neste exemplo, então, seria Exemplo * mantis/plugins/Exemplo Todos os códigos fontes do plugin ficarão nesse diretório. Neste turorial trabalharemos partindo dele. ===== Desenvolvendo a classe ===== Crie um arquivo PHP com o nome do seu plugin. * Exemplo.php Esse arquivo será o código-fonte de uma classe. Note que o MantisBT exige que essa classe herde a classe **MantisPlugin** e também que o nome do plugin seja (//NomeDoPlugin//)Plugin, ou seja, contenha Plugin no final. Portanto, o código fonte seria assim: Essa classe obrigatóriamente deve conter a função **register()**, responsável por armazenar as informações do plugin. As informações são: * **name** (O nome do plugin) **Obrigatório**; * **description** (Descrição do plugin); * **page** (A página inicial do plugin. Veremos páginas mais à frente); * **version** (Versão do plugin) **Obrigatório**; * **requires** (Dependências. Deve ser passado um array com a dependência e o valor) * Ex: $this->requires = array( 'MantisCore' => '1.2.0, <= 1.2.0' );); * **author** (Autor do plugin); * **contact** (e-mail do autor(es)); * **url** (Página de suporte do plugin). No nosso exemplo name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } } ?> Com isso já é possível instalar e desinstalar o nosso plugin livremente Para testar acesse o MantisBT como Administrador,Então: * Gerenciar → Gerenciar Plugins Se em algum momento for solicitada a senha novamente, então digite-a. O plugin deve estar disponível da parte de baixo do site, em Plugins Disponíveis. Instale o plugin para continuarmos com o tutorial. ===== Páginas do plugin ===== Para esta parte do tutorial, entende-se **página** como um arquivo PHP, enquanto HTML, CSS, etc. entende-se como **arquivo**. As páginas do plugin devem ficar em um diretório **pages** partindo do diretório do plugin * Exemplo/pages Dentro desse diretório então podemos criar a nossa página inicial, definida anteriormente Acesse essa página clicando no link sobre o seu plugin instalado Note que a URL da página ficou como * plugin.php?page=Exemplo/inicio.php Ou seja * plugin.php?page=(NomeDoPlugin)/(PaginaDoPlugin). O diretório **pages** deve ser usado apenas para páginas PHP. Se quisermos, por exemplo, adicionar um arquivo CSS, temos um outro diretório chamado **files**. * Exemplo/files No nosso exemplo criaremos uma folha de estilo (CSS) para a nossa página inicio.php p{ color:#FF0000; } "; echo "

Hello world!

"; ?>
Note que a função //plugin_file// foi utilizada. Essa função retorna o endereço de um arquivo. No nosso exemplo acima então, retorna o endereço da folha de estilo //estilo.css//; * /mantis/plugin_file.php?file=Exemplo/estilo.css Note que (aparentemente...) não é feita uma busca, mas sim uma formatação de texto, ou seja, se o arquivo não exisitir esse valor é retornado da mesma forma. Do mesmo modo podemos procurar por uma página utilizando a função //plugin_page// dessa forma: "; echo "

Hello world!

"; echo "Eu mesmo!"; ?>
Igual ao //plugin_file//, essa função retorna o endereço, existindo a página ou não. Até então a página do plugin deve estar apenas com uma pequena quantidade de texto. Para adicionarmos o cabeçalho e o rodapé padrão do MantisBT temos as funções //html_page_top()// e //html_page_bottom()//, que servem para adicionar o cabeçalho e o rodapé, respectivamente. A função //html_page_top()// aceita uma String como parâmetro para o título da página "; echo "

Hello world!

"; echo "Eu mesmo!"; html_page_bottom(); ?>
===== Init ===== Assim como a função //register()//, a função init é executada após o carregamento do plugin. Veremos um exemplo dele na parte **Eventos**. ===== Eventos ===== Entenda evento como alguma ação. Por ser uma classe, o seu plugin pode ter os seus métodos. Esse métodos são acionados através de EVENTOS, ou seja, um evento será alguma ação que irá ativar uma função. Podemos usar eventos declarados por nós ou então eventos do core do Mantis, que serão listados no final deste tutorial. No nosso exemplo, utilizaremos um evento do core do Mantis para adicionar a página do nosso plugin no Menu principal, e acionaremos no método //init()//: name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } function init(){ plugin_event_hook( 'EVENT_MENU_MAIN', 'adicionar_menu' ); } function adicionar_menu(){ $array_menu[0] = "Exemplo"; return $array_menu; } } ?> No exemplo acima ligamos a função //adicionar_menu()// ao evento //EVENT_MENU_MAIN//, que é executado ao exibir o menu principal. Lembrando que esse método é do core do MantisBT, por isso não precisamos declará-lo. A função //plugin_event_hook// serve para ligar funções à eventos, ou seja, ao ocorrer aquele evento, tal função é executada. Podemos ainda declarar os nossos próprios eventos. Para isso é necessário apenas passar como parâmetro o nome e o tipo de evento. No nosso exemplo usaremos um evento //EVENT_EXEMPLO_IMPRIMIR// do tipo //EVENT_TYPE_OUTPUT//. name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } function init(){ plugin_event_hook( 'EVENT_MENU_MAIN', 'adicionar_menu' ); } function events() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => EVENT_TYPE_OUTPUT ); } function adicionar_menu(){ $array_menu[0] = "Exemplo"; return $array_menu; } } ?> O evento foi declarado na função //events()//, e retorna um array onde chave = Nome do evento e valor = tipo do evento. Note também que o nome do evento foi //EVENT_(NOME_DO_PLUGIN)_(EVENTO)//, não é obrigatório o uso dessa nomenclatura mas é recomendável para evitar conflitos com outros plugins. Veremos esse evento em ação em //HOOKS//. Os tipos de evento definidos pelo core são: ==== EVENT_TYPE_EXECUTE ==== São os tipos mais simples. Não recebem parâmetros e não retornam valor. ==== EVENT_TYPE_OUTPUT ==== Pra quando algo for ser exibido ao usuário ==== EVENT_TYPE_CHAIN ==== Um evento que ocorre na forma "Corrente". Significa que vários métodos serão executados em um sequência para que o útlimo dela retorna algum valor. Pode-se enviar um parâmetro para a primeira função para que a última retorne o valor tratado. ==== EVENT_TYPE_DEFAULT ==== O tipo mais genérico. O parâmetro passado é incluido diretamente na função que é chamada, e o resultado final é armazenado em um array. A chave desse array é o nome da função e o nome do plugin. Esse array, então, é retornado. ===== Hooks ===== São quem liga os eventos às funções. Um exemplo acima já foi exibido, onde a função //adicionar_menu()// é ligada ao evento //EVENT_MENU_MAIN//. Aqui então criaremos um método para imprimir um valor e o ligaremos ao evento que criamos anteriormente, o evento //EVENT_EXEMPLO_IMPRIMIR//: name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } function init(){ plugin_event_hook( 'EVENT_MENU_MAIN', 'adicionar_menu' ); } function events() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => EVENT_TYPE_OUTPUT ); } function hooks() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => 'imprimir' ); } function adicionar_menu(){ $array_menu[0] = "Exemplo"; return $array_menu; } function imprimir( $p_event ){ echo "

Testando um evento

"; } } ?>
"; echo "

Hello world!

"; echo "Eu mesmo!"; event_signal('EVENT_EXEMPLO_IMPRIMIR'); html_page_bottom(); ?>
Neste exemplos nós: Ligamos o evento //EVENT_EXEMPLO_IMPRIMIR// à função //imprimir()//. Implementamos a função //imprimir()//, que apenas exibe um texto na tela Chamamos o evento e, consequentemente a função, usando a função //event_signal( {NOME_DA_FUNCAO} )//. Note que o método imprimir precisa aceitar um parâmetro //$p_event//, por restrições do core sobre as funções que são chamadas por eventos. ===== Configurações ===== Podemos criar e utilizar configurações para o nosso plugin. Veja os exemplos: name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } function init(){ plugin_event_hook( 'EVENT_MENU_MAIN', 'adicionar_menu' ); } function events() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => EVENT_TYPE_OUTPUT ); } function hooks() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => 'imprimir' ); } function config() { return array( 'Exemplo_Num' => '1', ); } function adicionar_menu(){ $array_menu[0] = "Exemplo"; return $array_menu; } function imprimir( $p_event ){ echo "

Testando um evento

"; } } ?>
"; echo "

Hello world!

"; echo "Eu mesmo!"; event_signal('EVENT_EXEMPLO_IMPRIMIR'); $t_exemplo_num = plugin_config_get( 'Exemplo_Num' ); echo "
"; echo "O valor = " . $t_exemplo_num; html_page_bottom(); ?>
Um arquivo novo Neste exemplo criamos em //Exemplo.php// a função //config()//, responsável por manter todas as configurações do nosso plugin. Note que as configurações são definidas por um array, onde a chave é o nome e o valor é o valor padrão da configuração. Em //inicio.php// criamos um formulário para a alteração e exibição do valor dessa configuração. Para retornar o valor usamos a função //plugin_config_get//, passando como parâmetro o nome da configuração. No formulário definimos que a propriedade //action// direciona para a página //alterar_conf// do plugin. Ainda abaixo exibimos o valor da configuração. Criamos uma nova página, a //alterar_conf.php//, responsável pela alteração do valor da configuração. Primeiramente ela recebe o valor do campo //Ex_Num// da página anterior. Em seguida verifica se está nulo. Se o valor estiver nulo, então retorna a configuração para o valor padrão, usando a função //plugin_config_delete//. Se o valor estiver preenchido então altera o valor da configuração usando a função //plugin_config_set//. Por útlimo redireciona a página para inicio.php usando a função //print_successful_redirect//. ===== Idiomas ===== Podemos definir diversos idiomas para os textos exibidos no nosso plugin. Para o sistema de plugin do Mantis isso é feito através de arquivos de texto. As configurações sobre idioma são diretas do core do Mantis. O idioma padrão é Inglês, então se é passado algum idioma que não existe, o idioma Inglês é atribuido. Os arquivos de texto ficam no diretório lang partindo da raiz do nosso plugin. * Exemplo/lang Dentro desse diretório deve ser criado um arquivo de texto com o nome //strings_{idioma}// substituindo //{idioma}// pelo idioma que ele representa. No nosso exemplo deixaremos que o nosso texto **Hello World** na nossa página //inicio.php// seja alterado de acordo com o idioma selecionado pelo usuário. Primeiro criaremos os arquivos de texto para os idiomas Português-Brasil e Inglês "; echo "

" . plugin_lang_get('HelloWorld') . "

"; echo "Eu mesmo!"; event_signal('EVENT_EXEMPLO_IMPRIMIR'); $t_exemplo_num = plugin_config_get( 'Exemplo_Num' ); echo "
"; echo "O valor = " . $t_exemplo_num; html_page_bottom(); ?>
Os nomes das variáveis e dos arquivos devem ser respeitados conforme nos exemplos. Nome do arquivo * strings_{lingua}.txt Variáveis * $s_plugin_{nome_plugin}_{nome_string} = {valor_string} Substituindo, é claro, o que está entre chaves {} pelo seu respectivo valor. Para então, tratar o valor que será exibido na tela usamos a função //plugin_lang_get// passando como parâmetro o nome da String. ===== Código final do tutorial ===== name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } function init(){ plugin_event_hook( 'EVENT_MENU_MAIN', 'adicionar_menu' ); } function events() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => EVENT_TYPE_OUTPUT ); } function hooks() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => 'imprimir' ); } function config() { return array( 'Exemplo_Num' => '1', ); } function adicionar_menu(){ $array_menu[0] = "Exemplo"; return $array_menu; } function imprimir( $p_event ){ echo "

Testando um evento

"; } } ?>
"; echo "

" . plugin_lang_get('HelloWorld') . "

"; echo "Eu mesmo!"; event_signal('EVENT_EXEMPLO_IMPRIMIR'); $t_exemplo_num = plugin_config_get( 'Exemplo_Num' ); echo "
"; echo "O valor = " . $t_exemplo_num; html_page_bottom(); ?>
"; echo "

" . plugin_lang_get('HelloWorld') . "

"; echo "Eu mesmo!"; event_signal('EVENT_EXEMPLO_IMPRIMIR'); $t_exemplo_num = plugin_config_get( 'Exemplo_Num' ); echo "
"; echo "O valor = " . $t_exemplo_num; html_page_bottom(); ?>
p{ color:#FF0000; } ===== Funções utilizadas neste tutorial ===== Esta seção irá explicar cada uma das funções utilizadas neste tutorial da forma que foram utilizadas neste tutorial. ==== register() ==== Função responsável para armazenar informações sobre o plugin. Exemplo: function register() { $this->name = 'Exemplo'; $this->description = 'Apenas um plugin de exemplo'; $this->page = 'inicio.php'; $this->version = '1.0'; $this->requires = ''; $this->author = 'Seu nome'; $this->contact = 'seuemail@email.com'; $this->url = 'http://www.suapagina.com'; } ==== init() ==== É uma função que é executada quando o plugin é carregado. ==== events() ==== Determina os eventos do seu plugin. Os eventos chamam funções do seu plugin e podem ser executados de qualquer local, até mesmo de outro plugins. Exemplo: function events() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => EVENT_TYPE_OUTPUT ); } ==== hooks() ==== Função utilizada para ligar eventos à funções. Exemplo: function hooks() { return array( 'EVENT_EXEMPLO_IMPRIMIR' => 'imprimir' ); } ==== config() ==== Define as configurações do seu plugin. Esta função declara as configurações e define o seu valor padrão. Exemplo: function config() { return array( 'Exemplo_Num' => '1', ); } ==== html_page_top($titulo) ==== Exibe o cabeçalho do MantisBT. O parâmetro //$titulo// é o título da página. ==== html_page_bottom() ==== Exibe o rodapé do MantisBT. ==== plugin_file($file) ==== Retorna uma string formatada com a URL do arquivo do plugin, definido no parâmetro //$file//. ==== plugin_page($page) ==== Retorna uma string formatada com a URL da página do plugin, definida no parâmetro //$page//. ==== plugin_lang_get($string) ==== Retorna uma string do arquivo de idiomas do plugin. A string é definida no parâmetro //$string//. ==== event_signal($nome_do_evento) ==== Executa um evento. O parâmetro //$nome_do_evento// é o nome do evento que será chamado. Isso é independente de plugin, uma vez que os eventos são registrados no core do MantisBT. ==== plugin_config_get( $nome_configuracao) ==== Retorna uma configuração do plugin, definida no parâmetro //$nome_configuracao//. ==== plugin_config_set( $nome_configuracao, $valor ) ==== Define um valor para uma configuração do plugin. A configuração é indicada em //$nome_configuracao//, e o valor que será definido para ela é definido em //$valor//. ==== plugin_config_delete($nome_configuracao) ==== Apaga qualquer valor definido na configuração determinada em //$nome_configuracao// e restaura o valor padrão para ela. ==== gpc_get_string($nome_requisicao) ==== Recupera uma requisição por POST ou GET. ==== print_successful_redirect($local) ==== Redireciona para o local definido em //$local//. ===== Dicas ===== ==== Incluindo arquivos (include) ==== Não é possível incluir arquivos pela função //plugin_page//, pois essa função retorna uma string de uma única página. O que difere as páginas desse plugin é um parâmetro que também é retornado pela função. Sendo assim, para incluir um arquivo em uma página do seu plugin simplesmente faça: include_once( dirname(__FILE__) . DIRECTORY_SEPARATOR . 'seu_arquivo.php'); Sendo que 'seu_arquivo.php' é o arquivo que deseja incluir.