PDA

View Full Version : [PHP/MYSQL] Stampare una struttura gerarchica a infiniti livelli


ciuhd
25-09-2008, 11:11
Salve a tutti,
stò realizzando una piccola applicazione in php/mysql, per la memorizzazione di annunci economici, è ho un problema nel rappresentare una struttura gerarchica a infiniti livelli.

Cerco di spiegarmi meglio, io ho questi ingredienti:
Una tabella che mi memorizza gli annunci, così fatta:
Annunci ( id*, cat_id*, titolo, ecc..);
dove id, è chiave primaria, e cat_id è l'id della categoria in cui l'annuncio è inserito.
e una tabella dove memorizzo le categorie:
Categorie( id*, nome, parent_id);
dove id è chiave primaria e parent_id è l'id della categoria genitore.
Se il parent_id è uguale a zero ,la categoria non ha genitori sopra di lei, è quindi root.

Quindi se ad esempio io ho queste tuple:
(1, Informatica , 0 );
(2, Periferiche , 1 );
(3, Scanner, 2 );
(4, Monitor, 2 );
(5, Lcd, 4 );
(6, Crt, 4);
(7, Abbigliamento, 0 );
(8, Uomo , 7 );
(9, Donna, 8 );


Io voglio ottenere una stampa di questo tipo:

Informatica
- Periferiche
--Scanner
--Monitor
---Lcd
---Crt
Abbigliamento
--Uomo
--Donna

Il problema è che a priori non sò quanti livelli ho nella mia struttura...:muro:

avastreg
29-09-2008, 09:57
ti conviene a mio parere utilizzare delle classi, in modo da crearti un metodo che può richiamarsi ricorsivamente

esempio rapido:


//metodo dell'oggetto categoria
function caricaSottocategorie() {

//ti trovi le sottocategorie joinando la seconda tabella

$sql = "...";

//query($sql)..

while (//leggo il risultato del db) {
//crei la nuova categoria
$sottocategoria = new categoria(/* riga.. */);
//richiami il metodo in modo che il tutto sia ricorsivo
$sottocategoria->caricaSottocategorie();
//aggiungi questa sottocategoria all'array di sottocategorie dell'oggetto in questione
this->$sottocategorie[] = $sottocategoria;
}

}

una volta istanziata la categoria root (con una combinazione speciale nel costruttore), mettiamo che sia $root, facendo

$root->caricaSottocategorie();

con print_r($root) dovresti avere tutto l'albero (composto da oggetti e dai propri array di oggetti sottostanti)

ciuhd
29-09-2008, 10:14
Grazie per la risposta, avastreg ;)

Stò già utilizzando una classe "categoria"...
e avevo pensato di fare una funzione ricorsiva come quella che mi hai suggerito.
Il problema che mi pongo è questo:
dovendo stampare l'albero di tutte le categorie in ogni pagina del sito, questo approccio secondo te è efficente??
In questo modo per devo andare a fare una query nel db per ogni categoria presente, perchè per ognuna devo controllare se ha dei discendenti...:muro:

avastreg
29-09-2008, 11:19
Grazie per la risposta, avastreg ;)

Stò già utilizzando una classe "categoria"...
e avevo pensato di fare una funzione ricorsiva come quella che mi hai suggerito.
Il problema che mi pongo è questo:
dovendo stampare l'albero di tutte le categorie in ogni pagina del sito, questo approccio secondo te è efficente??
In questo modo per devo andare a fare una query nel db per ogni categoria presente, perchè per ognuna devo controllare se ha dei discendenti...:muro:

per evitare di effettuare tutte quelle query ogni volta che ti caricano una pagina, puoi mettere in sessione l'albero (ok, la sessione non sarà proprio leggera, ma è meglio che rifare tutto il passaggio). Se in sessione c'e' già l'albero, usi quello, altrimenti lo inizializzi.

Un altro accorgimento in quest'ottica può essere creare classi categoria apposta per il menu (quindi con i parametri minimi necessari) oppure avere una funzione che ti esporta solo quello che ti serve (magari tutto come array). Già con gestione in sessione, però, dovrebbe risultare ottimizzato.

Per la visualizzazione, io utilizzo smarty quindi sono legato a logiche un po' diverse dal classico php + html, ma cmq ora che hai l'albero puoi saperne la profondità e quindi creare <ul> <li> innestati finchè ne hai bisogno, a seconda del menu che devi realizzare; anche in questo caso magari serve una funzione ricorsiva che percorre l'albero e genera il codice relativo.

ciuhd
29-09-2008, 11:23
vedrò di utilizzare le sessioni...


Di nuovo grazie ;-) :sofico:

avastreg
29-09-2008, 11:30
di niente :)

Hiskrtapps
30-09-2008, 14:23
Mysql non gestisce le tabelle ricorsive tipo quella che hai fatto te in maniera nativa.

Per fare quello che ti serve devi ristrutturare la tua tabella, e gestire le operazioni di cancellazione e inserimento in maniera un po' più complessa.

In queste 3 paginette è tutto spiegato meglio di quanto possa fare io.
http://www.sitepoint.com/article/hierarchical-data-database/

G.

nextstyle
01-10-2008, 01:03
per evitare query ricorsive
puoi semplicemente fare una singola query che ti scarichi tutta la tabella
e lasciare a php il compito di ordinarla (array multidimensionali...)

ciao

anonimizzato
09-11-2008, 09:03
Ciao a tutti ho un problema analogo che vorrei cercare di risolvere.

Le funzioni ricorsive proprio non le digerisco. :fagiano:

Diciamo che ho una tabella "struttura" a DB con due colonne:

paginaID -- pagina_parentID
----1------------0--------
----2------------0--------
----3------------0--------
----4------------1--------
----5------------1--------
----6------------2--------
----7------------3--------
----8------------3--------
----9------------6--------

Come facile intuire laddove pagina_parentID è 0 significa che si tratta di una pagina di primo livello, il resto è nidificabile INFINITE volte (qui solo 3 per praticità).

Come costruisco una funzione che RITORNI un array perfettamente gerarchizzato?

Avevo cominciato ad abbozzare una funzione simile:


function struttura($id) {

$sql = "select * from struttura where pagina_parentID = " . $id;
$result = mysql_query($sql);
if ($row = mysql_fetch_assoc($result)) {

do {

$struttura[] = $row['paginaID'];

} while ($row = mysql_fetch_assoc($result));

} else {

return $struttura;
}

}


Ma non riesco a capire dove e come devo annidare il richiamo ricorsivo a "struttura()" stessa.

Tnx. ;)

anonimizzato
09-11-2008, 11:14
function struttura($id) {

global $struttura;

$sql = "select * from struttura where pagina_parentID = " . $id;
$result = mysql_query($sql);

while ($row = mysql_fetch_assoc($result)) {

if ($id != 0) {

if (!is_array($struttura[$id])) {

$struttura[$id] = array();

}

$struttura[$id][$row['paginaID']] = 1;


} else {

$struttura[$row['paginaID']] = 1;

}

struttura($row['paginaID']);


}



return $struttura;

}



Sono arrivato a questo punto, tuttavia il terzo livello (nodo [6]) mi viene messo al primo livello invece che sotto il nodo [2].

Soluzioni?

frizzo28
09-11-2008, 12:00
Anche io ho dovuto fare la stessa cosa http://www.hwupgrade.it/forum/showthread.php?t=1851265:)
ciao

anonimizzato
09-11-2008, 12:26
Io però non voglio fare il "semplice" output a video indentato, ho bisogno di inserire il tutto in un array gerarchizzato. ;)

Mostrare a video la struttura non è tanto complicato, nel senso che basta trovare il modo migliore per indentare il tutto.

Es:


<?

require "connect.php";

function output_categorie($id_principale)
{
$sql = "SELECT * FROM downcat WHERE id_principale = \"$id_principale\"";
$res = mysql_query($sql);

echo "<ul>";
while ($row = mysql_fetch_assoc($res))
{
echo "<li>";
echo "<a href=apricat.php?id=".$row['id_cat'].">".$row['nome']."</a>";

//Stampa sottocategorie
output_categorie($row['id_cat']);

echo "</li>";
}
echo "</ul>";
}

output_categorie(0);
?>


Ma se volessi "storare" tutto in un unico array multidimensionale?

kk3z
09-11-2008, 20:06
<?
function get_categorie($id_principale)
{
$array = array();

$sql = "SELECT * FROM downcat WHERE id_principale = '$id_principale'";
$res = mysql_query($sql);
while ($row = mysql_fetch_assoc($res))
{
$array[ $row['id_cat'] ] = array(
'nome' => $row['nome'],
'sottocategorie' => get_categorie($row['id_cat']
);
}

return $array;
}

$array = get_categorie(0);
?>

Dovrebbe andare...

anonimizzato
11-11-2008, 14:52
Ti ringrazio, appena possibile me la studio. ;)