Comunidad de diseño web y desarrollo en internet online

Menu Recursivo

Citar            
MensajeEscrito el 30 Jul 2011 07:58 pm
Hola, qué tal.

Estoy tratando de hacer un menu php a partir de una base de datos donde no haya límite de subsecciones, es por eso que me basé en este código

http://www.finalwebsites.com/tutorials/dynamic-navigation-list.php

le hice muy pequeñas modificaciones muy por encima, pero aún así no pasa del 2do nivel, me devuelve todos los items con parent id = 0, después las subsecciones hijas de 0, pero no más allá

En lugar de devolverme 0.1.1.1, se estanca en 0.1.1

alguien tiene idea de por qué?

Código PHP :

<?php
include ("mysqlconn.php");
$sql = "SELECT id, label, parent FROM secciones ORDER BY parent, id ASC"; 
$items = mysql_query($sql);
while ($obj = mysql_fetch_object($items)) {
    if ($obj->parent == 0) {
        $parent_menu[$obj->id]['label'] = $obj->label;
        $parent_menu[$obj->id]['link'] = $obj->id;
    } else {
        $sub_menu[$obj->id]['parent'] = $obj->parent;
        $sub_menu[$obj->id]['label'] = $obj->label;
        $sub_menu[$obj->id]['link'] = $obj->id;
        $parent_menu[$obj->parent]['count']++;
    }
}
mysql_free_result($items);
function menu($parent_array, $sub_array, $qs_val = "menu", $main_id = "nav", $sub_id = "subnav", $extra_style = "foldout") {
    $menu = "<ul id=\"".$main_id."\">\n";
    foreach ($parent_array as $pkey => $pval) {
        if (!empty($pval['count'])) {
            $menu .= "  <li><a class=\"".$extra_style."\" href=\""."?"."id=".$pval['link']."&".$qs_val."=".$pkey."\">".$pval['label']."</a></li>\n";
        } else {
            $menu .= "  <li><a class=\"".$extra_style."\" href=\""."?"."id=".$pval['link']."\">".$pval['label']."</a></li>\n"; 
        }
        if (!empty($_REQUEST[$qs_val])) {
            $menu .= "<ul id=\"".$sub_id."\">\n";
            foreach ($sub_array as $sval) {
                if ($pkey == $_REQUEST[$qs_val] && $pkey == $sval['parent']) {
                    $menu .= "<li><a href=\""."?id=".rebuild_link($sval['link'], $qs_val, $sval['parent'])."\">".$sval['label']."</a></li>\n";
                }
            }
            $menu .= "</ul>\n";
        }
    }
    $menu .= "</ul>\n";
    return $menu;
}
function rebuild_link($link, $parent_var, $parent_val) {
    $link_parts = explode("?", $link);
    $base_var = "&".$parent_var."=".$parent_val;
    if (!empty($link_parts[1])) {
        $link_parts[1] = str_replace("&amp;", "##", $link_parts[1]);
        $parts = explode("##", $link_parts[1]);
        $newParts = array();
        foreach ($parts as $val) {
            $val_parts = explode("=", $val);
            if ($val_parts[0] != $parent_var) {
                array_push($newParts, $val);
            }
        }
        if (count($newParts) != 0) {
            $qs = "&amp;".implode("&amp;", $newParts);
        } 
        return $link_parts[0].$base_var.$qs;
    } else {
        return $link_parts[0].$base_var;
    }
}
echo menu($parent_menu, $sub_menu, "menu", "nav", "subnav");
?>

Explico mejor:

Hasta el 2do nivel (1.1) el menú se despliega correctamente, pero a partir del 3ro (1.1.1) ya directamente ni se despliega, aparece un <li> en blanco entre los items con parent = 0 por cada sección de 3er nivel, en lugar de posicionarse dentro de una <ul> dentro de su correspondiente padre de nivel 2, es decir, primer nivel de subsecciones.

¿Alguna manera de solucionarlo?

Más detalles

Mi tabla es así

Mi Tabla escribió:

id -> int, primary key
label -> varchar (25)
parent -> int
content -> varchar (200)

Por Martriay

5 de clabLevel



Genero:Masculino  

Freelancer

chrome
Citar            
MensajeEscrito el 01 Ago 2011 08:50 pm
la tabla es lo unico que esta bien echo, debes tomar esa tabla que es un array unidimensional y transformarla en un array multidimensional
la consulta seria la siguiente:

Código MySQL :

SELECT 
id,
label,
parent,
content 
FROM tutabla
-- OJO
ORDER BY parent, label 


luego lo recorres en php, los primeros resultados seran los menus principales (parent 0) luego vendrán los que son hijos de alguno de los principales.

si tienes mas dudas redacto un tutorial :P

Por Inyaka

Claber

3176 de clabLevel

9 tutoriales
2 articulos

Genero:Masculino   Desarrollador de GAIA

Programador y fotógrafo

firefox
Citar            
MensajeEscrito el 01 Ago 2011 10:45 pm
Si redactas un tutorial estaría más que agradecido, porque es un problema que estoy tratando de solucionar hace bastante jejeje
Mi conocimiento de php es básico, si bien entiendo la sintaxis y cómo está hecho ese menú, no entiendo por qué no funciona :S

Por Martriay

5 de clabLevel



Genero:Masculino  

Freelancer

chrome
Citar            
MensajeEscrito el 01 Ago 2011 11:01 pm
bien, aca tengo un ejemplo, espero no sea demasiado complejo por que ahi si me veria obligado al tuto XD(el cual demoraria bastante )
es un ejemplo con joomla

Código PHP :

 
   $query  = "
   SELECT
      category_id,
      category_name,
      category_description,
      category_parent_id
   FROM #__{vm}_category c
   INNER JOIN #__{vm}_category_xref cx ON c.category_id= cx.category_child_id
   WHERE c.category_publish='Y'
   ORDER BY category_parent_id, list_order, category_name ASC
   ";
   $db->query( $query );
   $menu = array();
   while( $db->next_record() )
   {
      $parent = ($db->f("category_parent_id"))? $db->f("category_parent_id") : 0; 
      # $sintaxis_abreviada_if_else ($true_o_false)? true : false;
      $record = array(
         'id'       => $db->f("category_id"),
         'parent'   => $db->f("category_parent_id"),
         'name'       => htmlentities( $db->f("category_name"), ENT_QUOTES, vmGetCharset() ). ps_product_category::products_in_category( $db->f("category_id") ),
         'description'    => $db->f("category_description"),
         'url'       => $sess->url($mm_action_url."index.php?page=shop.browse&category_id=".$db->f("category_id")),
         'active'    => ($db->f("category_id") == vmRequest::getInt( 'category_id' ))? 'active' : false
      );
      $menu[$parent][$db->f("category_id")] = (object) $record;
      

   }



luego en la vista lo usas asi:

Código PHP :

<ul id="menu" >
   <?php foreach($menu[0] as $i=>$m): ?>
      <li id="item-<?php echo $m->id ?>" class="item<?php if($m->active) echo ' '.$m->active ?>">
         <a href="<?php echo $m->url ?>" alt="<?php echo $m->name ?>" title="<?php echo $m->description ?>"><?php echo $m->name ?></a>
         <?php if( array_key_exists($i, $menu)): ?>
            <ul>
               <?php foreach($menu[$i] as $sm ): ?>
                  <li id="item-<?php echo $sm->id ?>"  class="item<?php if($sm->active) echo ' '.$sm->active ?>">
                     <a href="<?php echo $sm->url ?>" alt="<?php echo $sm->name ?>" title="<?php echo $sm->description ?>"><?php echo $sm->name ?></a></li>
               <?php endforeach; ?>
            </ul>
         <?php endif; ?>
      </li>
   <?php endforeach; ?>
</ul>

Por Inyaka

Claber

3176 de clabLevel

9 tutoriales
2 articulos

Genero:Masculino   Desarrollador de GAIA

Programador y fotógrafo

firefox
Citar            
MensajeEscrito el 02 Ago 2011 01:06 am
:shock:

Jajaja voy a intentar ahora mismo adaptar ese código, pero de todas formas podrías hacer ese tuto? Me serviría si me estanco en algún momento y a su vez sería un muy buen aporte a la comunidad en general.

Saludos

Por Martriay

5 de clabLevel



Genero:Masculino  

Freelancer

chrome
Citar            
MensajeEscrito el 02 Ago 2011 01:39 am
Estuve intentando aplicarlo, primero corregí una query al comienzo del codigo y ahora me aparece:

Fatal error: Call to a member function next_record() on a non-object

Definitivamente me vendría muy bien ese tutorial, siempre y cuando quieras hacerlo claro jaja

Saludos, y gracias

Por Martriay

5 de clabLevel



Genero:Masculino  

Freelancer

chrome
Citar            
MensajeEscrito el 02 Ago 2011 05:33 am
juas, eso no te va a funcionar, era solo un ejemplo para que entendieras la logica :P
solo eso, next_record() es un metodo de una clase de joomla, no puedes usarla fuera de joomla y para el caso viene a ser lo mismo que mysql_fetch_assoc()

Por Inyaka

Claber

3176 de clabLevel

9 tutoriales
2 articulos

Genero:Masculino   Desarrollador de GAIA

Programador y fotógrafo

firefox
Citar            
MensajeEscrito el 03 Ago 2011 02:33 am
Bueno, sigo intentando y ahora tira más errores, claramente no termino de entender como funciona. Si haces el tutorial, más que agradecido, sino... bueno, ya veré que hago jajaja

Gracias por intentarlo (:

Por Martriay

5 de clabLevel



Genero:Masculino  

Freelancer

chrome
Citar            
MensajeEscrito el 03 Ago 2011 04:04 pm
lo malo de un arbol infinito es que consumes recursos de la base de datos ya que al meter una funcion recursiva hace constantes llamados a la base de datos, podrias optar por crear una cache del resultado y utilizarlas luego.
yo aria un arreglo,vector,matriz,array como quiras decirlo

Código PHP :

$arreglo_temporal = array(
"id" => 1,
"label" => 'algo',
"hijos" => null
);
//bueno el asunto es que la base de datos llenara mi arreglo y despues hacer lo que quieras
//con el,

Código PHP :

function recursivo_db($id_padre = 0)
{
   //como usas variables globales lo cual no recomiendo deberia quedar asi
   global $variable_de_referncia_a_la_conexion_sql;
   $array = array();
   //$sql = "SELECT id, label, parent FROM secciones WHERE parent=$id_padre ORDER BY parent,id ASC";
   $sql = "SELECT id, label FROM secciones WHERE parent=$id_padre ORDER BY parent,id ASC";
   $items = mysql_query($sql);
   while ($assoc = mysql_fetch_assoc($items))
   { 
      
      $hijos = recursivo_db($assoc['id']);
      //unset($assoc['parent']);
      $assoc["hijos"] = is_null($hijos) ? null: $hijos;
      $array[] = $assoc;
   }
   return empty($array)? null:$array;
}

para usarlo solo deberia hacer esto

Código PHP :

//primero compruebo q no tengo nada en cache
$nombre_de_archivo = dirname(__FILE__). "/menu_tmp.ta";
$cache_file = new SplFileInfo($nombre_de_archivo );
//compruebo la fecha de creacion que no pase de 2 minutos
if($cache_file->getMTime()+120 > time())
{
//como el tiempo exedio del cache lo vuelvo a crear
    //con esto empiezo a sacar todos los que tengan parent=0 y sus hijos
    $arreglo_temporal = recursivo_db(0);
    //luego lo almaceno en el archivo temporal
    //serializo los datos para recuperarlos tambien c puede utilizar json_encode
    file_put_contents($nombre_de_archivo , serialize($arreglo_temporal));
}
else
{
   //como aun la cache esta fresta lo recupero y lo desearializo
   $arreglo_temporal = unserialize(file_get_contents($nombre_de_archivo) );
}

luego al final lo volves a rrecorrrer el array si quieres pero esta vez ya para crear los complementos como tags xhtml css y lo que quieras asi separas los datos de la vista:) eso ya te lo dejo a tu imaginacion

una osa este codigo no fue probado en ningun momento puede tener fallos de sintaxys no hagas copy paste , soloes una forma de ilustrar

Por tuadmin

Claber

598 de clabLevel



Genero:Masculino  

firefox
Citar            
MensajeEscrito el 11 Oct 2011 08:39 am
Hola , soy nuevo por aquí. Tengo una función recursiva que crea un menú dinámico en php que ataca una base de datos en mysql. Para la conexión a la base de datos uso zend framework. Antes de todo descargar zend framework aquí. Dejo el código a continuación.

Creación de la base de datos
--------------------------------------------

CREATE TABLE `menu2` (
`id` int(11) NOT NULL auto_increment,
`label` varchar(50) NOT NULL default '',
`link` varchar(100) NOT NULL default '#',
`parent` int(11) NOT NULL default '0',
`sort` int(11) default NULL,
PRIMARY KEY (`id`),
) ENGINE=MyISAM AUTO_INCREMENT=248 DEFAULT CHARSET=latin1;

Código php
-----------------

<?php
//IMPORTANTE!
ini_set('include_path', ini_get("include_path") . ';' . $_SERVER['DOCUMENT_ROOT'] . 'auto/libs/');

//incluimos el archivo de base de datos de zend framework
require_once("libs/Zend/Db.php");

try {
//objeto de conexion a la base de datos
$db = Zend_Db::factory('Pdo_Mysql', array(
'host' => 'localhost',
'username' => 'root',
'password' => 'root',
'dbname' => 'auto'
));

$db->getConnection();

function display_children($parent, $level,$db) {

$sql = "SELECT a.id, a.label, a.link, Deriv1.Count FROM menu2 a LEFT OUTER JOIN (SELECT parent, COUNT(*) AS Count FROM menu2 GROUP BY parent) Deriv1 ON a.id = Deriv1.parent WHERE a.parent=" . $parent . " ORDER BY sort";

$result = $db->query($sql);

echo "<ul>";
while ($row = $result->fetch()) {
if ($row['Count'] > 0) {
echo "<li><a href='" . $row['link'] . "'>" . $row['label'] . "</a>";
display_children($row['id'], $level + 1,$db);
echo "</li>";
} elseif ($row['Count']==0) {
echo "<li><a href='" . $row['link'] . "'>" . $row['label'] . "</a></li>";
} else;
}
echo "</ul>";
}
//0 , 1 -> muestra todos
//padre , nivel , objeto
display_children(0, 1,$db);

}catch (Zend_Exception $e) {
// Sucedió un error inexperado
die($e->getMessage());
}

?>

Un saludo y espero que les sirva.

Por albertopeiz77

0 de clabLevel



 

chrome

 

Cristalab BabyBlue v4 + V4 © 2011 Cristalab
Powered by ClabEngines v4, HTML5, love and ponies.