2017-02-08 24 views
0

Для одного возможного решения см. Мое второе сообщение ниже.Лучший способ генерации текстовых паттернов из массива PHP, имеющих 3 столбца (id, путь, имя)?

Имея PHP массив хранения данных из древовидной структуры, с

  • первой колонкой хранением идентификатора узла,
  • второго столбца хранением пути родительского узла в виде конкатенации значения идентификаторов,
  • третьих столбцов хранящих имя узла,

, который является лучшим способом для генерации текста пути (хлебные крошки) от пути выполненного из Идентификаторы?

Пример записей:

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: 122

Соответствующий входной тракт: 1.14.53

Выходная строка: edible > fruits > apples

Идея заключается в том, чтобы достичь что-то вроде:

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] 
} 

нотабене: Сам массив генерируется этим 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(); 

Причины для хранения пути в отдельную таблицу, с отношением один к одному для что триггер используется для вычисления и сохранения пути при вставке новой категории.

+0

Улучшен запрос MySQL. Предложение WHERE должно выбрать данный узел ($ id) и все его дочерние объекты, за исключением листьев. Кажется, работает. – OuzoPower

+0

Я разместил решение, которое я нашел в сообщении ниже. Это отчасти работает. Существует только одна проблема с запросом на выбор узлов-предков, который в настоящее время является неправильным. – OuzoPower

+0

Решена проблема получения узлов-предков; см. мой пост ниже. – OuzoPower

ответ

0

Вы также можете создать новую функцию на MYSQL, чтобы получить имена из идентификаторов и использовать как следующий:

SELECT p.id,YOURFUNCTION(p.path),..... 

https://dev.mysql.com/doc/refman/5.7/en/adding-functions.html

+0

Благодарим вас за это, но, как и на общем хостинге, я не уверен, что могу создавать новые функции MYSQL.Я также хочу сохранить как можно более переносимую ситуацию между локальной разработкой и производственным сервером. Функция MYSQL клиента была бы тем, что я забыл передать. Я считаю, что сейчас я на правильном пути с чистым PHP-кодом и скоро отправлю сообщение. – OuzoPower

0

Это мой дом сделал решение, закодированной в PHP, который работает хорошо:

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']); 

Примечание: при добавлении OR p.path LIKE('%.".$id."') в конце пункта WHERE в первом запросе, можно получить лист узлов, а также, однако в этом случае неопределенная ошибка смещения возникает в строке $path = str_replace('.', ',', $descendants[0]['path']); для листовых узлов, так как у них нет потомков. Следовательно, некоторое улучшение кода остается возможным.