Usamos cookies para medir audiência e melhorar sua experiência. Você pode aceitar ou recusar a qualquer momento. Veja sobre o iMasters.
Olá pessoal...
Hoje vamos falar sobre menu de níveis infinitos em PHP... Mas desta vez, vamos criar o menu efetuando somente UMA consulta ao banco de dados. Normalmente quando se fala em criar este tipo de menu, o que é feito:
Fazendo desta forma, se tivermos 20 categorias, e cada categoria tiver 5 sub categorias, e cada sub categoria tiver mais 5 sub sub categorias, teremos 101 consultas ao banco de dados. Imagina isto no seu site, tendo 5 acessos simultâneos – 505 consultas ao banco de dados a cada página aberta. Conseguiu perceber o problema?Agora, como vamos resolver isto?
Banco de dados sugerido
CREATE TABLE IF NOT EXISTS `menu` (
`menuId` INT NOT NULL AUTO_INCREMENT ,
`menuNome` VARCHAR(45) NOT NULL ,
`menuIdPai` INT NOT NULL DEFAULT 0 ,
`menuLink` VARCHAR(45) NULL ,
PRIMARY KEY (`menuId`) )
ENGINE = InnoDB
/applications/core/interface/imageproxy/imageproxy.php?img=http://img195.imageshack.us/img195/4517/menun.png&key=b9f99275f46532caca11ce576c13d96af1d62c5dfaac26f74670439a7a82f1bf" alt="Imagem Postada" />
Incluindo alguns valores.
INSERT INTO menu VALUES
(1, 'A Empresa', 0, 'empresa.php'),
(2, 'Sobre Nós', 1, 'sobre.php'),
(3, 'Objetivos', 1, 'objetivos.php'),
(4, 'Contato', 0, 'contato.php'),
(5, 'Produtos', 0, 'produtos.php'),
(6, 'Informática', 5, 'categoria.php?cat=informatica'),
(7, 'Missão da Empresa', 2, 'missao.php'),
(8, 'Visão da Empresa', 2, 'visao.php'),
(9, 'Televisão', 5, 'categoria.php?cat=televisao'),
(10, 'Computadores', 6, 'subcategoria.php?sub=computadores'),
(11, 'Monitores', 6, 'subcategoria.php?sub=monitores');
Agora, vamos ao código PHP. Faremos a consulta utilizando a classe MySQLi, como mostro abaixo:
<?php
$mysqli = new mysqli('localhost','root','','imasters');
$query = $mysqli->query('SELECT * FROM menu ORDER BY menuIdPai');
while($row = $query->fetch_object())
{
$menuItens[$row->menuIdPai][$row->menuId] = array('link' => $row->menuLink,'name' => $row->menuNome);
}
Ao final deste while, teremos o seguinte array.
Array
(
[0] => Array
(
[1] => Array
(
[link] => empresa.php
[name] => A Empresa
)
[4] => Array
(
[link] => contato.php
[name] => Contato
)
[5] => Array
(
[link] => produtos.php
[name] => Produtos
)
)
[1] => Array
(
[2] => Array
(
[link] => sobre.php
[name] => Sobre Nós
)
[3] => Array
(
[link] => objetivos.php
[name] => Objetivos
)
)
[2] => Array
(
[7] => Array
(
[link] => missao.php
[name] => Missão da Empresa
)
[8] => Array
(
[link] => visao.php
[name] => Visão da Empresa
)
)
[5] => Array
(
[9] => Array
(
[link] => categoria.php?cat=televisao
[name] => Televisão
)
[6] => Array
(
[link] => categoria.php?cat=informatica
[name] => Informática
)
)
[6] => Array
(
[10] => Array
(
[link] => subcategoria.php?sub=computadores
[name] => Computadores
)
[11] => Array
(
[link] => subcategoria.php?sub=monitores
[name] => Monitores
)
)
)Então, para exibirmos o menu, utilizando <ul><li>, utilizaremos a função imprimeMenuInfinito. Vamos explicá-la passo a passo.
function imprimeMenuInfinito( array $menuTotal , $idPai = 0 )
{
Aqui recebemos por parâmetro o array criado na consulta ao banco de dados e o idPai, sendo que o valor padrão é 0 (para o menu inicial).
echo '<ul>';
Aqui abrimos a ul do menu principal, mas ainda não fechamos
foreach( $menuTotal[$idPai] as $idMenu => $menuItem)
{
Aqui vamos iniciar a iteração do array. Para cada item do menu que tenha como idPai o idPai passado como parâmetro, vamos ter a chave do array na $idMenu e o seu valor em $menuItem (que também é um array).
echo '<li><a href="',$menuItem['link'],'">',$menuItem['name'],'</a>';
Aqui vamos imprimir o item do menu, utilizando o array menuItem. Veja que ainda não fechamos a li.
if( isset( $menuTotal[$idMenu] ) ) imprimeMenuInfinito( $menuTotal , $idMenu );
Aqui está o segredo. O que verificamos. Se existe o índice do item do menu que está sendo impresso nesta iteração, significa que este menu tem filhos. Então, chamamos novamente a função, passando o menu completo e o id do menu atual (que, como vimos, é o array pai, utilizado para imprimir o item do menu).
echo '</li>';
}
echo '</ul>';
Aqui fechamos a li do item do menu, fechamos o laço e o ul do menu principal.
Para chamar a função, utilizamos o código assim:
imprimeMenuInfinito($menuItens);
Veja que ao chamarmos a função, não adicionamos o parâmetro idPai. Porque isto? Porque definimos o idPai para o primeiro nível como sendo 0, que é o valor padrão da função.
Após executar este código, teremos o seguinte código gerado:
E o seguinte HTML gerado
<ul><li><a href="empresa.php">A Empresa</a><ul><li><a href="sobre.php">Sobre Nós</a><ul><li><a href="missao.php">Missão da Empresa</a></li><li><a href="visao.php">Visão da Empresa</a></li></ul></li><li><a href="objetivos.php">Objetivos</a></li></ul></li><li><a href="contato.php">Contato</a></li><li><a href="produtos.php">Produtos</a><ul><li><a href="categoria.php?cat=televisao">Televisão</a></li><li><a href="categoria.php?cat=informatica">Informática</a><ul><li><a href="subcategoria.php?sub=computadores">Computadores</a></li><li><a href="subcategoria.php?sub=monitores">Monitores</a></li></ul></li></ul></li></ul>
Perai... Mas este HTML tá muito feio (tudo na mesma linha, sem indentação). Então, vamos indentar ele corretamente e colocar as quebras de linha, para ficar completinho.
function imprimeMenuInfinito( array $menuTotal , $idPai = 0, $nivel = 0 )
{
Adicionamos um parâmetro à função, para definir em que nível ela está.
echo str_repeat( "\t" , $nivel ),'<ul>',PHP_EOL;
Aqui utilizamos o \t, que adiciona um tab ao código fonte, sendo repetido de acordo com a $nivel. Ao final da linha, utilizamos a constante PHP_EOL, que significa End Of Line. Esta constante exibe a quebra de linha de acordo com o sistema operacional onde está sendo executado o código. Se for em servidor Windows, \r\n e no Linux \n. Então, utilizando o PHP_EOL, seu código fica portável, pois pode ser executado tanto em servidor Win como em servidor Linux que terá o mesmo comportamento.
echo str_repeat( "\t" , $nivel + 1 ),'<li><a href="',$menuItem['link'],'">',$menuItem['name'],'</a>',PHP_EOL;
Dentro do foreach, fazemos a mesma coisa que fizemos antes, mas adicionamos 1 ao nível do menu.
if( isset( $menuTotal[$idMenu] ) ) imprimeMenuInfinito( $menuTotal , $idMenu , $nivel + 2);
Ao chamarmos recursivamente a função, adicionamos 2 ao nível atual.
echo str_repeat( "\t" , $nivel + 1 ),'</li>',PHP_EOL;
No fechamento do li utilizamos o mesmo nível do li anterior.
echo str_repeat( "\t" , $nivel ),'</ul>',PHP_EOL;
No fechamento do ul utilizamos também o mesmo nível do anterior.
Com este código, o HTML do menu ficou assim:
<ul>
<li><a href="empresa.php">A Empresa</a>
<ul>
<li><a href="sobre.php">Sobre Nós</a>
<ul>
<li><a href="missao.php">Missão da Empresa</a>
</li>
<li><a href="visao.php">Visão da Empresa</a>
</li>
</ul>
</li>
<li><a href="objetivos.php">Objetivos</a>
</li>
</ul>
</li>
<li><a href="contato.php">Contato</a>
</li>
<li><a href="produtos.php">Produtos</a>
<ul>
<li><a href="categoria.php?cat=televisao">Televisão</a>
</li>
<li><a href="categoria.php?cat=informatica">Informática</a>
<ul>
<li><a href="subcategoria.php?sub=computadores">Computadores</a>
</li>
<li><a href="subcategoria.php?sub=monitores">Monitores</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
Legal né? Então, o código completo da função ficou assim.
<?php
/**
* Função imprimeMenuInfinito - Função recursiva utilizada para imprimir
* menu com submenus em níveis infinitos.
*
* @author MatiasRezende - contato@matiasrezende.com.br
* @license http-~~-//creativecommons.org/licenses/by-sa/2.5/br/
* @param array $menuTotal - Array do menu a ser impresso
* @param $idPai - Id da categoria pai
*/
function imprimeMenuInfinito( array $menuTotal , $idPai = 0, $nivel = 0 )
{
// abrimos a ul do menu principal
echo str_repeat( "\t" , $nivel ),'<ul>',PHP_EOL;
// itera o array de acordo com o idPai passado como parâmetro na função
foreach( $menuTotal[$idPai] as $idMenu => $menuItem)
{
// imprime o item do menu
echo str_repeat( "\t" , $nivel + 1 ),'<li><a href="',$menuItem['link'],'">',$menuItem['name'],'</a>',PHP_EOL;
// se o menu desta iteração tiver submenus, chama novamente a função
if( isset( $menuTotal[$idMenu] ) ) imprimeMenuInfinito( $menuTotal , $idMenu , $nivel + 2);
// fecha o li do item do menu
echo str_repeat( "\t" , $nivel + 1 ),'</li>',PHP_EOL;
}echo str_repeat( "\t" , $nivel ),'</ul>',PHP_EOL;
}
$mysqli = new mysqli('localhost','root','','imasters');
$query = $mysqli->query('SELECT * FROM menu ORDER BY menuIdPai');$menuItens[$row->menuIdPai][$row->menuId] = array('link' => $row->menuLink,'name' => $row->menuNome);
}
imprimeMenuInfinito($menuItens);
Espero que tenham gostado.
Carlos Eduardo - Blog OGordo
Carregando comentários...