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.


Visualizações: 928