PHP + MySQL: master-detail + navegação
Carlos Santos
LabMM 4 - NTC - DeCA - UA
Aula PHP+MySQL 02, 03-05-2012
visualizar dados de várias tabelas

Quando queremos visualizar dados que estão distribuídos por duas
tabelas ligadas entre si, podemos:
  • criar um query baseado num JOIN que permita obter todos os dados;
  • criar vários recordsets de acordo com a informação necessária



A solução adequada depende da situação em que se aplica
base para exemplos
listar os mariachis

$query = "SELECT idMariachi, nome FROM Mariachi";
$rsMari = mysql_query($query , $connection);

while ($row_rsMari = mysql_fetch_assoc($rsMari)){
  echo $row_rsMari[“nome"];
}
listar os mariachis com família

$query = "SELECT Mariachi.idMariachi, Mariachi.nome,
Familia.nomeFamilia FROM Mariachi INNER JOIN Familia ON
Mariachi.Familia_idFamilia = Familia.idFamilia";
$rsMari = mysql_query($query , $connection);

while ($row_rsMari = mysql_fetch_assoc($rsMari)){
  echo $row_rsMari[“nome"].” - “.
                      $row_rsMari[“nomeFamilia].”<br/>”;
}
listar os mariachis com família (not so good)

$query = "SELECT idMariachi, nome, Familia_idFamilia FROM
Mariachi";
$rsMari = mysql_query($query , $connection);

while ($row_rsMari = mysql_fetch_assoc($rsMari)){
  $qFami = "SELECT nomeFamilia FROM Familia WHERE
           idFamilia = ".$row_rsMari[“Familia_idFamilia”];
  $rsFami = mysql_query($qFami , $connection);

    $row_rsFami = mysql_fetch_assoc($rsFami);

    echo $row_rsMari[“nome"].” - “.
                        $row_rsFami[“nomeFamilia].”<br/>”;
}
observações

uma página pode ter muitos recordsets

os valores obtidos num recordset podem ser utilizados para filtrar
resultados a obter noutro recordset

soluções com múltiplos acessos há BD são, normalmente, mais lentas

no entanto, existem circunstâncias em que a quantidade de informação
resultante de um INNER JOIN pode justificar a opção por múltiplos
queries!
master - detail

nesta estrutrura de informação temos:

  • uma página inicial que lista vários tópicos de um modo genérico;
  • uma página de detalhe que permite ver os detalhes do tópico escolhido na
    página master


que informação é necessário transferir entre as páginas?


                               querystring: id_item
               master           .../page.php?a=5
                                                         detail
                                                       detalhes do item
                item1                                 escolhido na página
                                                            master
                item2
                item3                                       voltar
exemplo: master-detail

master: listar todas as famílias

detail: listar os mariachis dessa família
exemplo: master > familias.php

$qFami = "SELECT * FROM Familia";
$rsFami = mysql_query($qFami , $connection);

while ($row_rsFami = mysql_fetch_assoc($rsFami)){
  $line = ‘<p><a href=”mariachisFamilia.php?id=’.
          $row_rsFami[“idFamilia”].
          ’”>’.
          $row_rsFami[“nomeFamilia"].
          ‘</a></p>’;

    echo $line;
}

os URLs na página serão, por exemplo: “mariachisFamilia.php?id=3”
exemplo: detail > mariachisFamilia.php

$idValue = intval($_GET['id']);
$qMari = "SELECT * FROM Mariachi
          WHERE Familia_idFamilia = ".$idValue;
$rsMari = mysql_query($qMari , $connection);

while ($row_rsMari = mysql_fetch_assoc($rsMari)){
  $line = ‘<p>$row_rsMari[“nome”]</p>’;

    echo $line;
}



Como mostrar nesta página o nome da família?
exemplo: master-detail (parte 2)

master: listar todas as famílias

detail: listar os mariachis dessa família
         e incluir o número de relacionamentos com chicas
exemplo: master-detail (parte 2)

soluções a discutir:

  • um query único baseado num INNER JOIN entre Mariachis e
    Mariachi_has_chica com operação de COUNT e filtragem pelo Mariachi?
  • um query para o nome do Mariachi e um query para contar o número de
    registos do Mariachi em Mariachi_has_Chica?
exemplo: master-detail (parte 2)

problema com query único, típico destas situações:

  • se um Mariachi não tiver uma ocorrência em Mariachi_has_Chica o
    resultado será um recordset vazio! Porquê?
  • não será possível mostrar os dados da informação pessoal do Mariachi



neste cenário, a solução a adotar deve ser a segunda!

ou ainda melhor... uma solução com OUTER JOIN

TPC -> implementar esta solução :)
exemplo: master-detail (parte 2)

por zonas condicionais entende-se partes do código que devem ser
processadas quando um recordset está ou não vazio

por exemplo:

  • se o mariachi nunca teve relacionamentos apresentar uma mensagem
    “este mariachi não é um bom exemplo!”
  • nos outros casos mostrar os relacionamentos


como implementar este tipo de condição?
  • if ($rsName) ...
navegação e paginação

imagina que uma família pode ter centenas de mariachis!

  • faz sentido mostrar numa página uma listagem com um número ilimitado
    de itens?



navegação - permite navegar nos itens, tipicamente:

  • previous - next (page 3 of 6)



paginação - mais complexa e permite navegar diretamente para uma
página, tipicamente

  • 1 ... 5 6 7 8 9 ... 20
navegação

o que é necessário saber

  • número total de registos
  • número de itens por página
  • número da página atual
  • registos para mostrar na página atual
navegação - número total de registos

recordset com query de COUNT de registos da tabela
navegação - número de itens por página

é um valor definido por nós e pode simplesmente ser guardado numa
variável

se o utilizador tiver a possibilidade de alterar então podemos necessitar
de uma cookie ou um parâmetro adicional na querystring
navegação - número da página atual

passado na querystring!

  • next -> lê página atual e soma 1
  • previous -> lê página atual e subtrai 1
  • chama novamente a página com o novo id da página a visualizar
  • é necessário ter em atenção as condições para não permitir clicar nas
    opções quando não existem mais páginas para trás ou para a frente
  • se não há valor da página deve assumir-se que é a primeira que deve ser
    mostrada
  • verificar valores que podem ser introduzidos manualmente no URL
navegação - registos para mostrar na página atual

NUNCA fazer uma query a pedir sempre todos os registos!

na query do pedido deve ser especificado o LIMIT (length e offset)

  • SELECT .... LIMIT offset, length
  • length é o valor do número de itens por página
  • offset é calculado com base na página atual e o número de itens por
    página
desafio

criar uma função genérica que adicione, em qualquer cenário, uma barra
de navegação!
  • navigation_bar(nrTotalItens, nrItensPerPage,
    pageNumber)



NOTA: a função não é responsável por mostrar os registos na página! Essa
lógica é da página e não da função.

DICA: para construir o URL ver chaves da super-variável _SERVER

Aula 02 PHP+MySQL - LabMM4

  • 1.
    PHP + MySQL:master-detail + navegação Carlos Santos LabMM 4 - NTC - DeCA - UA Aula PHP+MySQL 02, 03-05-2012
  • 2.
    visualizar dados devárias tabelas Quando queremos visualizar dados que estão distribuídos por duas tabelas ligadas entre si, podemos: • criar um query baseado num JOIN que permita obter todos os dados; • criar vários recordsets de acordo com a informação necessária A solução adequada depende da situação em que se aplica
  • 3.
  • 4.
    listar os mariachis $query= "SELECT idMariachi, nome FROM Mariachi"; $rsMari = mysql_query($query , $connection); while ($row_rsMari = mysql_fetch_assoc($rsMari)){ echo $row_rsMari[“nome"]; }
  • 5.
    listar os mariachiscom família $query = "SELECT Mariachi.idMariachi, Mariachi.nome, Familia.nomeFamilia FROM Mariachi INNER JOIN Familia ON Mariachi.Familia_idFamilia = Familia.idFamilia"; $rsMari = mysql_query($query , $connection); while ($row_rsMari = mysql_fetch_assoc($rsMari)){ echo $row_rsMari[“nome"].” - “. $row_rsMari[“nomeFamilia].”<br/>”; }
  • 6.
    listar os mariachiscom família (not so good) $query = "SELECT idMariachi, nome, Familia_idFamilia FROM Mariachi"; $rsMari = mysql_query($query , $connection); while ($row_rsMari = mysql_fetch_assoc($rsMari)){ $qFami = "SELECT nomeFamilia FROM Familia WHERE idFamilia = ".$row_rsMari[“Familia_idFamilia”]; $rsFami = mysql_query($qFami , $connection); $row_rsFami = mysql_fetch_assoc($rsFami); echo $row_rsMari[“nome"].” - “. $row_rsFami[“nomeFamilia].”<br/>”; }
  • 7.
    observações uma página podeter muitos recordsets os valores obtidos num recordset podem ser utilizados para filtrar resultados a obter noutro recordset soluções com múltiplos acessos há BD são, normalmente, mais lentas no entanto, existem circunstâncias em que a quantidade de informação resultante de um INNER JOIN pode justificar a opção por múltiplos queries!
  • 8.
    master - detail nestaestrutrura de informação temos: • uma página inicial que lista vários tópicos de um modo genérico; • uma página de detalhe que permite ver os detalhes do tópico escolhido na página master que informação é necessário transferir entre as páginas? querystring: id_item master .../page.php?a=5 detail detalhes do item item1 escolhido na página master item2 item3 voltar
  • 9.
    exemplo: master-detail master: listartodas as famílias detail: listar os mariachis dessa família
  • 10.
    exemplo: master >familias.php $qFami = "SELECT * FROM Familia"; $rsFami = mysql_query($qFami , $connection); while ($row_rsFami = mysql_fetch_assoc($rsFami)){ $line = ‘<p><a href=”mariachisFamilia.php?id=’. $row_rsFami[“idFamilia”]. ’”>’. $row_rsFami[“nomeFamilia"]. ‘</a></p>’; echo $line; } os URLs na página serão, por exemplo: “mariachisFamilia.php?id=3”
  • 11.
    exemplo: detail >mariachisFamilia.php $idValue = intval($_GET['id']); $qMari = "SELECT * FROM Mariachi WHERE Familia_idFamilia = ".$idValue; $rsMari = mysql_query($qMari , $connection); while ($row_rsMari = mysql_fetch_assoc($rsMari)){ $line = ‘<p>$row_rsMari[“nome”]</p>’; echo $line; } Como mostrar nesta página o nome da família?
  • 12.
    exemplo: master-detail (parte2) master: listar todas as famílias detail: listar os mariachis dessa família e incluir o número de relacionamentos com chicas
  • 13.
    exemplo: master-detail (parte2) soluções a discutir: • um query único baseado num INNER JOIN entre Mariachis e Mariachi_has_chica com operação de COUNT e filtragem pelo Mariachi? • um query para o nome do Mariachi e um query para contar o número de registos do Mariachi em Mariachi_has_Chica?
  • 14.
    exemplo: master-detail (parte2) problema com query único, típico destas situações: • se um Mariachi não tiver uma ocorrência em Mariachi_has_Chica o resultado será um recordset vazio! Porquê? • não será possível mostrar os dados da informação pessoal do Mariachi neste cenário, a solução a adotar deve ser a segunda! ou ainda melhor... uma solução com OUTER JOIN TPC -> implementar esta solução :)
  • 15.
    exemplo: master-detail (parte2) por zonas condicionais entende-se partes do código que devem ser processadas quando um recordset está ou não vazio por exemplo: • se o mariachi nunca teve relacionamentos apresentar uma mensagem “este mariachi não é um bom exemplo!” • nos outros casos mostrar os relacionamentos como implementar este tipo de condição? • if ($rsName) ...
  • 16.
    navegação e paginação imaginaque uma família pode ter centenas de mariachis! • faz sentido mostrar numa página uma listagem com um número ilimitado de itens? navegação - permite navegar nos itens, tipicamente: • previous - next (page 3 of 6) paginação - mais complexa e permite navegar diretamente para uma página, tipicamente • 1 ... 5 6 7 8 9 ... 20
  • 17.
    navegação o que énecessário saber • número total de registos • número de itens por página • número da página atual • registos para mostrar na página atual
  • 18.
    navegação - númerototal de registos recordset com query de COUNT de registos da tabela
  • 19.
    navegação - númerode itens por página é um valor definido por nós e pode simplesmente ser guardado numa variável se o utilizador tiver a possibilidade de alterar então podemos necessitar de uma cookie ou um parâmetro adicional na querystring
  • 20.
    navegação - númeroda página atual passado na querystring! • next -> lê página atual e soma 1 • previous -> lê página atual e subtrai 1 • chama novamente a página com o novo id da página a visualizar • é necessário ter em atenção as condições para não permitir clicar nas opções quando não existem mais páginas para trás ou para a frente • se não há valor da página deve assumir-se que é a primeira que deve ser mostrada • verificar valores que podem ser introduzidos manualmente no URL
  • 21.
    navegação - registospara mostrar na página atual NUNCA fazer uma query a pedir sempre todos os registos! na query do pedido deve ser especificado o LIMIT (length e offset) • SELECT .... LIMIT offset, length • length é o valor do número de itens por página • offset é calculado com base na página atual e o número de itens por página
  • 22.
    desafio criar uma funçãogenérica que adicione, em qualquer cenário, uma barra de navegação! • navigation_bar(nrTotalItens, nrItensPerPage, pageNumber) NOTA: a função não é responsável por mostrar os registos na página! Essa lógica é da página e não da função. DICA: para construir o URL ver chaves da super-variável _SERVER