Entendendo o relacionamento de tabelas no banco de dados

Dando continuidade ao tutorial do Data Mapper para Code Igniter hoje vou escrever sobre um assunto que sempre complicou minha vida quando o assunto é MySQL: relacionamento de tabelas.

Este post explicará apenas o básico sobre relacionamento, quando finalizei ele tratando de relacionamento e do uso de relacionamentos no Data Mapper ele acabou bastante extenso, optei por quebrar o post em dois para facilitar a leitura.

Se você já entende de relacionamentos não perca tempo com este post, aguarde o tutorial específico de como usar relacionamentos no Data Mapper para Code Igniter (será linkado neste post assim que for publicado!).

 

O que é relacionamento de tabelas?

Primeiro vamos entender um pouco sobre o funcionamento e tipos de relacionamento, deixando de lado o Data Mapper e falando apenas da questão lógica do negócio.

O relacionamento existe quando um ou mais dados de uma tabela estão relacionados de alguma forma com um ou mais dados de outra tabela.

Por exemplo, temos uma tabela d usuários (users) e uma tabela de posts (posts), cada usuário pode publicar infinitos posts porém cada post poderá ter apenas um usuário. Estas tabelas estão relacionadas.

Existe também relacionamento de dados de uma tabela com outros dados desta mesma tabela. Um usuário (user) pode ter vários amigos da mesma tabela (user), então os dados estão relacionados com dados da mesma tabela.

Agora vamos aos tipos de relacionamento:

 

Relacionamento um para um (one to one)

Neste tipo de relacionamento um dado de uma tabela equivale a um dado em outra tabela exatamente.

Por exemplo um usuário (table users) está relacionado a um endereço na tabela adress, e cada endereço só está relacionado a um usuário.

 

Relacionamento um para muitos – One to Many

No relacionamento um para muitos um dado da tabela um pode estar relacionado a diversos dados da tabela dois, porém cada dado da tabela dois estão relacionados a apenas um dado da tabela um.

Por exemplo um user (table users) pode estar relacionado a diversas casas (table houses), porém cada casa só está relacionada a um user.

 

Relacionamento muitos para muitos – Many to many

No "many to many" os dados da primeira tabela podem estar relacionados a diversos dados da segunda tabela e os dados da segunda tabela também podem estar relacionados a diversos dados da primeira tabela.

Exemplo: um usuário pode ter diversas habilidades (user com diversos relacionamentos para a tabela skills) e cada habilidade também pode estar relacionada a diversos usuários (dado da tabela skill relacionado a diversos dados da tabela users).

 

 

Estrutura das tabelas para relacionamento

Agora que já conhecemos os tipos de relacionamento, vamos entender como estruturar nosso banco de dados para permitir o acesso fácil aos dados relacionados.

Quando o relacionamento é um para um ou um para muitos podemos estruturar as colunas diretamente na tabelas relacionadas, continuando com o exemplo da tabela users e posts, na nossa tabela posts  podemos ter uma coluna chamada user_id  que identifica a qual user está relacionado aquele post.

Table users

id | name | email

 

Table posts

id | title | content | user_id

 

No exemplo acima temos automaticamente um relacionamento um para muitos de users->posts e um para um de posts->users.

Quando o relacionamento é muitos para muitos a estrutura do exemplo acima não é viável (a não ser com uma boa gambiarra, com split de valores e performance porca como eu já fiz). A solução é "quebrar" o relacionamento e inserí-lo em uma nova tabela destinada somente a isso.

Vamos supor que temos uma tabela images onde ficam armazenadas as imagens relacionadas aos posts. Um post poderá ter diversas images e uma image poderá ser utilizada em múltiplos posts. Para fazer este relacionamento criamos uma tabela de relacionamento, que para ilustrar este exemplo chamaremos de images_posts e terá a estrutura abaixo:

TABLE IMAGES_POSTS

id | image_id | post_id

 

Com este tipo de estruturação podemos relacionar infinitos posts com infinitas images. Por exemplo, o post com id = 4 poderá ter as imagens com id = 8, id = 9 e id = 10.

Teremos:

TABLE IMAGES_POSTS

id | image_id | post_id

1  | 8                | 4

2  | 9                | 4

3  | 10              | 4

 

Pronto, estrutura feira e as images 8, 9 e 10 também poderão estar relacionadas a outros posts também, apenas inserindo mais dados nesta tabela de relacionamento.

 

O próximo post explicará como inserir, acessar e manipulas dados de tabelas com relacionamento utilizando a ferramenta ORM Data Mapper para Code Igniter!

Espero que este post seja uma boa referência para estudos, para dar continuidade ao aprendizado veja alguns livros sobre MySQL que podem te ajudar.

Usando o Data Mapper no Code Igniter

Este post nasceu da necessidade de explicar um pouco mais o funcionamento do Data Mapper para o framework Code Igniter, para ficar mais fácil fazers posts mais avançados utilizando esta ótima ferramenta.

O que é Object-relational mapping (ORM)?

ORM é uma técnica que facilita o acesso e manipulação de banco de dados "transformando-os" como se fossem objetos.

Utilizando ORM o desenvolvedor não precisa se preocupar em escrever a SQL diretamente, a ferramenta ORM (no meu caso o Data Mapper) representa as tabelas do banco de dados com classes, e instâncias destas classes fazem as manipulações e consultas necessárias.

As principais vantagens do ORM é a produtividade, pois o código escrito reduz bastante, facilitando desenvolver e manter aplicações.

Eu comecei recentemente a utilizar o Code Igniter (o primeiro projeto é o novo And After) e estou gostando muito, estou muito mais produtivo mesmo trabalhando com linguagem e ferramentas que ainda não domino completamente: PHP, Code Igniter e ORM.

 

Database

Database,database… qual era aquela coluna mesmo?

Data Mapper

Data Mapper (DM) é um ORM para quem utiliza o framework Code Igniter (CI), e facilita muito qualquer consulta e manipulação ao banco.

O primeiro passo é instalar o Data Mapper no seu CI, seguindo os passos abaixo:

  1. Baixe a última versão do DM e descompacte
  2. Opcional: faça suas configurações do DM no arquivo application/config/datamapper.php
  3. Coloque o  application/config/datamapper.php na pasta application/config folder do seu CodeIgniter
  4. Coloque o application/libraries/datamapper.php na pasta application/libraries do seu Code Igniter.
  5. Coloque o application/languages/english/datamapper_lang.php na pasta application/language/english do seu Code Igniter (aqui você pode adicionar os idiomas que quiser, eles contem as mensagens de erro do DM).
  6. Configue o  application/config/autoload.php e adicione a biblioteca do datamapper e database no array do autoload

$autoload["libraries"] = array("database", "datamapper");

Com isso seu aplicativo deve estar pronto para utilizar o Data Mapper!

Abaixo vou publicar exemplos básicos de uso do Data Mapper para consultar o seu banco alterar e inserir dados. Será bem superficial, o objetivo deste post é introduzir  ORM e o Data Mapper para quem está começando ou pretende começar a utilizar o Code Igniter.

 

Começando – uma classe para cada tabela

Relembrando: utilizando uma ferramenta ORM (neste caso o Data Mapper) cada tabela será representada por uma classe no seu Model (usando MVC), e esta classe extenderá a classe do Data Mapper.

Como exemplo vou usar parte do código do backend desenvolvido para o And After, temos uma tabela users, então na camada Model temos a seguinte classe:

class User extends DataMapper {
    var $table = "users";

    function User()
    {
        parent::DataMapper();
    }
}

 

Neste exemplo acima a definição da variável $table é opcional, pois quando ela não está definida o Data Mapper automaticamente define table como o plural (adicionando o "s" ao final) do nome da sua classe. 

 

Consultando o banco de dados – Função Get

Agora vamos ver como o Data Mapper aumenta a produtividade no desenvolvimento, no exemplo abaixo vou fazer uma consulta que retorne todas as linhas e colunas da tabela users, utilizando a classe User criada no exemplo acima.

$u = new User();
$u->get();

Fácil assim, o $u é um objeto com todos os resultados da nossa consulta que seria o mesmo que:

get * from users

 

Limit

Sabemos que não é bom para a performance da nossa aplicação o get * e nem consultas sem um LIMIT definido, para definir o limite é simples, vamos retornar 5 usuários apenas:

$u = new User();
$u->get(5);

E no exemplo abaixo, pegando 5 usuários começando a partir do 10:

$u = new User();
$u->get(5,10);

 

Selecionando as colunas – select

E agora selecionando as colunas que serão retornadas para evitar consultar dados desnecessários, vamos pegar apenas o user e email dos usuários.

$u = new User();
$u->select("user,email");
$u->get(5);

 

Fazendo buscas – where

Vamos buscar o usuário que tenha o user "tester":

$u = new User();
$u->where("user", "tester");
$u->get(1);

 

Você pode usar diversos "where" em uma mesma consulta, e existe também o "or_where" como no exemplo abaixo:

Fazendo buscas – or_where

$u = new User();
$u->where("user", "tester");
$u->or_where("id", "1");
$u->get();

Neste caso vai retornar 1 user se o user com ID 1 for o "tester" ou dois, caso eles sejam diferentes.

 

Ordenando a consulta – order_by

Pegando 15 usuários ordenados pelo nome:

$u = new User();
$u->order_by("name asc")
$u->get(15);

 

Aqui estão os exemplos básicos de consultas utilizando o Data Mapper, recomendo que você leia e releia a documentação da função Get (en) para consultas avançadas.

 

Manipulando os objetos da consulta

Agora você aprendeu a fazer a consulta, já tem sua camada de Model estruturada com uma classe para cada tabela, vamos manipular os dados!

Para exemplificar como é a manipulação dos dados de uma consulta, vamos criar um array com o nome dos últimos usuários cadastrados:

//Consulta os usuários ordenado pela data
$u = new User();
$u->select("name");
$u->order_by("date DESC");
$u->get(10);

//Vamos criar um array com o nome dos usuários da consulta acima
$arr = array();
foreach ($u->all as $user)
{
    $arr[] = $user->name;
}

 

Quando o resultado é apenas um objeto pode ser feito da seguinte forma:

$u = new User();
$u->select("id,name");

$u->get(1);

echo $u->id ." - ". $u->name;

 

Espero que você, que usa o Code Igniter mas ainda não usa o Data Mapper em breve seja mais um adepto!

O próximo post sobre o Code Igniter será o relato da dificuldade que tive para estruturar a primeira aplicação e dividir corretamente as camadas Model, View e Controller (MVC) e do Data Mapper já tenho um começado que trata de relacionamento de tabelas do banco de dados utilizando esta ferramenta.

Espero que gostem, dúvidas, críticas e sugestões nos comentários!

Velocity – incluindo diversos arquivos através de um loop

O Chris já publicou aqui um tutorial de Velocity, uma linguagem de templates que estou usando diariamente no trabalho.

Como eu não conhecia a linguagem até começar a trabalhar aqui, existem várias coisas que são são novidades para mim – e os blogs e docmentações estão ajudando a aumentar a produtividade.

Para compartilhar o que aprendi (e servir para minhas consultas futuras), fiz algumas contribuições com posts aqui no O Desenvolvedor, e entre as relacionadas ao Velocity (e Java) destaco duas:

  1. Formatação de datas em Java
  2. Loop no Velocity com limite numérico (foreach)

 

Velocity – Loop de includes usando variáveis

Estava estudando métodos para dar include (parse) em arquivos com o Velocity, e em um caso específico queria incluir diversos arquivos através de um loop: código enxuto, ao invés de adicionar uma linha para cada parse.

Se você não sabe como funciona o parse no Velocity, veja este exemplo de código.

 

 

Para ilustrar este post, criei um "problema" e abaixo explico a solução.

 

Problema
Necessário fazer diversos includes a partir de uma lista de arquivos (string).

Solução
Pegar a lista, transformar em array e usar o parse para cada elemento do array

 

Supondo que você tem a string: "include1,include2,include5" e estes são os nomes de arquivos que você precisa incluir, o primeiro passo é dar um split pelas vírgulas e transformar isso em um array.

 

 

Primeiro setamos uma variável ($inc) com a lista de includes que serão feitos

#set($inc = "include3,include4,include9")

Abaixo utilizo o método split (ler documentação) na variável $inc gerada anteriormente, separado os elementos pela vírgula e criando um array com os nomes dos arquivos (o array poderia ser criado diretamente, porém usei o string para enriquecer mais o exemplo).

#set($arr = $stringUtils.split($inc,","))

Pronto, agora temos um array com o nome dos arquivos e é aqui que a "mágica" começa. Criamos um loop (foreach) para o array, e dentro dele definimos uma variável com o caminho do arquivo que será incluído e chamamos o parse para a variável do caminho ($dir).

#foreach($o in $arr)
   #set($dir = "includes/vm/"+$o+".vm")
   #parse($dir)
#end

 

Tentei concatenar o nome do arquivo (elemento do array) com o caminho direto na linha do parse e não funcionou. O workarround de definir a variável antes resolve o problema!

Espero que seja útil, esse script pode ser bastante útil para o controle de includes!

Criar atalhos no teclado com Javascript e jQuery

Depois de publicada a tabela de Key Codes para javascript vamos aprender algumas formas mais avançadas para criar atalhos de interface para sites utilizando o teclado.

O exemplo simples já foi dado no post da tabela de keycodes, fiz um exemplo um pouco mais complexo que permite verificar quando duas teclas estão pressionadas, para criar atalhos para por exemplo salvar um post que o usuário está escrevendo com o CTRL+S, ou permitir a um usuário da internet utilizar o CTRL+O para abrir um documento…

O exemplo abaixo não utiliza nenhuma biblioteca e comentei as linhas para facilitar o entendimento, segue o código:

var pressedCtrl = false;
//Quando uma tecla for liberada verifica se é o CTRL para notificar que CTRL não está pressionado
document.onkeyup=function(e){
	if(e.which == 17)
	pressedCtrl =false;
}
// Quando alguma tecla for pressionada:
// Primeiro if - verifica se é o CTRL e avisa que CTRL está pressionado
// Segundo if - verifica se a tecla é o "s" (keycode 83) para executar a ação
document.onkeydown=function(e){
	if(e.which == 17)
		pressedCtrl = true;
	if(e.which == 83 && pressedCtrl == true) {
		//Aqui vai o código e chamadas de funções para o ctrl+s
		alert("CTRL + S pressionados");
	}
}

No caso acima utilizei uma variável "pressedCtrl" que controla quando a tecla CTRL está pressionada e só se este caso for true ele executará as ações dos atalhos.

Com jQuery fica quase a mesma coisa – agora sem os comentários.

 

var pressedCtrl = false;
$(document).keyup(function (e) {
	if(e.which == 17)
		pressedCtrl=false;
})
$(document).keydown(function (e) {
	if(e.which == 17)
	pressedCtrl = true;
	if(e.which == 83 && pressedCtrl == true) {
		//Aqui vai o código e chamadas de funções para o ctrl+s
		alert("CTRL + S pressionados");
	}
});
 

Com os exemplos simples acima é possível incrementar atalhos mais complexos de mais do que 2 teclas, e outras combinações de teclas também.

Agora vamos a um exemplo de atalho de navegação, controlar a paginação de um site pelas teclas direita e esquerda do teclado.  O código abaixo utiliza a tecla da direita para redirecionar a página para a url do link <a> com id="next" e a tecla da esquerda para o link com id "prev".

$(document).ready(function(){
	$("document").keyUp(function(e){
		e.keyCode == 39;
		window.location = $("#next").atrr("href");
	});
	$("document").keyUp(function(e){
		e.keyCode == 37;
		window.location = $("#prev").atrr("href");
	});
});

 

Com um pouco de criatividade é possível aumentar a usabilidade do seu site utilizando estes atalhos – e para interface de intranets é possível melhorar bastante e além da usabilidade aumentar a produtiivdade dos usuários.

Referências

 

 

Tabela de Key Codes para Javascript

Com o javascript é possível identificar as teclas pressionadas pelo usuário e com isso ativar funções: atalhos, controle de interface, jogos, etc.

Comecei um post sobre o controle da interface com teclado utilizando jQuery mas achei interessante (e útil) antes publicar a tabela com todas as Keycodes (códigos que identificam cada tecla do teclado) para javascript.

Segue a tabela com o código de cada tecla:

Key Pressed Key Code
backspace 8
tab 9
enter 13
shift 16
ctrl 17
alt 18
pause/break 19
caps lock 20
escape 27
page up 33
page down 34
end 35
home 36
left arrow 37
up arrow 38
right arrow 39
down arrow 40
insert 45
delete 46
0 48
1 49
2 50
3 51
4 52
5 53
6 54
7 55
8 56
9 57
a 65
b 66
c 67
d 68
e 69
f 70
g 71
h 72
i 73
j 74
k 75
l 76
m 77
n 78
o 79
p 80
q 81
r 82
s 83
t 84
u 85
v 86
w 87
x 88
y 89
z 90
left window key 91
right window key 92
select key 93
numpad 0 96
numpad 1 97
numpad 2 98
numpad 3 99
numpad 4 100
numpad 5 101
numpad 6 102
numpad 7 103
numpad 8 104
numpad 9 105
multiply 106
add 107
subtract 109
decimal point 110
divide 111
f1 112
f2 113
f3 114
f4 115
f5 116
f6 117
f7 118
f8 119
f9 120
f10 121
f11 122
f12 123
num lock 144
scroll lock 145
semi-colon 186
equal sign 187
comma 188
dash 189
period 190
forward slash 191
grave accent 192
open bracket 219
back slash 220
close braket 221
single quote 222

 

Para verificar qual tecla foi pressionada você pode conferir o Key Code no javascript, utilizando o código abaixo:

document.onkeyup=function(e){

   if(e.which == 17){
          //Pressionou CTRL, aqui vai a função para esta tecla.
     return false;
   }

}

Depois publico algumas utilizações dos keycodes, como por exemplo utilizar uma combinação do teclado para dar submit em um form, validar dados, etc…