Categorias e subcategorias: Exemplo de modelagem

Um erro muito comum em modelagem de dados concerne a sistemas de categorias e subcategorias. Muitos não sabem como modelar o banco de dados, criam diversas tabelas e acabam complicando o que é simples.

Mostrarei um forma muito simples de como armazenar essas informações num banco de dados e como exibi-las na tela, na forma de lista, técnica muito utilizada para construção de menus.


Vamos à modelagem, primeiramente.

Teremos apenas uma tabela. Esta é a estrutura dela:

(usarei MySQL neste artigo, mas a lógica da modelagem independe do SGBD usado)

CREATE TABLE categorias(
	id INT(5) UNSIGNED NOT NULL AUTO_INCREMENT,
	id_pai INT(5) UNSIGNED NOT NULL,
	nome VARCHAR(20) NOT NULL,
	PRIMARY KEY (id)
) DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

Vamos popular a tabela da seguinte forma:

INSERT INTO categorias(id, id_pai, nome) VALUES
(1, 0, 'A Empresa'),
(2, 1, 'Sobre Nós'),
(3, 1, 'Objetivos'),
(4, 3, 'Objetivo dos nossos clientes'),
(5, 0, 'Contato'),
(6, 0, 'Produtos');

Obteremos a seguinte tabela:

mysql> select * from categorias;
+----+--------+----------------------+
| id | id_pai | nome                 |
+----+--------+----------------------+
|  1 |      0 | A Empresa            | 
|  2 |      1 | Sobre Nós           | 
|  3 |      1 | Objetivos            | 
|  4 |      3 | Objetivo dos nossos  | 
|  5 |      0 | Contato              | 
|  6 |      0 | Produtos             | 
+----+--------+----------------------+
6 rows in set (0,00 sec)

Nessa estrutura, temos três seções principais: “A Empresa”, “Contato” e “Produtos”. As categorias “Sobre Nós” e “Objetivos” são subcategorias de “A Empresa”. E “Objetivos dos nossos clientes” é subcategoria de “Objetivos”, que, por sua vez, é subcategoria de “A Empresa”, como citado anteriormente.

Vamos fazer uma seleção dessas informações e colocá-las num arrray, como o exibido abaixo.

// array que conterá as categorias
$cats = array();
 
$mysqli = new mysqli( 'localhost', 'user', 'senha', 'bancoDeDados' );
 
$sql = 'SELECT id, id_pai, nome FROM categorias';
 
$exec = $mysqli->query( $sql ) or exit( $mysqli->error );
 
$i = 1;
while ( $f = $exec->fetch_object() )
{
	$cats[$i]['id'] = $f->id;
	$cats[$i]['id_pai'] = $f->id_pai;
	$cats[$i]['nome'] = $f->nome;
	$i++;
}

Obteremos um array como o exibido abaixo:

$cats[1]['id_pai'] = 0;
$cats[1]['nome'] = 'A Empresa';
$cats[2]['id_pai'] = 1;
$cats[2]['nome'] = 'Sobre Nós';
$cats[3]['id_pai'] = 1;
$cats[3]['nome'] = 'Objetivo';
$cats[4]['id_pai'] = 3;
$cats[4]['nome'] = 'Objetivos dos Nossos Clientes';
$cats[5]['id_pai'] = 0;
$cats[5]['nome'] = 'Contato';
$cats[6]['id_pai'] = 0;
$cats[6]['nome'] = 'Produtos';

Note que o array não começou em zero. Os índices do array são os ID’s das categorias no banco de dados. Se começasse em zero, causaria conflito com o id_pai, que é zero para categorias principais.

Agora postarei uma função simples em PHP que montará o menu completo.

/**
 * Função que monta o menu com as categorias e subcategorias.
 * @param id_pai ID da categoria pai cujas subcategorias serão buscadas.
 * @param ArrayCats Array com as categorias do menu.
*/
function montaMenu( $id_pai, $arrayCats )
{
	// calcula o número de índices do array
	$catsSize = count( $arrayCats );
 
	echo "<ul>";
 
	for ( $i = 1; $i <= $catsSize; $i++ )
	{
		if ( $arrayCats[ $i ]['id_pai'] == $id_pai )
		{
			echo "<li>";
			echo $arrayCats[ $i ]['nome'];
 
			// busca as subcategorias da categoria atual
			montaMenu( $arrayCats[ $i ]['id'], $arrayCats );
 
			echo "</li>";
		}
	}
	echo "</ul>";
}

Você pode usar duas variáveis globais, se quiser: o array das categorias e a variável $catsSize. Isso reduz o processamento, uma vez que a função count() seria chamada apenas uma vez. Porém, para projetos grandes, com diversos menus, essa prática não seria bem-vinda.

Para exibir o menu, basta chamar a função da seguinte forma:

montaMenu( 0, $cats );

Ela começará buscando as categorias principais (id_pai = 0) e depois buscará por cada subcategoria.

 

The following two tabs change content below.

Roberto Beraldo

Related posts