manejo - ¿La mejor forma de generar migas de texto desde una matriz de PHP con 3 columnas(id, ruta, nombre)?
manejo de array en php (2)
También puede crear una nueva función en MYSQL para obtener los nombres de los identificadores y usarlos de la siguiente manera:
SELECT p.id,YOURFUNCTION(p.path),.....
https://dev.mysql.com/doc/refman/5.7/en/adding-functions.html
Para una posible solución, vea mi segunda publicación a continuación.
Tener una matriz de PHP que almacena datos de una estructura de árbol, con
- la primera columna que almacena la identificación del nodo,
- la segunda columna que almacena la ruta del nodo principal como una concatenación de valores de id,
- las terceras columnas que almacenan el nombre del nodo,
¿Cuál es la mejor forma de generar una ruta de texto (rutas de navegación) desde la ruta de acceso de los identificadores?
Registros de ejemplo:
id | path | name
---------------------
1 | 0 | edible
14 | 1 | fruits
53 | 1.14 | apples
54 | 1.14 | pears
122 | 1.14.53 | red apples
123 | 1.14.53 | green apples
124 | 1.14.54 | yellow pears
ID de entrada: 122
1.14.53
entrada correspondiente: 1.14.53
Cadena de salida: edible > fruits > apples
La idea es lograr algo como:
foreach($cats as $cat) { // for each category
foreach(explode(''.'', $cat[''path'']) as $id) { // explode the path into chunks
/*
1) get the name matching the value of $id
2) append label to breadcrumbs string
*/
}
// 3) output breadcrumbs for the given category
// [4) list leaf nodes under the breadcrumbs for the current category]
}
Nota bene: la matriz en sí es generada por esta consulta MySQL / MariaDB:
$req = "SELECT c.id,p.path,c.name FROM `".$database[''database'']."`.`".$database[''prefix'']."productcategories` c
LEFT OUTER JOIN `".$database[''database'']."`.`".$database[''prefix'']."prodcat_path` p
ON c.id = p.id
WHERE c.isparent AND (c.id=".$id." OR (p.path=".$id." OR p.path LIKE(''".$id.".%'') OR p.path LIKE(''%.".$id.".%'') OR p.path LIKE(''%.".$id."''))) ORDER BY p.path ASC";
$res = mysql_query($req) or die();
La razón para almacenar la ruta en una tabla distinta, con una relación de uno a uno para los registros, es que se usa un desencadenador para calcular y almacenar la ruta cuando se inserta una nueva categoría.
Esta es mi solución casera, codificada en PHP, que funciona bien:
function generateBreadcrumbsForNodeAndDescendants($id) {
define (''FOLDER_PATH'',dirname(__FILE__).''/'');
include(FOLDER_PATH.''db_ajax_connection.inc.php'');
// Select node and all subnodes, excepted leafs
// This query works, but is possibly not optimized.
$req = "SELECT c.id,p.path,c.name FROM `".$database[''database'']."`.`".$database[''prefix'']."categories` c
LEFT OUTER JOIN `".$database[''database'']."`.`".$database[''prefix'']."paths` p
ON c.id = p.id
WHERE c.isparent AND (c.id=".$id." OR (p.path=".$id." OR p.path LIKE(''".$id.".%'') OR p.path LIKE(''%.".$id.".%''))) ORDER BY p.path ASC";
// We would add the following line to the WHERE clause if we wanted to retrieve leaf nodes too:
// OR p.path LIKE(''%.".$id."'')
$res = mysql_query($req) or die();
$descendants = array();
while($descendant = mysql_fetch_assoc($res)) {
$descendants[] = $descendant;
}
$path = '''';
// Get the path to the current node.
// Because the records from the query are ordered by path, this is the first record.
$path = str_replace(''.'', '','', $descendants[0][''path'']);
// This is because there is no record stored in the path table for the first-level nodes
if ($path=='''')
$path = ''0'';
// Find ancestors of the current node
$req = "SELECT c.id,p.path,c.name FROM `".$database[''database'']."`.`".$database[''prefix'']."categories` c
LEFT OUTER JOIN `".$database[''database'']."`.`".$database[''prefix'']."paths` p
ON c.id = p.id
WHERE FIND_IN_SET(c.id,''".$path."'')";
$res = mysql_query($req) or die('''');
$ancestors = array();
while($ancestor = mysql_fetch_assoc($res)) {
$ancestors[] = $ancestor;
}
// Build a list of all ancestors and descendants of the current node, i.e. concatenate arrays
$nodes = array_merge($ancestors,$descendants);
$paths = array();
// Build associative key => value pairs: (id => path) and (id => name)
foreach ($nodes as $node) {
$paths[$node[''id'']]=$node[''path''];
$names[$node[''id'']]=$node[''name''];
}
$html='''';
// for each "descendant" node (including custom "root" node), translate numeric path into breadcrumbs
foreach ($descendants as $descendant) {
$html .= ''<p>'';
$path = $paths[$descendant[''id'']];
if ($path) { // because no path is stored for the 1st level nodes, we must test that $path != ''''
$i = 0;
foreach(explode(''.'', $path) as $id) {
if ($i)
$html .= '' > '';
$html .= $names[$id]; // These nodes can also be encapsulated in html anchors <a href="">...</a> to become links.
$i++;
}
$html .= '' > ''; // optional if we want to add the element to the path of its parent nodes (see below)
}
$html .= $names[$descendant[''id'']]; // optional if we want to add the element to the path of its parent nodes
// else, we should do some post-processing to remove duplicate paths,
// as several nodes may have the same parent path.
$html .= ''</p>'';
}
echo $html;
}
generateBreadcrumbsForNodeAndDescendants((int) $_POST[''key'']);
Nota: Al agregar OR p.path LIKE(''%.".$id."'')
Al final de la cláusula WHERE en la primera consulta, también se pueden recuperar los nodos hoja, sin embargo, en tal caso un error de desfase indefinido surge en la línea $path = str_replace(''.'', '','', $descendants[0][''path'']);
para nodos de hojas, ya que no tienen descendientes. Por lo tanto, es posible alguna mejora del código.