si tratta di memorizzazione di dati gerarchici in PHP vs MySQL. In PHP possiamo usare un albero semplice. Il problema è che non è facile memorizzare un albero nel database piatto che è MySQL. Un'opzione consiste nel prendere la lista PHP e recuperare e adiacenza da esso. Questo è essenzialmente un elenco di ogni oggetto e dei suoi genitori. Questo modo di fare le cose ha qualche svantaggio.
Un altro metodo consiste nell'estrarre informazioni dall'albero PHP che descrive gli insiemi nidificati che possono essere ricavati dai dati gerarchici. Per ottenere queste informazioni dall'albero PHP, è necessario utilizzare un algoritmo per l'attraversamento degli alberi preordinato modificato . Questo è un metodo di correre su e giù dall'albero per estrarre determinate informazioni da esso.
Sia che utilizziamo il modello dell'elenco di adiacenza o l'attraversamento dell'albero preordinato modificato per recuperare le informazioni, usiamo lo stesso albero PHP. La differenza diventa il modo in cui recuperiamo le informazioni dall'albero e come archiviamo le informazioni in MySQL.Il codice per come estrarre le informazioni da MySQL è già su the page you quoted. Per sincronizzare i dati tra PHP e MySQL devi solo usare le tecniche MySQL descritte su quella pagina e una classe di albero PHP.
Per questo, ho creato una classe in PHP che memorizza un albero. Usa un nodo. Ogni nodo può essere considerato come la radice di un albero completo, poiché da ciascun nodo è possibile accedere a una sottostruttura completa. Era semplicemente più semplice separare il nodo dall'albero e causare meno spese generali.
La parte importante della classe è il metodo showAdjacency. Questo esegue l'albero utilizzando una traversata dell'albero preordinata modificata e visualizza la quantità lft e rgt per ciascun nome che consente di memorizzare i dati in MySQL come un Set nidificato.
È anche possibile visualizzare l'albero, in modo che sia possibile visualizzarlo. Il metodo di eliminazione manca in questa classe. Quando lo si implementa, è necessario passare i figli del nodo eliminato al genitore del nodo. Forse lo farò dopo.
te lo comprendono l'intera classe in fondo al post, ma qui è come i dati vengono recuperati per l'albero di preorder modificato attraversamento:
// The modified preorder tree traversal.
private function showAdjacency($root, $spaces)
{
// Print the data first
if ($root)
{
// On the way down the tree, we get lft.
$left = ++$spaces;
foreach($root->next as $child)
{
if ($child)
{
$spaces = $this->showAdjacency($child, $spaces);
}
}
}
// On the way back up, we get rgt.
$right = ++$spaces;
echo "$left - $right - $root->data <br/>";
return $spaces;
}
È possibile, ovviamente, archiviare root-> Dati $, $ rgt e $ lft in un array che si utilizza per sincronizzarsi con il proprio database.
Ecco l'intera classe. Dopo la lezione, creo un albero utilizzando i dati di esempio da the page you linked to e restituisco i valori lft e rgt e la visualizzazione ad albero.
You can run the code on Codepad
<?php
// Class defintions and methods:
// It's easier to use separate nodes. Each node still points to an entire and complete subtree.
class Node
{
public $data;
public $next = array();
}
// A first try at creating a tree with any number of branches from its nodes
// by Peter Ajtai - feel free to use and modify
class Tree
{
// The root
private $root;
public function __construct()
{
$this->root = NULL;
}
// The public wrapper.
// This is needed because we must start the recursive functions
// at the root, and we do not want to give public access to root.
// I am not familiar w overloading in PHP, maybe __set should be used for this
public function insertPub($data, $parent)
{
$root =& $this->root;
$this->insert($root, $data, $parent);
}
private function insert(&$root, $data, $parent)
{
// Create the root of the entire tree if no parent is passed in
if (!$root && !$parent)
{
$root = new Node;
$temp =& $root;
$temp->data = $data;
// Create space for next insertion
$temp->next[] = NULL;
} else if ($root->data == $parent)
{
// Add data as a child if we're at the parent, and we're done.
// Find the empty node to insert at
foreach($root->next as &$child)
{
// Insert at the first (and only) NULL
if (!$child)
{
$child = new Node;
$temp =& $child;
$temp->data = $data;
// Create space for next insertion
$temp->next[] = NULL;
}
}
// Create space for the next insertion
$root->next[] = NULL;
} else
{
// Keep searching for the parent as default behavior.
foreach($root->next as $child)
{
if ($child)
{
$this->insert($child, $data, $parent);
}
}
}
}
// Public wrapper for the display function.
public function showAdjPub()
{
echo "The neighbors:<br/><br/>";
$root =& $this->root;
$this->showAdjacency($root, 0);
echo "<br/>";
}
// The display function.
private function showAdjacency($root, $spaces)
{
// Print the data first
if ($root)
{
$left = ++$spaces;
foreach($root->next as $child)
{
if ($child)
{
$spaces = $this->showAdjacency($child, $spaces);
}
}
}
$right = ++$spaces;
echo "$left - $right - $root->data <br/>";
return $spaces;
}
// Public wrapper for the display function.
public function showAllPub()
{
echo "The tree:<br/><br/>";
$root =& $this->root;
$this->showAll($root, 0);
echo "<br/>";
}
// The display function.
private function showAll($root, $spaces)
{
// Print the data first
if ($root)
{
for ($i=0; $i < $spaces; ++$i)
echo "---> ";
echo "$root->data <br/>";
++$spaces;
foreach($root->next as $child)
{
if ($child)
{
$this->showAll($child, $spaces);
}
}
}
}
}
// Create a new instance of the tree
$myTree = new Tree;
// Insert the data into the tree.
// The following data would be retrieved using MySQL
$name = 'Electronics'; $parent = NULL;
$myTree->insertPub($name, $parent);
$name = 'Televisions'; $parent = 'Electronics';
$myTree->insertPub($name, $parent);
$name = 'Tube'; $parent = 'Televisions';
$myTree->insertPub($name, $parent);
$name = 'Lcd'; $parent = 'Televisions';
$myTree->insertPub($name, $parent);
$name = 'Plasma'; $parent = 'Televisions';
$myTree->insertPub($name, $parent);
$name = 'Portable Electronics'; $parent = 'Electronics';
$myTree->insertPub($name, $parent);
$name = 'MP3 Players'; $parent = 'Portable Electronics';
$myTree->insertPub($name, $parent);
$name = 'Flash'; $parent = 'MP3 Players';
$myTree->insertPub($name, $parent);
$name = 'CD Players'; $parent = 'Portable Electronics';
$myTree->insertPub($name, $parent);
$name = '2 Way Radios'; $parent = 'Portable Electronics';
$myTree->insertPub($name, $parent);
// Display adjacency
$myTree->showAdjPub();
// Show hierarchy
$myTree->showAllPub();
?>
PS: La memorizzazione dei dati in PHP in matrici nidificate come da te suggerito sarebbe molto difficile. Nella classe precedente, se un membro dati viene eliminato, l'albero viene modificato (comprese le aggiunte di interi sottoalberi, ecc.) I valori lft
e rgt
verranno comunque recuperati correttamente.
Se si utilizzano gli array per archiviare le informazioni, sarà estremamente difficile eliminare elementi con genitori e figli e aggiornare il valore di lft e rgt sarebbe molto difficile. Infine, aggiungere serie di grandi dimensioni (sottoalberi) all'array sarebbe estremamente difficile.
Un albero è davvero il modo ideale per archiviare questo tipo di dati gerarchici. Imita le nostre nozioni di set. Il problema è che mentre PHP memorizza alberi con facilità, MySQL non lo fa, quindi dobbiamo passare attraverso tutto il difficile lavoro della traversata dell'albero preordinata modificata per estrarre le informazioni dall'albero PHP in modo che possiamo memorizzarle nel db MySQL.
* (risorsa) * http://matthewturland.com/2010/05/20/new-spl-features-in-php-5-3/ – Gordon
Heh, infatti non è l'adiacenza ma il modello dell'insieme annidato. Non credo che nessuno di questi nuovi SPL possa essere d'aiuto, dato che lo stesso _node_ conosce i suoi vicini, non solo i genitori. Avrei solo un sacco di oggetti che hanno un riferimento agli oggetti a sinistra ea destra, con una sorta di pattern 'Composite' per cambiare le impostazioni in cascata. – Wrikken
Potrebbe valere la pena dare un'occhiata a come [Doctrine] [http://www.propelorm.org/browser/branches/1.6/generator/lib/behavior/nestedset] e [Propel] [http: //trac.doctrine -project.org/browser/branches/1.2/lib/Doctrine/Node] gestisce i set nidificati. Potrebbe essere necessario costruire alcuni modelli fittizi per ottenere una buona occhiata al codice, specialmente con Propel. – prodigitalson