Foros del Web » Programando para Internet » PHP »

Agrupar por Categoría Padre

Estas en el tema de Agrupar por Categoría Padre en el foro de PHP en Foros del Web. Un saludo cordial foreros, estoy seguro que mi consulta resultará sencilla. He leído las faqs y aunque hay dos casos y varios Post desde el ...
  #1 (permalink)  
Antiguo 22/01/2009, 09:19
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Agrupar por Categoría Padre

Un saludo cordial foreros, estoy seguro que mi consulta resultará sencilla.
He leído las faqs y aunque hay dos casos y varios Post desde el 2005 que tratan lo que pido, las soluciones que dan… como que no van a lo que quiero(trabajan con más de una tabla o las repuestas van en otra dirección), no logro entenderlas o adaptarlas .

El caso es el siguiente:

Tengo una tabla con una estructura como esta:
categorias (id, id_padre, nombre, ….)

si realizo la siguiente consulta:

Código PHP:
$_bd_->_sql_consulta("SELECT * FROM ".prefijo."categorias ORDER BY id_padre ""simple"); 

while( 
$fila $_bd_->_sql_fetch_array())
{
    echo 
$fila["nombre"].'<br>';

Que me devuelve esto
Cat 1
Cat 2
Cat 3
Cat 2.1
Cat 2.2
Cat 3.1
Cat 3.1.1

Si la consulta la realizo con
Código:
 GROUP BY
me devuelve esto:
Cat 1
Cat 2.1
Cat 3.1
Cat 3.1

Y quisiera un resultado como este:

Cat 1
Cat 2
-- Cat 2.1
-- Cat 2.2
Cat 3
-- Cat 3.1
-- -- Cat 3.1.1

Creo que la solución no esta en las sentencias sino en la programación PHP.

Para la mayoria de ustedes creo que será un paseo pero para este novato aprendiz no tanto.

Así que muchas gracias de antemano por leerlo y ayudar con sus orientaciones.

Última edición por enyalon; 22/01/2009 a las 09:24
  #2 (permalink)  
Antiguo 22/01/2009, 18:12
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

¿Alguna Idea, orientación.?
Por favor algunas líneas de código para ver como resuelvo esto.
  #3 (permalink)  
Antiguo 22/01/2009, 18:57
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: Agrupar por Categoría Padre

Crea 2 matrices:
Una donde almacenes todas las categorias: $categorias['id'] = 'Nombre';
Otra donde almacenes todos los niveles: $niveles['padre'] = array('id', 'id', 'id');

Asi, recorres niveles facilmente:
Código PHP:
function ver_categorias($padre) {
    global 
$categorias$niveles;
    foreach(
$niveles[$padre] as $cat) {
        echo 
$categorias[$cat] . '<br />';
        if(isset(
$niveles[$cat]))
              
ver_categorias($cat);
    }
}

ver_categorias(0); // Mostrar todas las categorias 
__________________
- León, Guanajuato
- GV-Foto
  #4 (permalink)  
Antiguo 23/01/2009, 10:30
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Gracias por responder Triby.

No logro hacer que funcione. Disculpa la molestia podrías o alguien podría explicar la función un poco más.

Esto es lo que he hecho y no me funciona.

Código PHP:
function ver_categorias($padre)
{
    global 
$categorias$niveles,$_bd_;
    
    
$_bd_->_sql_consulta("SELECT * FROM ".prefijo."categorias WHERE id_padre = $padre ORDER BY nombre ASC""simple");

    while( 
$fila $_bd_->_sql_fetch_array())
    {
        
$categorias['id'] = $fila['id'];
        
$niveles['padre'] = $fila['id_padre'];
        
        foreach(
$niveles[$padre] as $cat)
        {
            echo 
$categorias[$cat] . '<br />';
            
            if(isset(
$niveles[$cat]))
            
ver_categorias($cat);
        }
    }
}

ver_categorias(0); // Mostrar todas las categorias 
  #5 (permalink)  
Antiguo 23/01/2009, 12:25
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

En un Post del 2006 de GatorV
Encontré estas funciones:
Cita:
http://www.forosdelweb.com/f18/crear-categorias-subcategorias-431446/
Cita:
Pero no me devuelven lo esperado.
Me devuelve
Cat 1
-sub cat 1.1

Y allí termina.
Cita:
Y el resultado que necesito es
Cat 1
-sub cat 1.1
-sub cat 1.2
Cat 2
Cat 3
-sub cat 3.1
-sub cat 3.1.1
-sub cat 3.2
Cat 4
-sub cat 4.1
-sub cat 4.2
Aquí el código que estoy usando para ver en que me estoy equivocando.

Código PHP:
<?php 

function despliegaCategorias() 
{
     global 
$_bd_;
    
    
$_bd_->_sql_consulta("SELECT * FROM ".prefijo."categorias WHERE id_padre = 0 ORDER BY nombre ASC""simple");

   echo 
"Empezar listado:<br>";
   
   while( 
$row $_bd_->_sql_fetch_array()) 

    {
        echo 
$row['nombre'] . "<br>";
        
listaHijos"-"$row['id'] );
    }
    echo 
"Terminando de listar";
}
function 
listaHijos$prefijo ''$id 
{
    global 
$_bd_;
    
$_bd_->_sql_consulta("SELECT * FROM ".prefijo."categorias WHERE id_padre = $id ORDER BY nombre ASC""simple");

    if(
$_bd_->_sql_num_rows() == "0"
    {
        return; 
// No hay categorias "hijo"
    
}
   while( 
$row $_bd_->_sql_fetch_array())
    {
        echo 
$prefijo $row['nombre'];
        
listaHijos$prefijo "-"$row['id'] );
    }


despliegaCategorias();
?>
También encontré esta función:

Cita:
http://www.forosdelweb.com/1299466-post146.html

Posteada por Vaalegk en el 2005
Aquí el código tal cual lo estoy usando.

Código PHP:
<?php 
/*
funcion generica
Parametros:
    $tabla     = Nombre de la tabla en la DB
    $id_field  = Nombre del campo llave de la tabla
    $show_data = Campo a mostrar en el arbol
    $link_field= Campo que establece la relacion padre hijo
    $parent       = padre actual
    $prefix    = string con un campo a mostrar en cada entrada del arbol
*/
function crearArbol($tabla,$id_field,$show_data,$link_field,$parent,$prefix)
{
    global 
$_bd_;
    
    
$_bd_->_sql_consulta("SELECT * FROM ".prefijo."$tabla WHERE $link_field = $parent""simple");

    if(
$_bd_->_sql_num_rows() > $parent
    {
        while( 
$fila $_bd_->_sql_fetch_array())
        {
            echo 
$prefix.$fila[$show_data].'<br>';
            
            
crearArbol($tabla,$id_field,$show_data,$link_field,$fila[$id_field],$prefix.$prefix);
        }
    }

}
crearArbol('categorias','id','nombre','id_padre',0,'-'); 
?>
Y que me devuelve:

Cita:
-Cat 1
-- Cat 1.1

Y no es lo que quiero.
No se en que estoy fallando.
Por favor alguien que me ayude a ver el error.

No pregunto un tema ya tratado sin antes buscar. Como lo ven... lo he hecho. Pero no logre hacer funcionar los códigos.

Así que apiádense de mi.

Les recuerdo la estructura de la tabla en la base de datos
Categorias (id, id_padre, nombre, …)
  #6 (permalink)  
Antiguo 23/01/2009, 13:45
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: Agrupar por Categoría Padre

Lo primero que debes hacer es crear las matrices y llenarlas:
Código PHP:
$categorias $niveles = array();

$_bd_->_sql_consulta("SELECT * FROM ".prefijo."categorias ORDER BY id_padre, nombre""simple");
while( 
$fila $_bd_->_sql_fetch_array()) {
        
$id $fila['id'];
        
$id_padre $fila['id_padre'];
        
$categorias[$id] = $fila['nombre'];
        
// Si no existe el indice, lo creamos
        
if(!isset($niveles[$id_padre]))
                
$niveles[$id_padre] = array();
        
// Agregamos el ID de categoria en el nivel correspondiente
        
$niveles[$id_padre][] = $id;

Despues de eso ya puedes llamar a la funcion, incluyendo formatos html si lo deseas:
Código PHP:
function ver_categorias($padre) {
    global 
$categorias$niveles;
    echo 
'<ul>';
    foreach(
$niveles[$padre] as $cat) {
        echo 
'<li>' $categorias[$cat];
        if(isset(
$niveles[$cat]))
              
ver_categorias($cat);
        echo 
'</li>';
    }
    echo 
'</ul>';
}

ver_categorias(0); // Mostrar todas las categorias 
__________________
- León, Guanajuato
- GV-Foto
  #7 (permalink)  
Antiguo 23/01/2009, 15:06
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Muchas gracias Triby, no se siente uno tan sólo con estos "problemillas".

Te comento que me sale este error:
Cita:
Warning: Invalid argument supplied for foreach() in
¿Alguna idea?

Ya siento que este problema y yo no estamos volviendo molestos.
  #8 (permalink)  
Antiguo 23/01/2009, 15:11
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años
Puntos: 2534
Respuesta: Agrupar por Categoría Padre

el error descrito, solo ocurre si el argumento no es un array (textualmente) osea...

que tal ves, el pseudo array que usas en el foreach() no es un array

debes, y como recomendación general... evitar este tipo de problemas, controlandolos!

ejemplo
Código PHP:
if ( ! empty($foo[$bar]) && is_array($foo[$bar]))
{
  
// ...

  
foreach ($foo[$bar/* ... */// ...

  // ...

__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #9 (permalink)  
Antiguo 23/01/2009, 15:37
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: Agrupar por Categoría Padre

Para saber a que se debe ese error:
Código PHP:
echo '<pre>';
var_dump($categorias$niveles);
echo 
'</pre>'
Recuerda que la mayoria de las respuestas aqui en el foro son "sugerencias" hechas "al vuelo" y no estan probadas, por lo que debes depurar y/o adaptar el codigo para ajustarlo a tus necesidades.
__________________
- León, Guanajuato
- GV-Foto
  #10 (permalink)  
Antiguo 23/01/2009, 22:49
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Hola Triby muchas gracias otra vez por la atención.

Créeme que intento modificarlos y adaptarlos para entenderlos mejor y quizá terminar aprendiendo un poco .

Pues comento lo que sucede:

Al pedir volcar la información de estas variables, el resultado es el esperado me vuelca esta información:

Cita:
array(19) {
[1]=>
string(5) "cat 1"
[2]=>
string(5) "cat 2"
[3]=>
string(5) "cat 3"
[11]=>
string(5) "cat 4"
[19]=>
string(5) "cat 5"
[12]=>
string(3) "1.1"
... y así sigue.
Parecería que todo bien… pero resulta que cuando pido volcar esta información dentro de la función ver_categorias(0) devuelve NULL NULL.

Creo entonces que la información que contienen las variables no logra entrar a la función. Esto me parece lógico ya que el SELECT a la base de datos lo realizo fuera de la función. Si mi lógica no esta errada (cosa realmente muy posible), para que el foreach tenga un argumento valido, hay que encontrar la forma de que la información que las variables $categorias, $niveles tienen fuera de la función llegue a ella.

Entiendo que que se pide que sean globales en esta línea global $categorias, $niveles; y que así intentamos acceder a la información de esas variables, pero parece no funcionar.

Pero hasta allí llega mi entendimiento, seguiré leyendo al respecto en el “omnisciente” Google, y esperando por supuesto cualquier otra observación.

Gracias nuevamente por la atención y la paciencia.

Última edición por enyalon; 23/01/2009 a las 23:01 Razón: Me falto decir algo
  #11 (permalink)  
Antiguo 23/01/2009, 22:56
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: Agrupar por Categoría Padre

Ok... $categorias parece estar bien... y el var_dump() de niveles que imprime?
__________________
- León, Guanajuato
- GV-Foto
  #12 (permalink)  
Antiguo 23/01/2009, 23:16
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Cita:
Iniciado por pateketrueke Ver Mensaje

...debes, y como recomendación general... evitar este tipo de problemas, controlandolos!

ejemplo
Código PHP:
if ( ! empty($foo[$bar]) && is_array($foo[$bar]))
{
  
// ...

  
foreach ($foo[$bar/* ... */// ...

  // ...

Gracias por el dato pateketrueke es una forma de verificar antes y que no imprima el Warning, así controlo que no imprima el Warning, pero igual hay una razón por la que no se ejecutan las sentencias que me interesan. En otras palabras mi problemilla persiste. Igual el dato me enseña algo nuevo y eso es siempre bien recibido, por lo tanto gracias.
  #13 (permalink)  
Antiguo 23/01/2009, 23:24
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Cita:
Iniciado por Triby Ver Mensaje
Ok... $categorias parece estar bien... y el var_dump() de niveles que imprime?
Que rápido Jejeje,

Pues imprime las dos variables. No las he copiado todas por su extensión, si vuelco solo niveles da esto:
Cita:
array(9) {
[0]=>
array(5) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
[3]=>
string(2) "11"
[4]=>
string(2) "19"
}
[1]=>
array(3) {
[0]=>
string(2) "12"
[1]=>
string(2) "13"
... y sigue.
Pero como te dije esos valores no logran entrar dentro de la función.
Código PHP:
function ver_categorias($padre)
{
    global 
$categorias$niveles;
...
echo 
'<pre>'// Aquí no imprime nada. o mejor dicho imprime NULL NULL
var_dump($categorias$niveles);
echo 
'</pre>';

... 
//el foreach esta aquí y pues no llega nada.
}

echo 
'<pre>'// Aquí imprime todo bien.
var_dump($categorias$niveles);
echo 
'</pre>'

ver_categorias(0); // Mostrar todas las categorias 

Última edición por enyalon; 23/01/2009 a las 23:34 Razón: Corregir un dato
  #14 (permalink)  
Antiguo 23/01/2009, 23:46
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: Agrupar por Categoría Padre

Puedes mostrar completo el codigo?... al menos la parte donde creas las matrices hasta donde mandas llamar ver_categorias()... porque lo que se ve es que $categorias y $niveles no estan definidas, es decir, ni siquiera son matrices vacias.
__________________
- León, Guanajuato
- GV-Foto
  #15 (permalink)  
Antiguo 23/01/2009, 23:59
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años
Puntos: 2534
Respuesta: Agrupar por Categoría Padre

bien, eso nos da una pista mas....

antes de usar tu global dentro de una función es preferible declararla fuera del contexto, o algo así....

Código PHP:
<?php

candy
(); // MAL
// aunque no es error declarar una funcion al final y
// asi usarla antes de, puede dar error si intentas usar
// una global fuera de contexto....
//
// o bien, creer que usas una variable que no es (suena raro)

global $foo;

$foo 'bar';
$does 'BAZ';

$GLOBALS['buzz'] = 'cola!';

candy(); // OK

function candy()
{
  static 
$i 0;
  
  global 
$foo$does;
  echo 
"<pre>$i, $foo ~ $does ($GLOBALS[buzz])</pre>";
  
  ++
$i;
}

candy(); // OK
resultados...

Código:
0,  ~  ()

1, bar ~ BAZ (cola!)

2, bar ~ BAZ (cola!)
NOTA que usar global es como var, o bien... es definir una variable antes de usarla, y por eso no da el error clásico de Undefined Variable (tal ves, otra pista)

por otro lado, cualquier variable declarada en el contexto global no necesariamente es considerada global ...


la verdad el ejemplo explica muchas cosas, seguro!
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.

Última edición por pateketrueke; 24/01/2009 a las 00:07 Razón: resultados
  #16 (permalink)  
Antiguo 24/01/2009, 00:50
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Perfecto muchas gracias a los dos.
Funciona Jejeje
La acotación final de pateketrueke termino de poner las piezas en su lugar.
Son geniales
Supongo que Triby daba por sentado que yo sabia esto.

Aquí el código Funcionando:
Código PHP:
<?php

global $categorias$niveles;

$_bd_->_sql_consulta("SELECT * FROM ".prefijo."categorias ORDER BY id_padre, nombre""simple");
while( 
$fila $_bd_->_sql_fetch_array()) //establecemos la conexión y realizamos la consulta (cada quien con su código)
{
    
$id $fila['id'];
    
$id_padre $fila['id_padre'];
    
$categorias[$id] = $fila['nombre'];
    
// Si no existe el indice, lo creamos
    
if(!isset($niveles[$id_padre]))
    
$niveles[$id_padre] = array();
    
// Agregamos el ID de categoria en el nivel correspondiente
    
$niveles[$id_padre][] = $id;    

function 
ver_categorias($padre
{
    global 
$categorias$niveles;
    
    if ( ! empty(
$categorias) && is_array($niveles))
    {
        echo 
'<ul>';
        foreach(
$niveles[$padre] as $cat)
        {
            echo 
'<li>--' $categorias[$cat];
            if(isset(
$niveles[$cat]))
                
                
ver_categorias($cat);
                
            echo 
'</li>';
        }
        echo 
'</ul>';
    }
}
  
ver_categorias(0); // Mostrar todas las categorías 
?>
P.D. ¿se podría listar diferenciando los niveles. Por ejemplo agregando un par de guiones antes del primer subnivel y tres antes del segundo y así sustantivamente?
Cita:
Algo así:
Cat 1
-- Cat 1.1
---Cat 1.1.1
Ya han hecho más que suficiente pero no quedaría mal ese agregado.

Nuevamente Muchas gracias por la atención y paciencia.
  #17 (permalink)  
Antiguo 24/01/2009, 14:16
Avatar de pateketrueke
Modernizr
 
Fecha de Ingreso: abril-2008
Ubicación: Mexihco-Tenochtitlan
Mensajes: 26.399
Antigüedad: 16 años
Puntos: 2534
Respuesta: Agrupar por Categoría Padre

claro que se puede, para ello debes ingeniar usando recursividad...

Código PHP:
function foo($bar$lvl 0)
{
  
$tab str_repeat('-'$lvl);
  if (
/* ... */)
  {
    
$out foo($candy$lvl 1);
  }
  echo 
$tab $out;

de modo que, cada que se empiece un nuevo ciclo se incrementa un parámetro de la función que permite la profundidad (que bien puede ser una variable estática) y así, cumple su cometido....

espero ilustre de algo, suerte!
__________________
Y U NO RTFM? щ(ºдºщ)

No atiendo por MP nada que no sea personal.
  #18 (permalink)  
Antiguo 24/01/2009, 14:45
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: Agrupar por Categoría Padre

Cita:
Supongo que Triby daba por sentado que yo sabia esto.
Precisamente por eso queria ver todo tu codigo, para ver donde definias las matrices y donde la funcion.

pateketrueke, muy buenos tus ejemplos.
__________________
- León, Guanajuato
- GV-Foto
  #19 (permalink)  
Antiguo 24/01/2009, 15:38
Avatar de enyalon  
Fecha de Ingreso: agosto-2008
Mensajes: 28
Antigüedad: 15 años, 9 meses
Puntos: 0
Respuesta: Agrupar por Categoría Padre

Cita:
Iniciado por Triby Ver Mensaje
Precisamente por eso queria ver todo tu codigo, para ver donde definias las matrices y donde la funcion.
Ahora ya lo he aprendido. Gracias a ustedes.
De seguro les seguire preguntando de cuando en cuando en los hilos de estos foros.



pateketrueke
Voy a intentar aplicar el ejemplo que me das. Luego les cuento.
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 00:07.