Archive for the ‘ ExtJS ’ Category

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.

Sistema de Autenticação com ExtJS

Vamos construir um sistema simples de autenticação utilizando o ExtJS. Feito o Download, vamos iniciar nosso sistema carregando a biblioteca do ExtJS para montarmos o nosso sistema de login. Nosso ponto de partida é o arquivo Index.php com a estrutura HTML a seguir:

Index.php

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
	<head>
	<link rel="stylesheet" type="text/css" href="/igs/includes/ext/resources/css/ext-all.css">
	<script type="text/javascript" src="/igs/includes/ext/adapter/ext/ext-base.js"></script>
	<script type="text/javascript" src="/igs/includes/ext/ext-all.js"></script>
	<script type="text/javascript" src="login.js"></script>
	</head>
	<body></body>
</html>
Obviamente, modifique os path de acordo com seu diretório EXT. Veremos o código do Login.js a seguir

Obviamente, modifique os paths de acordo com seu diretório EXT. Veremos o código do Login.js a seguir

Login.js

A seguir vem o login.js. Ele cria o formulário, renderiza uma janela popup, exibe a janela ao usuário, submete os dados via AJAX, e lida com o sucesso e o fracasso de resposta dependendo se o usuário inseriu os dados com sucesso.

Ext.onReady(function(){
    Ext.QuickTips.init();

	// Crie uma variável para armazenar nosso EXT Form Panel 
	// Assinamos várias opções de configuração	 
    var login = new Ext.FormPanel({
        labelWidth:80,
        url:'login.asp',
        frame:true,
        title:'Entre com seu Login',
        defaultType:'textfield',
	monitorValid:true,
	// Atributos específicos para os campos de usuário/senha. 
	// O atributo "name" define o nome da variável que será enviada do servidor.
        items:[{
                fieldLabel:'Usuário',
                name:'loginUsername',
                allowBlank:false
            },{
                fieldLabel:'Senha',
                name:'loginPassword',
                inputType:'password',
                allowBlank:false
            }],

	// Toda a mágica que acontece depois que o usuário clique no botão     
        buttons:[{
                text:'Login',
                formBind: true,
                // Função que é executada quando o usuário clicar no botão 
                handler:function(){
                    login.getForm().submit({
                        method:'POST',
                        waitTitle:'Conectando',
                        waitMsg:'Enviando dados...',

			// Função que executa (sucesso ou falha) quando o servidor responder. 
			// A que será executada é determinada pela 
			// responsta que virá do login.asp como mostrado abaixo. O servidor responde 
			// um JSON válido. 
			// Algo como: response.write "{ success: true}" ou
			// responde.write "{ success: false, errors: { reason: 'Falha no Login. Tente novamente.' }}" 
			// dependendo da lógica que contiver no código de retorno do servidor.
			// Se o sucesso ocorrer, o usuário será notificado com uma mensagem de alerta messagebox, 
			// e quando ele clicar em "Ok", então será redirecionado a qualquer página
			// que você tenha definido para redirecionamento. 

                        success:function(){
                        	Ext.Msg.alert('Status', 'Login Successful!', function(btn, text){
				   if (btn == 'ok'){
		                        var redirect = 'test.php';
		                        window.location = redirect;
                                   }
			        });
                        },

			// Função de falha, veja comentário sobre re: sucesso e falha. 
			// Você poderá ver aqui, se o login falhar, chama uma messagebox
			// com detalhes da falha  

                        failure:function(form, action){
                            if(action.failureType == 'server'){
                                obj = Ext.util.JSON.decode(action.response.responseText);
                                Ext.Msg.alert('Login Failed!', obj.errors.reason);
                            }else{
                                Ext.Msg.alert('Warning!', 'Authentication server is unreachable : ' + action.response.responseText);
                            }
                            login.getForm().reset();
                        }
                    });
                }
            }]
    });

	// Aqui é criado uma janela para agregar o formulário. 
	// O objeto login é passado como ítem desta janela.       
    var win = new Ext.Window({
        layout:'fit',
        width:300,
        height:150,
        closable: false,
        resizable: false,
        plain: true,
        border: false,
        items: [login]
	});
	win.show();
});

Login.php

Aqui é onde o servidor processa o seu login. Vou me apegar a colocar apenas um código simples para mostrar as respostas que serão retornadas, e tederminar que função o login.js executará (sucesso ou falha). Contanto, aqui é onde você deverá chamar seu banco de dados com o usuário/senha da variável, da autenticação, e por fim enviar uma das mensagens de resposta dependendo se o usuário digirou uma credencial válida.

<?php
$loginUsername = isset($_POST["loginUsername"]) ? $_POST["loginUsername"] : "";

if($loginUsername == "f"){
    echo "{success: true}";
} else {
    echo "{success: false, errors: { reason: 'Falha no login. Tente novamente.' }}";
}
?>

Ou, você pode usar PHP avançado com array associativo e a função json_encode, e renderizar a resposta em JSON. Isso pode ser útil para não ter trabalho braçal caso esteja utilizando um JSON mais complexo.

<?php
$loginUsername = isset($_POST["loginUsername"]) ? $_POST["loginUsername"] : "";

if($loginUsername == "f"){
    $result["success"] = true;
} else {
    $result["success"] = false;
    $result["errors"]["reason"] = "Falha no Login. Tente novamente.";
}
echo json_encode($result);
?>

Você vai notar uma linha no login.js que redireciona para text.php caso um login bem sucedido aconteça. Esta pode ser, obviamente, qualquer que seja a página principal de sua aplicação.

Baseado no original de David Fitch: Tutorial: Basic Login

Criando Rich Internet Applications com ExtJS

mb_extjs_splashExtJS é sem dúvida uma das ferramentas mais poderosas que temos hoje para se criar Aplicativos Web robustas, a grande vantagem é a facilitade de se criar elementos com boa usabilidade e instintivos.

Trata-se de um Framework Client-side para criar Rich Internet Applications (RIA). Com a variedade de funcionalidades existentes na versão 3.0 e as contribuições avulsas de usuários, ele se torna uma ferramenta completa para se criar diversos aplicativos complexos.

tasksO mais interessante, é o visual da aplicação. É possível criar aplicações que se passam por aplicações desktop devido a riqueza dos componentes. Isso faz com que usuários mais leigos tenham uma facilidade maior ao usar sua aplicação por estar habituado a usar softwares como o pacote do Office 2007, e outros softwares populares, tornando sua aplicação bem intuitiva. Na página de exemplos você pode ter uma noção do que pode ser feito.

Obviamente nem tudo são flores. Apesar de ter a possibilidade de personalizar o framework apenas com os módulos que você irá utilizar em sua aplicação (como o jQuery), o tamanho final da aplicação se torna um tanto quanto “pesada” se comparado a interfaces criadas diretamente com HTML acompanhado de JavaScript. Então antes de sair usando, é melhor botar na balança a real complexidade de seu aplicativo pois muitos podem se enganar com a facilidade de criar interfaces com boa aparência e acabar usando um canhão para matar uma mosca.

No entando, estamos lidando com uma estrura um pouco diferente. No ExtJS todas as interfaces são carregadas ao acessar a aplicação. O que na minha opinião é bem interessante, após carregado, sua aplicação web não fará nenhum reload na página para acessar qualquer área interna do seu sistema (sem contar que no próximo acesso, sua interface provavelmente estará no Cache do navegador).  Todos os dados de banco são carregados através de uma requisição HTTPrequest recebendo um XML ou Json como resposta, o que abre o leque para se trabalhar com WebService, ou fazer com que sua aplicação também esteja disponível Offline através do Google Gears.

Nos próximos posts vou explicar na prática como iniciar com ExtJS, colocar exemplos e indicar boas práticas de minhas experiências anteriores.

The Ubuntu Counter Project - user number # 31874