Menu em ExtJS com Permissões usando PHP e Mysql
Uma das coisas que mais me deu dor de cabeça quando comecei a trabalhar com ExtJS foi montar uma estrutura de Menu Dinâmico de acordo com as permissões do usuário logado. Por isso vou compartilhar minha solução:
Primeiro de tudo vamos criar o nosso banco de dados. Vamos precisar de duas tabelas: uma para o nosso menu e outra com as permissões de cada usuário.
A tabela do Menu terá os campos de id (o id do objeto no Extjs para facilitar manipulação posterior), o nome, o ícone, a pai (caso exista), a ordem e é claro a função que será chamada na ação do clique. Na segunda tabela vamos ter apenas duas chave, o id do usuário e o id do menu. Segue abaixo de exemplo a que eu utilizei:
MySQL
# # Estrutura da Tabela Menu # CREATE TABLE /*!32312 IF NOT EXISTS*/ `menu` ( `id_menu` int(3) NOT NULL AUTO_INCREMENT, `id` varchar(20) DEFAULT NULL, `menu` varchar(70) DEFAULT NULL, `ordem` int(3) DEFAULT NULL, `pai` int(3) DEFAULT NULL, `ico` varchar(50) DEFAULT NULL, `funcao` varchar(80) DEFAULT NULL, PRIMARY KEY (`id_menu`) ) TYPE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; # # Estrutura da Tabela de Permissões # CREATE TABLE /*!32312 IF NOT EXISTS*/ `permissoes` ( `id_usuario` int(3) NOT NULL DEFAULT '0', `id_menu` int(3) NOT NULL DEFAULT '0', PRIMARY KEY (`id_menu`,`id_usuario`) ) TYPE=MyISAM DEFAULT CHARSET=latin1;
Dica: Vale lembrar que o ícone dos pais são definidos pelo nome da classe CSS e os filhos devemos especificar o caminho físico da imagem. Não sei por que, mas sub-menus não possuem o atributo “iconCls”. No PHP já vamos levar isso em conta.
A outra parte do nosso Menu é a montagem do Json que irá ser lido no ExtJS. Este método foi testado apenas com 1 sub-nível de menu, mas é fácil de modificar para funcionar com mais. Se alguém fizer, comente a experiência. O método é bem simples de entender. Basicamente buscamos os ítens do Menu principal e percorremos ele em busca de sub-menus alocando tudo em um array associativo.
PHP
private function trataObjJson($strJson,$arrObjs)
{
foreach($arrObjs AS $obj)
$strJson = str_replace("\"" . $obj . "\"",$obj,$strJson);
return $strJson;
}
public function getMenu()
{
if($this->Search("SELECT id_usuario FROM usuarios WHERE id_usuario=" . $_SESSION['id_usuario']))
{
$menu = "";
$tmpMenuPai = $this->Search("SELECT A.id_menu,id,menu,ordem,pai,ico,funcao FROM menu A JOIN permissoes B ON A.id_menu=B.id_menu WHERE A.pai=0 AND B.id_usuario=" . $_SESSION['id_usuario'] . " ORDER By A.ordem");
$i=0;
$funcoes = array();
foreach($tmpMenuPai AS $item)
{
$menu[$i]['text'] = $item['menu'];
$menu[$i]['iconCls'] = $item['ico'];
$menu[$i]['tabIndex'] = $i;
if($item['funcao']) {
$menu[$i]['id'] = $item['id'];
$menu[$i]['handler'] = $item['funcao'];
$funcoes[] = $item['funcao'];
}
$tmpMenuFilho = $this->Search("SELECT A.id_menu,menu,id,ordem,ico,funcao FROM menu A JOIN permissoes B ON A.id_menu=B.id_menu WHERE A.pai=" . $item['id_menu'] . " AND B.id_usuario=" . $this->_id . " ORDER By A.ordem");
$arrFilho = Array();
$j=0;
foreach($tmpMenuFilho AS $filho)
{
$arrFilho[$j]['text'] = $filho['menu'];
$arrFilho[$j]['icon'] = $filho['ico'];
if($filho['funcao']) {
$arrFilho[$j]['id'] = $filho['id'];
$arrFilho[$j]['handler'] = $filho['funcao'];
$funcoes[] = $filho['funcao'];
}
$j++;
}
if($arrFilho)
$menu[$i]['menu'] = $arrFilho;
$i++;
}
header("Content-Type: application/json");
echo $this->trataObjJson(json_encode($menu),$funcoes);
}
}
Observe que precisamos de um método auxiliar para tratar as funções. Isso se deve pelo fato da função json_encode do PHP colocar áspas em tudo, então para o ExtJS não interpretar nossa função como uma string e gerar um erro, utilizamos uma função para retira-las.
Agora que já temos a nossa estrutura de menu em Json, bastam poucas linhas em ExtJS para finalizar:
ExtJS
Ext.onReady(function(){
var conn = new Ext.data.Connection();
conn.request({
url: 'inc/php/menu.class.php',
success: function(a){Ext.getCmp('menuPrincipal').bottomToolbar.add(Ext.util.JSON.decode(a.responseText));},
failure: function(){Ext.MessageBox.alert('Erro', 'Erro ao carregar menu. Atualize a página.');}
});
});
Espero ter ajudado.