Foros del Web » Programando para Internet » PHP »

[SOLUCIONADO] Categorias, Subcategorias y Recursividad

Estas en el tema de Categorias, Subcategorias y Recursividad en el foro de PHP en Foros del Web. Buenas! Estoy atascado con este tema... Estoy tratando de mostrar una tabla de mi DB donde almaceno las "Categorias". Estas categorias pueden tener otras subcategorias ...
  #1 (permalink)  
Antiguo 07/08/2014, 05:59
Avatar de fbedia  
Fecha de Ingreso: julio-2010
Mensajes: 159
Antigüedad: 13 años, 9 meses
Puntos: 8
Categorias, Subcategorias y Recursividad

Buenas!
Estoy atascado con este tema...

Estoy tratando de mostrar una tabla de mi DB donde almaceno las "Categorias".

Estas categorias pueden tener otras subcategorias y estas a su vez otras subcategorias.... y estas a su vez podrían tener mas subcategorias...etc..etc..

Un ejemplo de datos seria:
Cita:
- DEPORTES
-- TIERRA
--- FUTBOL
---- FUTBOL BASE
---- FUTBITO
---- FUTBOL PROFESIONAL
--- SKY
--- TENIS
-- MAR
---- REMO
---- NADO
-- AIRE
--- SALTO PARACAIDAS
Como ven, podria habe muchas subcategorias.... y yo desconozco hasta cuantos niveles puede llegar, por eso creo que lo que necesito es una funcion RECURSIVA... pero no doy con la forma de hacerlo :(

La tabla "CATEGORIAS" consta de estos campos:
Cita:
id_categoria (INT)
nombre (TEXT)
id_categoria_padre (INT)
(las categorias principales tienen el id_categoria_padre=0

Les postearia el codigo que tengo.... pero creo que seria peor porque no logro la recursividad.
Lo mejor quizas sea partir de este ejemplo:

Código PHP:
Ver original
  1. $sql = mysqli_query($link,"SELECT id_categoria, nombre, id_categoria_padre FROM categorias WHERE id_categoria_padre=0");
  2.  
  3. $parent = mysqli_fetch_assoc($sql);
  4.  
  5. foreach ($parent as $p)
  6. {
  7.   echo "<h2>{$p['nombre']}</h2><ul>";
  8.   $sql = mysqli_query($link,"SELECT id_categoria, nombre, id_categoria_padre FROM categorias WHERE id_categoria_padre  = '{$p['id_categoria_padre ']}'");
  9.   $child = mysqli_fetch_assoc($sql);
  10.   foreach ($child as $c)
  11.   {
  12.     echo "<li>{$c['nombre']}</li>";
  13.   }
  14.   echo "</ul>";
  15. }

El codigo anterior muestra las categorias padre y un nivel de subcategoria....
Lo que necesito es que se muestre (si lo hay) las subcategorias de las subcategorias...

Espero haberme explicado!
Muchas gracias y un saludo.
__________________
Follow me on twitter @franbedia
  #2 (permalink)  
Antiguo 07/08/2014, 06:34
Avatar de bookmaster  
Fecha de Ingreso: febrero-2002
Ubicación: Toledo
Mensajes: 976
Antigüedad: 22 años, 2 meses
Puntos: 67
Respuesta: Categorias, Subcategorias y Recursividad

Pues usando ejemplos, la cosa sería algo así:
Código PHP:
Ver original
  1. function Listado($Padre = 0){
  2. $Consulta = SELECT * FROM Tabla WHERE id_categoria_padre = $Padre;
  3. echo '<ul>';
  4. // Entras en el bucle que te muestra las categorias
  5.  echo "<li>{$c['nombre']} ". Listado($c['id_categoria_padre'])."</li>";
  6. // Sales del bucle
  7. echo '</ul>';
  8. }
Uso:
Código PHP:
Ver original
  1. echo Listado();

Tendrías que ajustar el código para hacerlo funcional, yo tengo uno ya echo pero ahora mismo no le encuentro, si sólo quieres mostrar una de las categorías con sus subcategorias con poner el valor dentro de Listado(CategoriaInicial) te valdría.
__________________
Decir si te a funcionado la respuesta es ¡GRATIS!. Por favor indicarlo.
http://www.lohacemosweb.net
http://tutoriales.lohacemosweb.net
  #3 (permalink)  
Antiguo 07/08/2014, 11:58
Avatar de Triby
Mod on free time
 
Fecha de Ingreso: agosto-2008
Ubicación: $MX->Gto['León'];
Mensajes: 10.106
Antigüedad: 15 años, 8 meses
Puntos: 2237
Respuesta: Categorias, Subcategorias y Recursividad

Normalmente yo hago una sola consulta, leyendo todas las categorías y cargándolas en un array.

Todo en pseudo-código.

Según tu ejemplo (suponiendo las ID):
Código:
- 1 - DEPORTES
-- 2 - TIERRA
--- 3 - FUTBOL
---- 4 - FUTBOL BASE
---- 5 - FUTBITO
---- 6 - FUTBOL PROFESIONAL
--- 7 - SKY
--- 8 - TENIS
-- 9 - MAR
---- 10 - REMO
La idea es crear un array con un elemento 'todos' que contendrá la información de cada categoría/subcategoría y un elemento para cada categoría que tenga hijos:

Código:
todos => array(
     // ID         ID, Nombre, Padre
      1 => array(1, DEPORTES, 0)
      2 => array(2, TIERRA, 1)
      3 => array(3, FUTBOL, 2)
      4 => array(4, FUTBOL BASE, 3)
      5 => array(5, FUTBITO, 3)
      6 => array(6, FUTBOL PROFESIONAL, 3)
      7 => array(7, SKY, 2)
      8 => array(8, TENIS, 2)
      9 => array(9, MAR, 1)
      10 => array(10, REMO, 9)
)
// Como categoría padre solo está deportes
0 => array(1)
// Deportes tiene 2 hijos: TIERRA y MAR
1 => array(2, 9)
// Tierra tiene 3 hijos: FUTBOL, SKY y TENIS
2 => array(3, 7, 8)
// Futbol tiene 3 hijos
3 => array(4, 5, 6)
// Mar tiene un hijo
9 => array(10)
Después de cargarlas todas, puedes hacer una función (recursiva o no, según necesites) para mostrar todo:

Código:
funcion verCategorias(padre = 0) {
      foreach(categorias[padre] as id) {
            print categorias['todos'][id]['nombre']
            // Revisar si la categoría tiene hijos
            if(isset(categorias[id])) {
                     verCategorias(id)
            }
      }
}
La ventaja de hacerlo así es que economizas recursos al reducir la cantidad de consultas y, además, puedes crear un archivo de caché para agilizar aún más el proceso.
__________________
- León, Guanajuato
- GV-Foto
  #4 (permalink)  
Antiguo 07/08/2014, 12:45
Avatar de alex171294  
Fecha de Ingreso: agosto-2014
Mensajes: 10
Antigüedad: 9 años, 8 meses
Puntos: 2
Respuesta: Categorias, Subcategorias y Recursividad

Cita:
Iniciado por bookmaster Ver Mensaje
Pues usando ejemplos, la cosa sería algo así:
Código PHP:
Ver original
  1. function Listado($Padre = 0){
  2. $Consulta = SELECT * FROM Tabla WHERE id_categoria_padre = $Padre;
  3. echo '<ul>';
  4. // Entras en el bucle que te muestra las categorias
  5.  echo "<li>{$c['nombre']} ". Listado($c['id_categoria_padre'])."</li>";
  6. // Sales del bucle
  7. echo '</ul>';
  8. }
Uso:
Código PHP:
Ver original
  1. echo Listado();

Tendrías que ajustar el código para hacerlo funcional, yo tengo uno ya echo pero ahora mismo no le encuentro, si sólo quieres mostrar una de las categorías con sus subcategorias con poner el valor dentro de Listado(CategoriaInicial) te valdría.
eso que muestras daría con un bucle infinito, ya que por más que la consulta no obtenga resultados de igual manera vuelves a llamar a Listado.

La recursividad es algo complicado, y que puede traer problemas serios si no se aplica correctamente.

Ten en cuenta lo siguiente, puedes hasta hacer consultas (muchas) innecesariamente con recursividad sin notarlo, haciendo tu código bastante pesado de forma innecesaria.

Yo creo que quizá con 2 funciones lo logres de igual manera te dejo aquí una forma recursiva:

function obtenerListado($idPadre = 0)
{
// obtienes todos los registros con idPadre pasado por parametro
// recorres cada uno de estos con un for o lo que sea, SI ALGUNO TIENE IDPADRE DIFERENTE A 0 llamas a la funcion obtenerListado guardando su resultado en el $arregloConResultados;
// y a los que no tengan un id diferente a 0 (o al que llegó por parametro) lo agregamos directamente a $arregloConResultados;
return $arregloConResultados;
}

cuando llames a obtenerListado deberías obtener un arreglo con arreglos adentro generando el arbol de categorias.

Saludos!
  #5 (permalink)  
Antiguo 07/08/2014, 13:27
Avatar de bookmaster  
Fecha de Ingreso: febrero-2002
Ubicación: Toledo
Mensajes: 976
Antigüedad: 22 años, 2 meses
Puntos: 67
Respuesta: Categorias, Subcategorias y Recursividad

Era un ejemplo de como hacerlo y puse claramente que no era funcional que tendría que ajustarlo, pero vamos que lo que quería que viera es esta linea
Código PHP:
Ver original
  1. echo "<li>{$c['nombre']} ". Listado($c['id_categoria_padre'])."</li>";
Que es la que se encarga de repetir el proceso.

Pero vamos que hay mil formas de hacerlo y yo solo le e dado un paso para que aprenda al menos como realizarlo.
Para mi gusto la mejor solución la a dado Triby.
__________________
Decir si te a funcionado la respuesta es ¡GRATIS!. Por favor indicarlo.
http://www.lohacemosweb.net
http://tutoriales.lohacemosweb.net
  #6 (permalink)  
Antiguo 08/08/2014, 03:22
Avatar de fbedia  
Fecha de Ingreso: julio-2010
Mensajes: 159
Antigüedad: 13 años, 9 meses
Puntos: 8
Respuesta: Categorias, Subcategorias y Recursividad

Gracias a todos!
He tratado de hacer lo que comentado por Triby.
A continuacion los resultados:

En primer lugar la tabla mysql con datos de prueba con la que he trabajado:

Código SQL:
Ver original
  1. CREATE TABLE IF NOT EXISTS `categorias_noticias` (
  2.   `id_categoria` INT(11) NOT NULL AUTO_INCREMENT,
  3.   `id_cat_principal` INT(11) NOT NULL,
  4.   `nombre` VARCHAR(25) NOT NULL,
  5.   `rango_minimo` INT(11) NOT NULL,
  6.   `visible` tinyint(1) NOT NULL,
  7.   PRIMARY KEY (`id_categoria`)
  8. ) ENGINE=MyISAM  DEFAULT CHARSET=utf8 AUTO_INCREMENT=11 ;
  9.  
  10. --
  11. -- Volcado de datos para la tabla `categorias_noticias`
  12. --
  13.  
  14. INSERT INTO `categorias_noticias` (`id_categoria`, `id_cat_principal`, `nombre`, `rango_minimo`, `visible`) VALUES
  15. (1, 0, 'Deportes', 1, 1),
  16. (2, 0, 'Sociedad', 1, 1),
  17. (3, 2, 'Economia', 1, 1),
  18. (4, 2, 'Religion', 1, 1),
  19. (5, 1, 'Tierra', 1, 1),
  20. (6, 1, 'Mar', 1, 1),
  21. (7, 5, 'Futbol', 1, 1),
  22. (8, 5, 'Tenis', 1, 1),
  23. (9, 7, 'Futbol 7', 1, 1),
  24. (10, 7, 'Futbol 11', 1, 1);

Con el siguiente codigo, si no me equivoco, creo el array comentado por Triby:

Código PHP:
Ver original
  1. <?php
  2.  
  3. $link_db = mysqli_connect('localhost', 'root', '', 'proyecto12');
  4. mysqli_set_charset($link_db, "utf8");
  5.  
  6. $q = mysqli_query($link_db,"SELECT id_categoria, id_cat_principal, nombre
  7.         FROM categorias_noticias
  8.         ORDER BY id_categoria");
  9.  
  10. $indice=0;
  11.  
  12. while($row=mysqli_fetch_array($q)) {
  13.  
  14.         $todos[$indice]=array(
  15.                             "id_categoria"=>$row[0],
  16.                             "id_cat_principal"=>$row[1],
  17.                             "nombre"=>$row[2],
  18.                         );
  19.         $indice++;
  20.        
  21.  
  22. }
  23.  
  24.  
  25. var_dump($todos);
  26.  
  27. ?>

El resultado de var_dump es el siguiente:

Cita:
array(8) {
[0]=> array(3) {
["id_categoria"]=> string(1) "1" ["id_cat_principal"]=> string(1) "0" ["nombre"]=> string(8) "Deportes"
}
[1]=> array(3) {
["id_categoria"]=> string(1) "2" ["id_cat_principal"]=> string(1) "0" ["nombre"]=> string(8) "Sociedad"
}
[2]=> array(3) {
["id_categoria"]=> string(1) "3" ["id_cat_principal"]=> string(1) "2" ["nombre"]=> string(8) "Economia"
}
[3]=> array(3) {
["id_categoria"]=> string(1) "4" ["id_cat_principal"]=> string(1) "2" ["nombre"]=> string(8) "Religion"
}
[4]=> array(3) {
["id_categoria"]=> string(1) "5" ["id_cat_principal"]=> string(1) "1" ["nombre"]=> string(6) "Tierra"
}
[5]=> array(3) {
["id_categoria"]=> string(1) "6" ["id_cat_principal"]=> string(1) "1" ["nombre"]=> string(3) "Mar"
}
[6]=> array(3) {
["id_categoria"]=> string(1) "7" ["id_cat_principal"]=> string(1) "5" ["nombre"]=> string(6) "Futbol"
}
[7]=> array(3) {
["id_categoria"]=> string(1) "8" ["id_cat_principal"]=> string(1) "5" ["nombre"]=> string(5) "Tenis"
}
[8]=> array(3) {
["id_categoria"]=> string(1) "9" ["id_cat_principal"]=> string(1) "7" ["nombre"]=> string(8) "Futbol 7"
}
[9]=> array(3) {
["id_categoria"]=> string(2) "10" ["id_cat_principal"]=> string(1) "7" ["nombre"]=> string(9) "Futbol 11"
}
}
Asta aqui creo que mas o menos voy bien no?

Ahora mi mayor problema es que no se bien como interactuar con el array anterior...
Por ejemplo: ¿Como hago para pintar unicamente los registros con id_cat_padre=0?

------------

De "chiripa" he conseguido mostrar el menú ordenado como quiero... sin embargo, aparte de que creo que no es muy eficiente... no es un metodo que me convezca, porque por decirlo de alguna forma, nunca se "en que parte o bub-nivel" estoy. Es decir, si quiero pintarlo con etiquetas <ul><li></li><li><ul>.....</ul></li></ul>....etc... no sabria con el siguiente codigo como hacerlo:

Código PHP:
Ver original
  1. <?php
  2. echo mostrar(0);
  3. //var_dump($todos);
  4.  
  5. //echo $todos[0]['nombre'];
  6.  
  7. function mostrar($actual=0) {
  8.  
  9.     $link_db = mysqli_connect('localhost', 'root', '', 'proyecto12');
  10.     mysqli_set_charset($link_db, "utf8");
  11.  
  12.     $q = mysqli_query($link_db,"SELECT id_categoria, id_cat_principal, nombre
  13.         FROM categorias_noticias
  14.         ORDER BY id_categoria");
  15.  
  16.     $indice=0;
  17.  
  18.     while($row=mysqli_fetch_array($q)) {
  19.  
  20.         $todos[$indice]=array(
  21.                             "id_categoria"=>$row[0],
  22.                             "id_cat_principal"=>$row[1],
  23.                             "nombre"=>$row[2],
  24.                         );
  25.         $indice++;
  26.        
  27.  
  28.     }
  29.  
  30.     foreach($todos as $valor) {
  31.        
  32.         if($valor['id_cat_principal']==$actual) {
  33.             echo $valor['nombre']."<br/>";
  34.             echo mostrar($valor['id_categoria']);
  35.         }
  36.     }
  37. }
  38. ?>

El codigo anterior me devuelve las categorias y subcategorias ordenadas (algo es algo):

Cita:
Deportes
Tierra
Futbol
Futbol 7
Futbol 11
Tenis
Mar
Sociedad
Economia
Religion
__________________
Follow me on twitter @franbedia
  #7 (permalink)  
Antiguo 08/08/2014, 04:12
 
Fecha de Ingreso: enero-2011
Ubicación: Barcelona
Mensajes: 36
Antigüedad: 13 años, 3 meses
Puntos: 5
Respuesta: Categorias, Subcategorias y Recursividad

Habersi esto te sirve, a mi me funcionó.

Código PHP:
Ver original
  1. <?php
  2. $arrCategorias=array();
  3. $arrCategorias[0]=array('id_categoria'=>'1', 'id_cat_principal'=>'0', 'nombre'=>'Deportes');
  4. $arrCategorias[1]=array('id_categoria'=>'2', 'id_cat_principal'=>'0', 'nombre'=>'Sociedad');
  5. $arrCategorias[2]=array('id_categoria'=>'3', 'id_cat_principal'=>'2', 'nombre'=>'Economia');
  6. $arrCategorias[3]=array('id_categoria'=>'4', 'id_cat_principal'=>'2', 'nombre'=>'Religion');
  7. $arrCategorias[4]=array('id_categoria'=>'5', 'id_cat_principal'=>'1', 'nombre'=>'Tierra');
  8. $arrCategorias[5]=array('id_categoria'=>'6', 'id_cat_principal'=>'1', 'nombre'=>'Mar');
  9. $arrCategorias[6]=array('id_categoria'=>'7', 'id_cat_principal'=>'5', 'nombre'=>'Futbol');
  10. $arrCategorias[7]=array('id_categoria'=>'8', 'id_cat_principal'=>'5', 'nombre'=>'Tenis');
  11. $arrCategorias[8]=array('id_categoria'=>'9', 'id_cat_principal'=>'7', 'nombre'=>'Futbol 7');
  12. $arrCategorias[9]=array('id_categoria'=>'10', 'id_cat_principal'=>'7', 'nombre'=>'Futbol 11');
  13. $arrCategorias[10]=array('id_categoria'=>'11', 'id_cat_principal'=>'0', 'nombre'=>'Test');
  14. $arrCategorias[11]=array('id_categoria'=>'12', 'id_cat_principal'=>'11', 'nombre'=>'Subtest');
  15. $arrCategorias[12]=array('id_categoria'=>'13', 'id_cat_principal'=>'12', 'nombre'=>'SubSubtest');
  16. $arrCategorias[13]=array('id_categoria'=>'14', 'id_cat_principal'=>'13', 'nombre'=>'SubSubSubtest');
  17.  
  18. imprime();
  19.  
  20. function imprime($padre=0){
  21.     global $arrCategorias;
  22.     //Validar que haya submenu (evita que se escriban <ul></ul> vacios).
  23.     $haySubMenu=false;
  24.     for($i=0; $i<count($arrCategorias) && !$haySubMenu; $i++){
  25.         $haySubMenu=$arrCategorias[$i]['id_cat_principal']==$padre;
  26.     }
  27.     if(!$haySubMenu) return;
  28.    
  29.     //Escribir listado.
  30.     echo "<ul>";
  31.         foreach($arrCategorias as $cat){
  32.             if($cat['id_cat_principal']==$padre){
  33.                 echo "<li>".$cat['nombre'];
  34.                 imprime($cat['id_categoria']);
  35.                 echo "</li>";
  36.             }
  37.         }
  38.     echo "</ul>";
  39. }
  40. ?>

Saludos, Alex.
  #8 (permalink)  
Antiguo 08/08/2014, 05:09
Avatar de fbedia  
Fecha de Ingreso: julio-2010
Mensajes: 159
Antigüedad: 13 años, 9 meses
Puntos: 8
Respuesta: Categorias, Subcategorias y Recursividad

Muchas gracias socio! Eso me sirve :)
Ahí estaba el intringulis del algoritmo!

Doy el tema por solucionado.

Un saludo.
__________________
Follow me on twitter @franbedia

Etiquetas: categorias, mysql, recursividad, select, sql, subcategorias, tabla
Atención: Estás leyendo un tema que no tiene actividad desde hace más de 6 MESES, te recomendamos abrir un Nuevo tema en lugar de responder al actual.
Respuesta




La zona horaria es GMT -6. Ahora son las 12:59.